mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-10-05 09:26:32 +00:00
binding parse action with parameter
This commit is contained in:
74
src/key.zig
74
src/key.zig
@@ -20,6 +20,9 @@ pub const Binding = struct {
|
|||||||
/// modifiers and keys. Action is the action name and optionally a
|
/// modifiers and keys. Action is the action name and optionally a
|
||||||
/// parameter after a colon, i.e. "csi:A" or "ignore".
|
/// parameter after a colon, i.e. "csi:A" or "ignore".
|
||||||
pub fn parse(input: []const u8) !Binding {
|
pub fn parse(input: []const u8) !Binding {
|
||||||
|
// NOTE(mitchellh): This is not the most efficient way to do any
|
||||||
|
// of this, I welcome any improvements here!
|
||||||
|
|
||||||
// Find the first = which splits are mapping into the trigger
|
// Find the first = which splits are mapping into the trigger
|
||||||
// and action, respectively.
|
// and action, respectively.
|
||||||
const eqlIdx = std.mem.indexOf(u8, input, "=") orelse return Error.InvalidFormat;
|
const eqlIdx = std.mem.indexOf(u8, input, "=") orelse return Error.InvalidFormat;
|
||||||
@@ -66,27 +69,41 @@ pub const Binding = struct {
|
|||||||
return Error.InvalidFormat;
|
return Error.InvalidFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split our action by colon. A colon may not exist for some
|
|
||||||
// actions so it is optional. The part preceding the colon is the
|
|
||||||
// action name.
|
|
||||||
const actionRaw = input[eqlIdx + 1 ..];
|
|
||||||
const colonIdx = std.mem.indexOf(u8, actionRaw, ":");
|
|
||||||
const action = actionRaw[0..(colonIdx orelse actionRaw.len)];
|
|
||||||
|
|
||||||
// An action name is always required
|
|
||||||
if (action.len == 0) return Error.InvalidFormat;
|
|
||||||
|
|
||||||
// Find a matching action
|
// Find a matching action
|
||||||
const actionInfo = @typeInfo(Action).Union;
|
result.action = action: {
|
||||||
inline for (actionInfo.fields) |field| {
|
// Split our action by colon. A colon may not exist for some
|
||||||
if (std.mem.eql(u8, action, field.name)) {
|
// actions so it is optional. The part preceding the colon is the
|
||||||
// If the field type is void we expect no value
|
// action name.
|
||||||
if (field.field_type == void) {
|
const actionRaw = input[eqlIdx + 1 ..];
|
||||||
if (colonIdx != null) return Error.InvalidFormat;
|
const colonIdx = std.mem.indexOf(u8, actionRaw, ":");
|
||||||
result.action = @unionInit(Action, field.name, {});
|
const action = actionRaw[0..(colonIdx orelse actionRaw.len)];
|
||||||
|
|
||||||
|
// An action name is always required
|
||||||
|
if (action.len == 0) return Error.InvalidFormat;
|
||||||
|
|
||||||
|
const actionInfo = @typeInfo(Action).Union;
|
||||||
|
inline for (actionInfo.fields) |field| {
|
||||||
|
if (std.mem.eql(u8, action, field.name)) {
|
||||||
|
// If the field type is void we expect no value
|
||||||
|
switch (field.field_type) {
|
||||||
|
void => {
|
||||||
|
if (colonIdx != null) return Error.InvalidFormat;
|
||||||
|
break :action @unionInit(Action, field.name, {});
|
||||||
|
},
|
||||||
|
|
||||||
|
[]const u8 => {
|
||||||
|
const idx = colonIdx orelse return Error.InvalidFormat;
|
||||||
|
const param = actionRaw[idx + 1 ..];
|
||||||
|
break :action @unionInit(Action, field.name, param);
|
||||||
|
},
|
||||||
|
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return Error.InvalidFormat;
|
||||||
|
};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -135,6 +152,27 @@ pub const Binding = struct {
|
|||||||
// multiple character
|
// multiple character
|
||||||
try testing.expectError(Error.InvalidFormat, parse("a+b=ignore"));
|
try testing.expectError(Error.InvalidFormat, parse("a+b=ignore"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "parse: action" {
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
// invalid action
|
||||||
|
try testing.expectError(Error.InvalidFormat, parse("a=nopenopenope"));
|
||||||
|
|
||||||
|
// no parameters
|
||||||
|
try testing.expectEqual(
|
||||||
|
Binding{ .key = .a, .action = .{ .ignore = {} } },
|
||||||
|
try parse("a=ignore"),
|
||||||
|
);
|
||||||
|
try testing.expectError(Error.InvalidFormat, parse("a=ignore:A"));
|
||||||
|
|
||||||
|
// parameter
|
||||||
|
{
|
||||||
|
const binding = try parse("a=csi:A");
|
||||||
|
try testing.expect(binding.action == .csi);
|
||||||
|
try testing.expectEqualStrings("A", binding.action.csi);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The set of actions that a keybinding can take.
|
/// The set of actions that a keybinding can take.
|
||||||
|
Reference in New Issue
Block a user