From 7dc3e531c60b16e49669563e05862bcb619abb46 Mon Sep 17 00:00:00 2001 From: Paul Graydon Date: Wed, 18 Feb 2026 22:48:32 +0100 Subject: [PATCH 1/6] feat: [vim] add leader key bindings --- src/keybind/builtin/vim.json | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index 54291a0..467bdae 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -3,10 +3,22 @@ "init_command": ["enter_vim_mode"], "deinit_command": ["exit_vim_mode"] }, + "project": { + "syntax": "vim", + "on_match_failure": "ignore", + "press": [ + ["", "find_file"], + ["b", "switch_buffers"], + ["/", "find_in_files"], + + ["gs", "show_vcs_status"] + ] + }, "normal": { "syntax": "vim", "on_match_failure": "ignore", "name": "NORMAL", + "inherit": "project", "line_numbers": "relative", "cursor": "block", "selection": "normal", @@ -24,7 +36,6 @@ ["k", "move_up_vim"], ["l", "move_right_vim"], ["h", "move_left_vim"], - ["", "move_right_vim"], ["J", "join_next_line"], @@ -56,7 +67,7 @@ ["gi", "goto_implementation"], ["gy", "goto_type_definition"], ["gg", "goto_line_vim"], - ["grn", "rename_symbol"], + ["gr", "references"], ["gD", "goto_declaration"], ["G", "move_buffer_end"], @@ -112,13 +123,20 @@ ["6", "add_integer_argument_digit", 6], ["7", "add_integer_argument_digit", 7], ["8", "add_integer_argument_digit", 8], - ["9", "add_integer_argument_digit", 9] + ["9", "add_integer_argument_digit", 9], + + ["lf", "format"], + ["lr", "rename_symbol"], + + ["sd", "show_diagnostics"], + ["ss", "show_symbols"] ] }, "visual": { "syntax": "vim", "on_match_failure": "ignore", "name": "VISUAL", + "inherit": "project", "line_numbers": "relative", "cursor": "block", "selection": "normal", @@ -184,6 +202,7 @@ "syntax": "vim", "on_match_failure": "ignore", "name": "VISUAL LINE", + "inherit": "project", "line_numbers": "relative", "cursor": "block", "selection": "normal", From 5bc7f4c2e8139eb38e66cb04ad943bba381cd015 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Thu, 19 Feb 2026 09:47:11 +0100 Subject: [PATCH 2/6] refactor: add more detailed request errors to Project --- src/Project.zig | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/Project.zig b/src/Project.zig index ae361c9..ffba3db 100644 --- a/src/Project.zig +++ b/src/Project.zig @@ -55,7 +55,17 @@ const Self = @This(); const OutOfMemoryError = error{OutOfMemory}; const SpawnError = (OutOfMemoryError || error{ThespianSpawnFailed}); -pub const RequestError = error{InvalidRequest} || OutOfMemoryError || cbor.Error; +pub const RequestError = error{ + InvalidMostRecentFileRequest, + InvalidNewOrModifiedFilesRequest, + InvalidQueryNewOrModifiedFilesRequest, + InvalidRequestNewOrModifiedFilesRequest, + InvalidRecentFilesRequest, + InvalidQueryRecentFilesRequest, + InvalidGetMruPositionRequest, + InvalidVcsStatusRequest, + InvalidTasksRequest, +} || OutOfMemoryError || cbor.Error; pub const StartLspError = (error{ ThespianSpawnFailed, Timeout, InvalidLspCommand } || LspError || OutOfMemoryError || cbor.Error); pub const LspError = (error{ NoLsp, LspFailed } || OutOfMemoryError || std.Io.Writer.Error); pub const GitError = error{InvalidGitResponse}; @@ -386,7 +396,7 @@ inline fn sort_by_mtime(T: type, items: []T) void { } pub fn request_n_most_recent_file(self: *Self, from: tp.pid_ref, n: usize) RequestError!void { - if (n >= self.files.items.len) return error.InvalidRequest; + if (n >= self.files.items.len) return error.InvalidMostRecentFileRequest; const file_path = if (self.files.items.len > 0) self.files.items[n].path else null; from.send(.{file_path}) catch |e| std.log.err("send request_n_most_recent_file failed: {t}", .{e}); @@ -415,7 +425,7 @@ fn simple_query_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize, while (n < query.len) : (n += 1) matches[n] = idx + n; from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, file.path, file.type, file.icon, file.color, file.vcs_status, matches }) catch |e| { std.log.err("send new_or_modified_files failed: {t}", .{e}); - return error.InvalidRequest; + return error.InvalidNewOrModifiedFilesRequest; }; i += 1; if (i >= max) return i; @@ -485,7 +495,7 @@ pub fn query_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize, qu for (matches.items[0..@min(max, matches.items.len)]) |match| from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, match.path, match.type, match.icon, match.color, match.vcs_status, match.matches }) catch |e| { std.log.err("send new_or_modified_files failed: {t}", .{e}); - return error.InvalidRequest; + return error.InvalidQueryNewOrModifiedFilesRequest; }; return @min(max, matches.items.len); } @@ -495,7 +505,7 @@ pub fn request_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize) for (self.new_or_modified_files.items, 0..) |file, i| { from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, file.path, file.type, file.icon, file.color, file.vcs_status }) catch |e| { std.log.err("send navigate failed: {t}", .{e}); - return error.InvalidRequest; + return error.InvalidRequestNewOrModifiedFilesRequest; }; if (i >= max) return; } @@ -513,7 +523,7 @@ fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: [ while (n < query.len) : (n += 1) matches[n] = idx + n; from.send(.{ "PRJ", "recent", self.longest_file_path, file.path, file.type, file.icon, file.color, matches }) catch |e| { std.log.err("send navigate failed: {t}", .{e}); - return error.InvalidRequest; + return error.InvalidRecentFilesRequest; }; i += 1; if (i >= max) return i; @@ -572,7 +582,7 @@ pub fn query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query_: []c for (matches.items[0..@min(max, matches.items.len)]) |match| from.send(.{ "PRJ", "recent", self.longest_file_path, match.path, match.type, match.icon, match.color, match.matches }) catch |e| { std.log.err("send navigate failed: {t}", .{e}); - return error.InvalidRequest; + return error.InvalidQueryRecentFilesRequest; }; return @min(max, matches.items.len); } @@ -808,10 +818,10 @@ fn update_mru_internal(self: *Self, file_path: []const u8, mtime: i128, row: usi pub fn get_mru_position(self: *Self, from: tp.pid_ref, file_path: []const u8) RequestError!void { for (self.files.items) |*file| { if (!std.mem.eql(u8, file.path, file_path)) continue; - from.send(.{ file.pos.row + 1, file.pos.col + 1 }) catch return error.InvalidRequest; + from.send(.{ file.pos.row + 1, file.pos.col + 1 }) catch return error.InvalidGetMruPositionRequest; return; } - from.send(.{"none"}) catch return error.InvalidRequest; + from.send(.{"none"}) catch return error.InvalidGetMruPositionRequest; } pub fn request_vcs_status(self: *Self, from: tp.pid_ref) RequestError!void { @@ -822,7 +832,7 @@ pub fn request_vcs_status(self: *Self, from: tp.pid_ref) RequestError!void { if (self.status_request) |_| return; self.status_request = from.clone(); }, - else => return error.InvalidRequest, + else => return error.InvalidVcsStatusRequest, }, .running => { if (self.status_request) |_| return; @@ -859,7 +869,7 @@ pub fn request_tasks(self: *Self, from: tp.pid_ref) RequestError!void { try cbor.writeValue(writer, task.command); from.send_raw(.{ .buf = message.written() }) catch |e| { std.log.err("send navigate failed: {t}", .{e}); - return error.InvalidRequest; + return error.InvalidTasksRequest; }; } From db60fa16868320e6afe43382454ee2a81a8aec95 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Thu, 19 Feb 2026 09:49:03 +0100 Subject: [PATCH 3/6] fix: add command description for goto_line_vim --- src/tui/editor.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 8eb7af3..cabbea2 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -6286,7 +6286,7 @@ pub const Editor = struct { self.clamp(); try self.send_editor_jump_destination(); } - pub const goto_line_vim_meta: Meta = .{ .arguments = &.{.integer} }; + pub const goto_line_vim_meta: Meta = .{ .description = "Goto line (vim)", .arguments = &.{.integer} }; pub fn select_to_line_vim(self: *Self, ctx: Context) Result { try self.send_editor_jump_source(); From 6d58fa5912dca7a55e8124c142c1f2be77a0cf42 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Thu, 19 Feb 2026 10:05:38 +0100 Subject: [PATCH 4/6] feat: add some space leader bindings to vim home mode by inheriting from project mode --- src/keybind/builtin/vim.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index 467bdae..68c4461 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -281,6 +281,7 @@ "home": { "syntax": "vim", "on_match_failure": "ignore", + "inherit": "project", "press": [ ["f", "find_file"], ["g", "find_in_files"], @@ -291,8 +292,7 @@ ["F", "change_fontface"], ["h", "open_help"], ["v", "open_version_info"], - ["q", "quit"], - ["", "home_menu_activate"] + ["q", "quit"] ] } } From 4287e9a28b7de97ddc63debfaffd3f2d22bf5e1e Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Thu, 19 Feb 2026 10:23:26 +0100 Subject: [PATCH 5/6] fix: vim visual modes should inherit from normale mode --- src/keybind/builtin/vim.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index 68c4461..3145348 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -136,7 +136,7 @@ "syntax": "vim", "on_match_failure": "ignore", "name": "VISUAL", - "inherit": "project", + "inherit": "normal", "line_numbers": "relative", "cursor": "block", "selection": "normal", @@ -202,7 +202,7 @@ "syntax": "vim", "on_match_failure": "ignore", "name": "VISUAL LINE", - "inherit": "project", + "inherit": "normal", "line_numbers": "relative", "cursor": "block", "selection": "normal", From 620128e6fdc7c7e050fac439cd7fcda602dc84f2 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Thu, 19 Feb 2026 10:06:02 +0100 Subject: [PATCH 6/6] fix: explicitly override close_/save_file in vim normal mode --- src/keybind/builtin/vim.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index 3145348..a844be6 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -23,6 +23,8 @@ "cursor": "block", "selection": "normal", "press": [ + ["", "close_file"], + ["", "save_file"], ["b", "move_word_left_vim"], ["w", "move_word_right_vim"], ["W", "move_word_right"],