mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 00:36:07 +03:00
core: "all" bindings work
This commit is contained in:
@ -1590,7 +1590,7 @@ fn maybeHandleBinding(
|
||||
};
|
||||
|
||||
// Determine if this entry has an action or if its a leader key.
|
||||
const action: input.Binding.Action, const consumed: bool = switch (entry) {
|
||||
const leaf: input.Binding.Set.Leaf = switch (entry) {
|
||||
.leader => |set| {
|
||||
// Setup the next set we'll look at.
|
||||
self.keyboard.bindings = set;
|
||||
@ -1605,7 +1605,20 @@ fn maybeHandleBinding(
|
||||
return .consumed;
|
||||
},
|
||||
|
||||
.leaf => |leaf| .{ leaf.action, leaf.flags.consumed },
|
||||
.leaf => |leaf| leaf,
|
||||
};
|
||||
const action = leaf.action;
|
||||
|
||||
// consumed determines if the input is consumed or if we continue
|
||||
// encoding the key (if we have a key to encode).
|
||||
const consumed = consumed: {
|
||||
// If the consumed flag is explicitly set, then we are consumed.
|
||||
if (leaf.flags.consumed) break :consumed true;
|
||||
|
||||
// If the global or all flag is set, we always consume.
|
||||
if (leaf.flags.global or leaf.flags.all) break :consumed true;
|
||||
|
||||
break :consumed false;
|
||||
};
|
||||
|
||||
// We have an action, so at this point we're handling SOMETHING so
|
||||
@ -1617,8 +1630,22 @@ fn maybeHandleBinding(
|
||||
self.keyboard.bindings = null;
|
||||
|
||||
// Attempt to perform the action
|
||||
log.debug("key event binding consumed={} action={}", .{ consumed, action });
|
||||
const performed = try self.performBindingAction(action);
|
||||
log.debug("key event binding flags={} action={}", .{
|
||||
leaf.flags,
|
||||
action,
|
||||
});
|
||||
const performed = performed: {
|
||||
// If this is a global or all action, then we perform it on
|
||||
// the app and it applies to every surface.
|
||||
if (leaf.flags.global or leaf.flags.all) {
|
||||
try self.app.performAllAction(self.rt_app, action);
|
||||
|
||||
// "All" actions are always performed since they are global.
|
||||
break :performed true;
|
||||
}
|
||||
|
||||
break :performed try self.performBindingAction(action);
|
||||
};
|
||||
|
||||
// If we performed an action and it was a closing action,
|
||||
// our "self" pointer is not safe to use anymore so we need to
|
||||
|
@ -1160,7 +1160,7 @@ pub const Set = struct {
|
||||
set.remove(alloc, t);
|
||||
if (old) |entry| switch (entry) {
|
||||
.leader => unreachable, // Handled above
|
||||
.leaf => |leaf| set.put_(
|
||||
.leaf => |leaf| set.putFlags(
|
||||
alloc,
|
||||
t,
|
||||
leaf.action,
|
||||
@ -1179,11 +1179,12 @@ pub const Set = struct {
|
||||
return error.SequenceUnbind;
|
||||
},
|
||||
|
||||
else => if (b.flags.consumed) {
|
||||
try set.put(alloc, b.trigger, b.action);
|
||||
} else {
|
||||
try set.putUnconsumed(alloc, b.trigger, b.action);
|
||||
},
|
||||
else => try set.putFlags(
|
||||
alloc,
|
||||
b.trigger,
|
||||
b.action,
|
||||
b.flags,
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1196,24 +1197,11 @@ pub const Set = struct {
|
||||
t: Trigger,
|
||||
action: Action,
|
||||
) Allocator.Error!void {
|
||||
try self.put_(alloc, t, action, .{});
|
||||
try self.putFlags(alloc, t, action, .{});
|
||||
}
|
||||
|
||||
/// Same as put but marks the trigger as unconsumed. An unconsumed
|
||||
/// trigger will evaluate the action and continue to encode for the
|
||||
/// terminal.
|
||||
///
|
||||
/// This is a separate function because this case is rare.
|
||||
pub fn putUnconsumed(
|
||||
self: *Set,
|
||||
alloc: Allocator,
|
||||
t: Trigger,
|
||||
action: Action,
|
||||
) Allocator.Error!void {
|
||||
try self.put_(alloc, t, action, .{ .consumed = false });
|
||||
}
|
||||
|
||||
fn put_(
|
||||
/// Add a binding to the set with explicit flags.
|
||||
pub fn putFlags(
|
||||
self: *Set,
|
||||
alloc: Allocator,
|
||||
t: Trigger,
|
||||
@ -1486,6 +1474,49 @@ test "parse: global triggers" {
|
||||
}
|
||||
}
|
||||
|
||||
test "parse: all triggers" {
|
||||
const testing = std.testing;
|
||||
|
||||
// all keys
|
||||
try testing.expectEqual(Binding{
|
||||
.trigger = .{
|
||||
.mods = .{ .shift = true },
|
||||
.key = .{ .translated = .a },
|
||||
},
|
||||
.action = .{ .ignore = {} },
|
||||
.flags = .{ .all = true },
|
||||
}, try parseSingle("all:shift+a=ignore"));
|
||||
|
||||
// all physical keys
|
||||
try testing.expectEqual(Binding{
|
||||
.trigger = .{
|
||||
.mods = .{ .shift = true },
|
||||
.key = .{ .physical = .a },
|
||||
},
|
||||
.action = .{ .ignore = {} },
|
||||
.flags = .{ .all = true },
|
||||
}, try parseSingle("all:physical:a+shift=ignore"));
|
||||
|
||||
// all unconsumed keys
|
||||
try testing.expectEqual(Binding{
|
||||
.trigger = .{
|
||||
.mods = .{ .shift = true },
|
||||
.key = .{ .translated = .a },
|
||||
},
|
||||
.action = .{ .ignore = {} },
|
||||
.flags = .{
|
||||
.all = true,
|
||||
.consumed = false,
|
||||
},
|
||||
}, try parseSingle("unconsumed:all:a+shift=ignore"));
|
||||
|
||||
// all sequences not allowed
|
||||
{
|
||||
var p = try Parser.init("all:a>b=ignore");
|
||||
try testing.expectError(Error.InvalidFormat, p.next());
|
||||
}
|
||||
}
|
||||
|
||||
test "parse: modifier aliases" {
|
||||
const testing = std.testing;
|
||||
|
||||
|
Reference in New Issue
Block a user