mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-20 10:46:07 +03:00
config: changed() to test if a specific key has changed
This commit is contained in:
@ -172,18 +172,24 @@ pub const Config = struct {
|
|||||||
pub const Key = key: {
|
pub const Key = key: {
|
||||||
const field_infos = std.meta.fields(Config);
|
const field_infos = std.meta.fields(Config);
|
||||||
var enumFields: [field_infos.len]std.builtin.Type.EnumField = undefined;
|
var enumFields: [field_infos.len]std.builtin.Type.EnumField = undefined;
|
||||||
var decls = [_]std.builtin.Type.Declaration{};
|
var i: usize = 0;
|
||||||
inline for (field_infos, 0..) |field, i| {
|
inline for (field_infos) |field| {
|
||||||
|
// Ignore fields starting with "_" since they're internal and
|
||||||
|
// not copied ever.
|
||||||
|
if (field.name[0] == '_') continue;
|
||||||
|
|
||||||
enumFields[i] = .{
|
enumFields[i] = .{
|
||||||
.name = field.name,
|
.name = field.name,
|
||||||
.value = i,
|
.value = i,
|
||||||
};
|
};
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var decls = [_]std.builtin.Type.Declaration{};
|
||||||
break :key @Type(.{
|
break :key @Type(.{
|
||||||
.Enum = .{
|
.Enum = .{
|
||||||
.tag_type = std.math.IntFittingRange(0, field_infos.len - 1),
|
.tag_type = std.math.IntFittingRange(0, field_infos.len - 1),
|
||||||
.fields = &enumFields,
|
.fields = enumFields[0..i],
|
||||||
.decls = &decls,
|
.decls = &decls,
|
||||||
.is_exhaustive = true,
|
.is_exhaustive = true,
|
||||||
},
|
},
|
||||||
@ -635,10 +641,7 @@ pub const Config = struct {
|
|||||||
const alloc = result._arena.?.allocator();
|
const alloc = result._arena.?.allocator();
|
||||||
|
|
||||||
inline for (@typeInfo(Config).Struct.fields) |field| {
|
inline for (@typeInfo(Config).Struct.fields) |field| {
|
||||||
// Ignore fields starting with "_" since they're internal and
|
if (!@hasField(Key, field.name)) continue;
|
||||||
// not copied ever.
|
|
||||||
if (field.name[0] == '_') continue;
|
|
||||||
|
|
||||||
@field(result, field.name) = try cloneValue(
|
@field(result, field.name) = try cloneValue(
|
||||||
alloc,
|
alloc,
|
||||||
field.type,
|
field.type,
|
||||||
@ -680,7 +683,7 @@ pub const Config = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator that goes through each changed field from
|
/// Returns an iterator that goes through each changed field from
|
||||||
/// old to new.
|
/// old to new. The order of old or new do not matter.
|
||||||
pub fn changeIterator(old: *const Config, new: *const Config) ChangeIterator {
|
pub fn changeIterator(old: *const Config, new: *const Config) ChangeIterator {
|
||||||
return .{
|
return .{
|
||||||
.old = old,
|
.old = old,
|
||||||
@ -688,6 +691,26 @@ pub const Config = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the given key has changed from old to new. This
|
||||||
|
/// requires the key to be comptime known to make this more efficient.
|
||||||
|
pub fn changed(self: *const Config, new: *const Config, comptime key: Key) bool {
|
||||||
|
// Get the field at comptime
|
||||||
|
const field = comptime field: {
|
||||||
|
const fields = std.meta.fields(Config);
|
||||||
|
for (fields) |field| {
|
||||||
|
if (@field(Key, field.name) == key) {
|
||||||
|
break :field field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable;
|
||||||
|
};
|
||||||
|
|
||||||
|
const old_value = @field(self, field.name);
|
||||||
|
const new_value = @field(new, field.name);
|
||||||
|
return !equal(field.type, old_value, new_value);
|
||||||
|
}
|
||||||
|
|
||||||
fn equal(comptime T: type, old: T, new: T) bool {
|
fn equal(comptime T: type, old: T, new: T) bool {
|
||||||
// Do known named types first
|
// Do known named types first
|
||||||
switch (T) {
|
switch (T) {
|
||||||
@ -719,27 +742,21 @@ pub const Config = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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,
|
||||||
new: *const Config,
|
new: *const Config,
|
||||||
i: usize = 0,
|
i: usize = 0,
|
||||||
|
|
||||||
pub fn next(self: *ChangeIterator) ?Key {
|
pub fn next(self: *ChangeIterator) ?Key {
|
||||||
const fields = comptime std.meta.fields(Config);
|
const fields = comptime std.meta.fields(Key);
|
||||||
|
|
||||||
while (self.i < fields.len) {
|
while (self.i < fields.len) {
|
||||||
switch (self.i) {
|
switch (self.i) {
|
||||||
inline 0...(fields.len - 1) => |i| {
|
inline 0...(fields.len - 1) => |i| {
|
||||||
const field = fields[i];
|
const field = fields[i];
|
||||||
|
const key = @field(Key, field.name);
|
||||||
self.i += 1;
|
self.i += 1;
|
||||||
|
if (self.old.changed(self.new, key)) return key;
|
||||||
if (field.name[0] == '_') return self.next();
|
|
||||||
|
|
||||||
const old_value = @field(self.old, field.name);
|
|
||||||
const new_value = @field(self.new, field.name);
|
|
||||||
if (!equal(field.type, old_value, new_value)) {
|
|
||||||
return @field(Key, field.name);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
@ -766,6 +783,20 @@ pub const Config = struct {
|
|||||||
// I want to do this but this doesn't work (the API doesn't work)
|
// I want to do this but this doesn't work (the API doesn't work)
|
||||||
// try testing.expectEqualDeep(dest, source);
|
// try testing.expectEqualDeep(dest, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "changed" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var source = try Config.default(alloc);
|
||||||
|
defer source.deinit();
|
||||||
|
var dest = try source.clone(alloc);
|
||||||
|
defer dest.deinit();
|
||||||
|
dest.@"font-family" = "something else";
|
||||||
|
|
||||||
|
try testing.expect(source.changed(&dest, .@"font-family"));
|
||||||
|
try testing.expect(!source.changed(&dest, .@"font-size"));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Color represents a color using RGB.
|
/// Color represents a color using RGB.
|
||||||
|
Reference in New Issue
Block a user