mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-25 13:16:11 +03:00
config: implement comparison for keybinding change
This commit is contained in:
122
src/config.zig
122
src/config.zig
@ -1,3 +1,4 @@
|
|||||||
|
const config = @This();
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
@ -711,37 +712,6 @@ pub const Config = struct {
|
|||||||
return !equal(field.type, old_value, new_value);
|
return !equal(field.type, old_value, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equal(comptime T: type, old: T, new: T) bool {
|
|
||||||
// Do known named types first
|
|
||||||
switch (T) {
|
|
||||||
inline []const u8,
|
|
||||||
[:0]const u8,
|
|
||||||
=> return std.mem.eql(u8, old, new),
|
|
||||||
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Back into types of types
|
|
||||||
switch (@typeInfo(T)) {
|
|
||||||
inline .Bool,
|
|
||||||
.Int,
|
|
||||||
=> return old == new,
|
|
||||||
|
|
||||||
.Optional => |info| {
|
|
||||||
if (old == null and new == null) return true;
|
|
||||||
if (old == null or new == null) return false;
|
|
||||||
return equal(info.child, old.?, new.?);
|
|
||||||
},
|
|
||||||
|
|
||||||
.Struct => return old.equal(new),
|
|
||||||
|
|
||||||
else => {
|
|
||||||
@compileLog(T);
|
|
||||||
@compileError("unsupported field type");
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This yields a key for every changed field between old and new.
|
/// This yields a key for every changed field between old and new.
|
||||||
pub const ChangeIterator = struct {
|
pub const ChangeIterator = struct {
|
||||||
old: *const Config,
|
old: *const Config,
|
||||||
@ -799,6 +769,78 @@ pub const Config = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A config-specific helper to determine if two values of the same
|
||||||
|
/// type are equal. This isn't the same as std.mem.eql or std.testing.equals
|
||||||
|
/// because we expect structs to implement their own equality.
|
||||||
|
///
|
||||||
|
/// This also doesn't support ALL Zig types, because we only add to it
|
||||||
|
/// as we need types for the config.
|
||||||
|
fn equal(comptime T: type, old: T, new: T) bool {
|
||||||
|
// Do known named types first
|
||||||
|
switch (T) {
|
||||||
|
inline []const u8,
|
||||||
|
[:0]const u8,
|
||||||
|
=> return std.mem.eql(u8, old, new),
|
||||||
|
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Back into types of types
|
||||||
|
switch (@typeInfo(T)) {
|
||||||
|
.Void => return true,
|
||||||
|
|
||||||
|
inline .Bool,
|
||||||
|
.Int,
|
||||||
|
.Enum,
|
||||||
|
=> return old == new,
|
||||||
|
|
||||||
|
.Optional => |info| {
|
||||||
|
if (old == null and new == null) return true;
|
||||||
|
if (old == null or new == null) return false;
|
||||||
|
return equal(info.child, old.?, new.?);
|
||||||
|
},
|
||||||
|
|
||||||
|
.Struct => |info| {
|
||||||
|
if (@hasDecl(T, "equal")) return old.equal(new);
|
||||||
|
|
||||||
|
// If a struct doesn't declare an "equal" function, we fall back
|
||||||
|
// to a recursive field-by-field compare.
|
||||||
|
inline for (info.fields) |field_info| {
|
||||||
|
if (!equal(
|
||||||
|
field_info.type,
|
||||||
|
@field(old, field_info.name),
|
||||||
|
@field(new, field_info.name),
|
||||||
|
)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
.Union => |info| {
|
||||||
|
const tag_type = info.tag_type.?;
|
||||||
|
const old_tag = std.meta.activeTag(old);
|
||||||
|
const new_tag = std.meta.activeTag(new);
|
||||||
|
if (old_tag != new_tag) return false;
|
||||||
|
|
||||||
|
inline for (info.fields) |field_info| {
|
||||||
|
if (@field(tag_type, field_info.name) == old_tag) {
|
||||||
|
return equal(
|
||||||
|
field_info.type,
|
||||||
|
@field(old, field_info.name),
|
||||||
|
@field(new, field_info.name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable;
|
||||||
|
},
|
||||||
|
|
||||||
|
else => {
|
||||||
|
@compileLog(T);
|
||||||
|
@compileError("unsupported field type");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Color represents a color using RGB.
|
/// Color represents a color using RGB.
|
||||||
pub const Color = struct {
|
pub const Color = struct {
|
||||||
r: u8,
|
r: u8,
|
||||||
@ -1006,9 +1048,21 @@ pub const Keybinds = struct {
|
|||||||
|
|
||||||
/// Compare if two of our value are requal. Required by Config.
|
/// Compare if two of our value are requal. Required by Config.
|
||||||
pub fn equal(self: Keybinds, other: Keybinds) bool {
|
pub fn equal(self: Keybinds, other: Keybinds) bool {
|
||||||
// TODO
|
const self_map = self.set.bindings;
|
||||||
_ = self;
|
const other_map = other.set.bindings;
|
||||||
_ = other;
|
if (self_map.count() != other_map.count()) return false;
|
||||||
|
|
||||||
|
var it = self_map.iterator();
|
||||||
|
while (it.next()) |self_entry| {
|
||||||
|
const other_entry = other_map.getEntry(self_entry.key_ptr.*) orelse
|
||||||
|
return false;
|
||||||
|
if (!config.equal(
|
||||||
|
inputpkg.Binding.Action,
|
||||||
|
self_entry.value_ptr.*,
|
||||||
|
other_entry.value_ptr.*,
|
||||||
|
)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user