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
|
// - Only `--long=value` format is accepted. Do we want to allow
|
||||||
// `--long value`? Not currently allowed.
|
// `--long value`? Not currently allowed.
|
||||||
|
|
||||||
|
// For trimming
|
||||||
|
const whitespace = " \t";
|
||||||
|
|
||||||
/// The base errors for arg parsing. Additional errors can be returned due
|
/// The base errors for arg parsing. Additional errors can be returned due
|
||||||
/// to type-specific parsing but these are always possible.
|
/// to type-specific parsing but these are always possible.
|
||||||
pub const Error = error{
|
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
|
// No parseCLI, magic the value based on the type
|
||||||
@field(dst, field.name) = switch (Field) {
|
@field(dst, field.name) = switch (Field) {
|
||||||
[]const u8 => value: {
|
[]const u8 => value: {
|
||||||
@ -239,7 +230,19 @@ fn parseIntoField(
|
|||||||
value orelse return error.ValueRequired,
|
value orelse return error.ValueRequired,
|
||||||
) catch return error.InvalidValue,
|
) 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;
|
return;
|
||||||
@ -249,6 +252,42 @@ fn parseIntoField(
|
|||||||
return error.InvalidField;
|
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 {
|
fn parseBool(v: []const u8) !bool {
|
||||||
const t = &[_][]const u8{ "1", "t", "T", "true" };
|
const t = &[_][]const u8{ "1", "t", "T", "true" };
|
||||||
const f = &[_][]const u8{ "0", "f", "F", "false" };
|
const f = &[_][]const u8{ "0", "f", "F", "false" };
|
||||||
@ -462,6 +501,63 @@ test "parseIntoField: enums" {
|
|||||||
try testing.expectEqual(Enum.two, data.v);
|
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" {
|
test "parseIntoField: optional field" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
var arena = ArenaAllocator.init(testing.allocator);
|
var arena = ArenaAllocator.init(testing.allocator);
|
||||||
@ -582,7 +678,6 @@ pub fn LineIterator(comptime ReaderType: type) type {
|
|||||||
} orelse return null;
|
} orelse return null;
|
||||||
|
|
||||||
// Trim any whitespace around it
|
// Trim any whitespace around it
|
||||||
const whitespace = " \t";
|
|
||||||
const trim = std.mem.trim(u8, entry, whitespace);
|
const trim = std.mem.trim(u8, entry, whitespace);
|
||||||
if (trim.len != entry.len) {
|
if (trim.len != entry.len) {
|
||||||
std.mem.copy(u8, entry, trim);
|
std.mem.copy(u8, entry, trim);
|
||||||
|
@ -2187,6 +2187,11 @@ pub const ShellIntegration = enum {
|
|||||||
@"no-cursor",
|
@"no-cursor",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Shell integration features
|
||||||
|
pub const ShellIntegrationFeatures = packed struct {
|
||||||
|
cursor: bool = true,
|
||||||
|
};
|
||||||
|
|
||||||
/// OSC 10 and 11 default color reporting format.
|
/// OSC 10 and 11 default color reporting format.
|
||||||
pub const OSCColorReportFormat = enum {
|
pub const OSCColorReportFormat = enum {
|
||||||
none,
|
none,
|
||||||
|
Reference in New Issue
Block a user