diff --git a/src/Surface.zig b/src/Surface.zig index 8c1c31a84..2254b287c 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -2569,14 +2569,22 @@ pub fn keyEventIsBinding( .press, .repeat => {}, } - // Our keybinding set is either our current nested set (for - // sequences) or the root set. - const set = self.keyboard.sequence_set orelse &self.config.keybind.set; + // If we're in a sequence, check the sequence set + if (self.keyboard.sequence_set) |set| { + return set.getEvent(event) != null; + } - // log.warn("text keyEventIsBinding event={} match={}", .{ event, set.getEvent(event) != null }); + // Check active key tables (inner-most to outer-most) + const table_items = self.keyboard.table_stack.items; + for (0..table_items.len) |i| { + const rev_i: usize = table_items.len - 1 - i; + if (table_items[rev_i].set.getEvent(event) != null) { + return true; + } + } - // If we have a keybinding for this event then we return true. - return set.getEvent(event) != null; + // Check the root set + return self.config.keybind.set.getEvent(event) != null; } /// Called for any key events. This handles keybindings, encoding and diff --git a/src/config/Config.zig b/src/config/Config.zig index 8d941c733..17b4275b0 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -5822,6 +5822,7 @@ pub const Keybinds = struct { // allocated value). This isn't a memory leak because the arena // will be freed when the config is freed. self.set = .{}; + self.tables = .empty; // keybinds for opening and reloading config try self.set.put( @@ -6591,6 +6592,7 @@ pub const Keybinds = struct { // will be freed when the config is freed. log.info("config has 'keybind = clear', all keybinds cleared", .{}); self.set = .{}; + self.tables = .empty; return; } @@ -7073,6 +7075,52 @@ pub const Keybinds = struct { try testing.expect(std.mem.indexOf(u8, output, "keybind = shift+b=csi:world\n") != null); try testing.expect(std.mem.indexOf(u8, output, "keybind = foo/shift+a=csi:hello\n") != null); } + + test "parseCLI clear clears tables" { + const testing = std.testing; + var arena = ArenaAllocator.init(testing.allocator); + defer arena.deinit(); + const alloc = arena.allocator(); + + var keybinds: Keybinds = .{}; + + // Add bindings to root set and tables + try keybinds.parseCLI(alloc, "shift+a=copy_to_clipboard"); + try keybinds.parseCLI(alloc, "foo/shift+b=paste_from_clipboard"); + try keybinds.parseCLI(alloc, "bar/ctrl+c=close_window"); + + try testing.expectEqual(1, keybinds.set.bindings.count()); + try testing.expectEqual(2, keybinds.tables.count()); + + // Clear all keybinds + try keybinds.parseCLI(alloc, "clear"); + + // Both root set and tables should be cleared + try testing.expectEqual(0, keybinds.set.bindings.count()); + try testing.expectEqual(0, keybinds.tables.count()); + } + + test "parseCLI reset clears tables" { + const testing = std.testing; + var arena = ArenaAllocator.init(testing.allocator); + defer arena.deinit(); + const alloc = arena.allocator(); + + var keybinds: Keybinds = .{}; + + // Add bindings to tables + try keybinds.parseCLI(alloc, "foo/shift+a=copy_to_clipboard"); + try keybinds.parseCLI(alloc, "bar/shift+b=paste_from_clipboard"); + + try testing.expectEqual(2, keybinds.tables.count()); + + // Reset to defaults (empty value) + try keybinds.parseCLI(alloc, ""); + + // Tables should be cleared, root set has defaults + try testing.expectEqual(0, keybinds.tables.count()); + try testing.expect(keybinds.set.bindings.count() > 0); + } }; /// See "font-codepoint-map" for documentation.