From d9ab0fd5af14b0835614dd7e54406b100d5e308d Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Fri, 28 Nov 2025 16:11:41 +0100 Subject: [PATCH] feat: add support in keybind module for looking up key sequence prefix matches This is the initial part of some sort of which-key like function. --- src/keybind/keybind.zig | 22 +++++++++++++++++++++- src/tui/tui.zig | 9 +++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/keybind/keybind.zig b/src/keybind/keybind.zig index 79d63ac..e0c4a46 100644 --- a/src/keybind/keybind.zig +++ b/src/keybind/keybind.zig @@ -71,13 +71,15 @@ const Handler = struct { opts.insert_command else "insert_chars"; + const bindings = try get_mode_binding_set(mode_name, insert_command); self.* = .{ .allocator = allocator, - .bindings = try get_mode_binding_set(mode_name, insert_command), + .bindings = bindings, }; return .{ .allocator = allocator, .input_handler = EventHandler.to_owned(self), + .bindings = bindings, .keybind_hints = self.bindings.hints(), .mode = try allocator.dupe(u8, mode_name), .name = self.bindings.name, @@ -127,6 +129,7 @@ pub const Mode = struct { mode: []const u8, name: []const u8 = "", line_numbers: LineNumbers = .inherit, + bindings: *const BindingSet, keybind_hints: *const KeybindHints, cursor_shape: ?CursorShape = null, init_command: ?Command = null, @@ -168,6 +171,11 @@ pub const Mode = struct { self.deinit_command = null; self.initialized = false; } + + pub fn current_key_event_sequence_bindings(self: *const Mode, allocator: std.mem.Allocator) error{OutOfMemory}![]const Binding { + if (globals.current_sequence.items.len == 0) return &.{}; + return self.bindings.get_matches_for_key_event_sequence(allocator, globals.current_sequence.items); + } }; const NamespaceMap = std.StringHashMapUnmanaged(Namespace); @@ -760,6 +768,18 @@ const BindingSet = struct { globals.current_sequence.clearRetainingCapacity(); } } + + /// Retreive bindings that will match a key event sequence + pub fn get_matches_for_key_event_sequence(self: *const @This(), allocator: std.mem.Allocator, sequence: []const KeyEvent) error{OutOfMemory}![]const Binding { + var matches: std.ArrayListUnmanaged(Binding) = .{}; + for (self.press.items) |*binding| switch (binding.match(sequence)) { + .matched, .match_possible => { + (try matches.addOne(allocator)).* = binding.*; + }, + .match_impossible => {}, + }; + return matches.toOwnedSlice(allocator); + } }; pub const LineNumbers = enum { diff --git a/src/tui/tui.zig b/src/tui/tui.zig index 41b20a1..82a390a 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -297,6 +297,15 @@ fn handle_input_idle(self: *Self) void { var buf: [32]u8 = undefined; const m = tp.message.fmtbuf(&buf, .{"input_idle"}) catch return; _ = self.send_widgets(tp.self_pid(), m) catch return; + if (self.input_mode_) |mode| { + const bindings = mode.current_key_event_sequence_bindings(self.allocator) catch return; + defer self.allocator.free(bindings); + for (bindings) |binding| + self.logger.print(" {f} => {s}", .{ + keybind.key_event_sequence_fmt(binding.key_events), + binding.commands[0].command, + }); + } } fn update_input_idle_timer(self: *Self) void {