mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-24 20:56:08 +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 builtin = @import("builtin");
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -711,37 +712,6 @@ pub const Config = struct {
|
||||
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.
|
||||
pub const ChangeIterator = struct {
|
||||
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.
|
||||
pub const Color = struct {
|
||||
r: u8,
|
||||
@ -1006,9 +1048,21 @@ pub const Keybinds = struct {
|
||||
|
||||
/// Compare if two of our value are requal. Required by Config.
|
||||
pub fn equal(self: Keybinds, other: Keybinds) bool {
|
||||
// TODO
|
||||
_ = self;
|
||||
_ = other;
|
||||
const self_map = self.set.bindings;
|
||||
const other_map = other.set.bindings;
|
||||
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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user