mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
config: packed struct of bools supported as config field
This commit is contained in:
123
src/cli/args.zig
123
src/cli/args.zig
@ -10,6 +10,9 @@ const ErrorList = @import("../config/ErrorList.zig");
|
||||
// - Only `--long=value` format is accepted. Do we want to allow
|
||||
// `--long value`? Not currently allowed.
|
||||
|
||||
// For trimming
|
||||
const whitespace = " \t";
|
||||
|
||||
/// The base errors for arg parsing. Additional errors can be returned due
|
||||
/// to type-specific parsing but these are always possible.
|
||||
pub const Error = error{
|
||||
@ -191,18 +194,6 @@ fn parseIntoField(
|
||||
}
|
||||
}
|
||||
|
||||
switch (fieldInfo) {
|
||||
.Enum => {
|
||||
@field(dst, field.name) = std.meta.stringToEnum(
|
||||
Field,
|
||||
value orelse return error.ValueRequired,
|
||||
) orelse return error.InvalidValue;
|
||||
return;
|
||||
},
|
||||
|
||||
else => {},
|
||||
}
|
||||
|
||||
// No parseCLI, magic the value based on the type
|
||||
@field(dst, field.name) = switch (Field) {
|
||||
[]const u8 => value: {
|
||||
@ -239,7 +230,19 @@ fn parseIntoField(
|
||||
value orelse return error.ValueRequired,
|
||||
) catch return error.InvalidValue,
|
||||
|
||||
else => unreachable,
|
||||
else => switch (fieldInfo) {
|
||||
.Enum => std.meta.stringToEnum(
|
||||
Field,
|
||||
value orelse return error.ValueRequired,
|
||||
) orelse return error.InvalidValue,
|
||||
|
||||
.Struct => try parsePackedStruct(
|
||||
Field,
|
||||
value orelse return error.ValueRequired,
|
||||
),
|
||||
|
||||
else => unreachable,
|
||||
},
|
||||
};
|
||||
|
||||
return;
|
||||
@ -249,6 +252,42 @@ fn parseIntoField(
|
||||
return error.InvalidField;
|
||||
}
|
||||
|
||||
fn parsePackedStruct(comptime T: type, v: []const u8) !T {
|
||||
const info = @typeInfo(T).Struct;
|
||||
assert(info.layout == .Packed);
|
||||
|
||||
var result: T = .{};
|
||||
|
||||
// We split each value by ","
|
||||
var iter = std.mem.splitSequence(u8, v, ",");
|
||||
loop: while (iter.next()) |part_raw| {
|
||||
// Determine the field we're looking for and the value. If the
|
||||
// field is prefixed with "no-" then we set the value to false.
|
||||
const part, const value = part: {
|
||||
const negation_prefix = "no-";
|
||||
const trimmed = std.mem.trim(u8, part_raw, whitespace);
|
||||
if (std.mem.startsWith(u8, trimmed, negation_prefix)) {
|
||||
break :part .{ trimmed[negation_prefix.len..], false };
|
||||
} else {
|
||||
break :part .{ trimmed, true };
|
||||
}
|
||||
};
|
||||
|
||||
inline for (info.fields) |field| {
|
||||
assert(field.type == bool);
|
||||
if (std.mem.eql(u8, field.name, part)) {
|
||||
@field(result, field.name) = value;
|
||||
continue :loop;
|
||||
}
|
||||
}
|
||||
|
||||
// No field matched
|
||||
return error.InvalidValue;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn parseBool(v: []const u8) !bool {
|
||||
const t = &[_][]const u8{ "1", "t", "T", "true" };
|
||||
const f = &[_][]const u8{ "0", "f", "F", "false" };
|
||||
@ -462,6 +501,63 @@ test "parseIntoField: enums" {
|
||||
try testing.expectEqual(Enum.two, data.v);
|
||||
}
|
||||
|
||||
test "parseIntoField: packed struct" {
|
||||
const testing = std.testing;
|
||||
var arena = ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const Field = packed struct {
|
||||
a: bool = false,
|
||||
b: bool = true,
|
||||
};
|
||||
var data: struct {
|
||||
v: Field,
|
||||
} = undefined;
|
||||
|
||||
try parseIntoField(@TypeOf(data), alloc, &data, "v", "b");
|
||||
try testing.expect(!data.v.a);
|
||||
try testing.expect(data.v.b);
|
||||
}
|
||||
|
||||
test "parseIntoField: packed struct negation" {
|
||||
const testing = std.testing;
|
||||
var arena = ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const Field = packed struct {
|
||||
a: bool = false,
|
||||
b: bool = true,
|
||||
};
|
||||
var data: struct {
|
||||
v: Field,
|
||||
} = undefined;
|
||||
|
||||
try parseIntoField(@TypeOf(data), alloc, &data, "v", "a,no-b");
|
||||
try testing.expect(data.v.a);
|
||||
try testing.expect(!data.v.b);
|
||||
}
|
||||
|
||||
test "parseIntoField: packed struct whitespace" {
|
||||
const testing = std.testing;
|
||||
var arena = ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const Field = packed struct {
|
||||
a: bool = false,
|
||||
b: bool = true,
|
||||
};
|
||||
var data: struct {
|
||||
v: Field,
|
||||
} = undefined;
|
||||
|
||||
try parseIntoField(@TypeOf(data), alloc, &data, "v", " a, no-b ");
|
||||
try testing.expect(data.v.a);
|
||||
try testing.expect(!data.v.b);
|
||||
}
|
||||
|
||||
test "parseIntoField: optional field" {
|
||||
const testing = std.testing;
|
||||
var arena = ArenaAllocator.init(testing.allocator);
|
||||
@ -582,7 +678,6 @@ pub fn LineIterator(comptime ReaderType: type) type {
|
||||
} orelse return null;
|
||||
|
||||
// Trim any whitespace around it
|
||||
const whitespace = " \t";
|
||||
const trim = std.mem.trim(u8, entry, whitespace);
|
||||
if (trim.len != entry.len) {
|
||||
std.mem.copy(u8, entry, trim);
|
||||
|
@ -2187,6 +2187,11 @@ pub const ShellIntegration = enum {
|
||||
@"no-cursor",
|
||||
};
|
||||
|
||||
/// Shell integration features
|
||||
pub const ShellIntegrationFeatures = packed struct {
|
||||
cursor: bool = true,
|
||||
};
|
||||
|
||||
/// OSC 10 and 11 default color reporting format.
|
||||
pub const OSCColorReportFormat = enum {
|
||||
none,
|
||||
|
Reference in New Issue
Block a user