mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
Fix empty keybind setting (#5977)
Fixes https://github.com/ghostty-org/ghostty/issues/5936. Extracts the default keybind setting to an `init` function. Add logic to call `init` in `parseIntoField` if it is defined for the type.
This commit is contained in:
@ -247,16 +247,6 @@ pub fn parseIntoField(
|
|||||||
|
|
||||||
inline for (info.Struct.fields) |field| {
|
inline for (info.Struct.fields) |field| {
|
||||||
if (field.name[0] != '_' and mem.eql(u8, field.name, key)) {
|
if (field.name[0] != '_' and mem.eql(u8, field.name, key)) {
|
||||||
// If the value is empty string (set but empty string),
|
|
||||||
// then we reset the value to the default.
|
|
||||||
if (value) |v| default: {
|
|
||||||
if (v.len != 0) break :default;
|
|
||||||
const raw = field.default_value orelse break :default;
|
|
||||||
const ptr: *const field.type = @alignCast(@ptrCast(raw));
|
|
||||||
@field(dst, field.name) = ptr.*;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For optional fields, we just treat it as the child type.
|
// For optional fields, we just treat it as the child type.
|
||||||
// This lets optional fields default to null but get set by
|
// This lets optional fields default to null but get set by
|
||||||
// the CLI.
|
// the CLI.
|
||||||
@ -264,11 +254,27 @@ pub fn parseIntoField(
|
|||||||
.Optional => |opt| opt.child,
|
.Optional => |opt| opt.child,
|
||||||
else => field.type,
|
else => field.type,
|
||||||
};
|
};
|
||||||
|
const fieldInfo = @typeInfo(Field);
|
||||||
|
const canHaveDecls = fieldInfo == .Struct or fieldInfo == .Union or fieldInfo == .Enum;
|
||||||
|
|
||||||
|
// If the value is empty string (set but empty string),
|
||||||
|
// then we reset the value to the default.
|
||||||
|
if (value) |v| default: {
|
||||||
|
if (v.len != 0) break :default;
|
||||||
|
// Set default value if possible.
|
||||||
|
if (canHaveDecls and @hasDecl(Field, "init")) {
|
||||||
|
try @field(dst, field.name).init(alloc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const raw = field.default_value orelse break :default;
|
||||||
|
const ptr: *const field.type = @alignCast(@ptrCast(raw));
|
||||||
|
@field(dst, field.name) = ptr.*;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If we are a type that can have decls and have a parseCLI decl,
|
// If we are a type that can have decls and have a parseCLI decl,
|
||||||
// we call that and use that to set the value.
|
// we call that and use that to set the value.
|
||||||
const fieldInfo = @typeInfo(Field);
|
if (canHaveDecls) {
|
||||||
if (fieldInfo == .Struct or fieldInfo == .Union or fieldInfo == .Enum) {
|
|
||||||
if (@hasDecl(Field, "parseCLI")) {
|
if (@hasDecl(Field, "parseCLI")) {
|
||||||
const fnInfo = @typeInfo(@TypeOf(Field.parseCLI)).Fn;
|
const fnInfo = @typeInfo(@TypeOf(Field.parseCLI)).Fn;
|
||||||
switch (fnInfo.params.len) {
|
switch (fnInfo.params.len) {
|
||||||
@ -761,6 +767,29 @@ test "parseIntoField: ignore underscore-prefixed fields" {
|
|||||||
try testing.expectEqualStrings("12", data._a);
|
try testing.expectEqualStrings("12", data._a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "parseIntoField: struct with init func" {
|
||||||
|
const testing = std.testing;
|
||||||
|
var arena = ArenaAllocator.init(testing.allocator);
|
||||||
|
defer arena.deinit();
|
||||||
|
const alloc = arena.allocator();
|
||||||
|
|
||||||
|
var data: struct {
|
||||||
|
a: struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
v: []const u8,
|
||||||
|
|
||||||
|
pub fn init(self: *Self, _alloc: Allocator) !void {
|
||||||
|
_ = _alloc;
|
||||||
|
self.* = .{ .v = "HELLO!" };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
} = undefined;
|
||||||
|
|
||||||
|
try parseIntoField(@TypeOf(data), alloc, &data, "a", "");
|
||||||
|
try testing.expectEqual(@as([]const u8, "HELLO!"), data.a.v);
|
||||||
|
}
|
||||||
|
|
||||||
test "parseIntoField: string" {
|
test "parseIntoField: string" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
var arena = ArenaAllocator.init(testing.allocator);
|
var arena = ArenaAllocator.init(testing.allocator);
|
||||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user