From 485f06f57611a6c050647d595f5cae294c135f0b Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sun, 1 Feb 2026 17:02:13 +0100 Subject: [PATCH 1/7] refactor: split up completion_dropdown.handle_event function --- src/tui/mode/overlay/completion_dropdown.zig | 48 +++++++++++--------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/src/tui/mode/overlay/completion_dropdown.zig b/src/tui/mode/overlay/completion_dropdown.zig index a035dbb..c059640 100644 --- a/src/tui/mode/overlay/completion_dropdown.zig +++ b/src/tui/mode/overlay/completion_dropdown.zig @@ -102,25 +102,8 @@ pub fn handle_event(self: *Type, _: tp.pid_ref, m: tp.message) tp.result { try m.match(.{ "E", "close" })) { const cursor = self.value.editor.get_primary().cursor; - if (self.value.cursor.row != cursor.row or - self.value.cursor.col > cursor.col or - !self.value.view.eql(self.value.editor.view)) - { - tp.self_pid().send(.{ "cmd", "palette_menu_cancel" }) catch |e| self.logger.err(module_name, e); - } else { - const query = get_query_text_nostore(self, cursor, self.allocator) catch |e| switch (e) { - error.Stop => return, - else => |e_| { - self.logger.err(module_name, e_); - return; - }, - }; - defer self.allocator.free(query); - if (self.value.last_query) |last| { - if (!std.mem.eql(u8, query, last)) - update_query(self, cursor) catch |e| self.logger.err(module_name, e); - } else update_query(self, cursor) catch |e| self.logger.err(module_name, e); - } + if (!maybe_cancel(self, cursor)) + maybe_update_query(self, cursor) catch |e| self.logger.err(module_name, e); } } @@ -143,12 +126,35 @@ fn get_query_text(self: *Type, cursor: ed.Cursor, allocator: std.mem.Allocator) return query; } -fn update_query(self: *Type, cursor: ed.Cursor) error{OutOfMemory}!void { +fn maybe_cancel(self: *Type, cursor: Buffer.Cursor) bool { + if (self.value.cursor.row != cursor.row or + self.value.cursor.col > cursor.col or + !self.value.view.eql(self.value.editor.view)) + { + tp.self_pid().send(.{ "cmd", "palette_menu_cancel" }) catch |e| self.logger.err(module_name, e); + return true; + } + return false; +} + +fn maybe_update_query(self: *Type, cursor: Buffer.Cursor) error{OutOfMemory}!void { + const query = get_query_text_nostore(self, cursor, self.allocator) catch |e| switch (e) { + error.Stop => return, + else => |e_| return e_, + }; + defer self.allocator.free(query); + if (self.value.last_query) |last| { + if (!std.mem.eql(u8, query, last)) + try update_query_text(self, cursor); + } else try update_query_text(self, cursor); +} + +fn update_query_text(self: *Type, cursor: ed.Cursor) error{OutOfMemory}!void { const query = get_query_text(self, cursor, self.allocator) catch |e| switch (e) { error.Stop => return, else => |e_| return e_, }; - self.update_query(query) catch return; + Type.update_query(self, query) catch return; tp.self_pid().send(.{ "cmd", "completion" }) catch |e| self.logger.err(module_name, e); return; } From e45f2ced71e8a3622d379fb8a5a60e4bda398318 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sun, 1 Feb 2026 17:56:07 +0100 Subject: [PATCH 2/7] fix: do not constantly re-trigger completion when already completing --- src/tui/mode/overlay/completion_dropdown.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tui/mode/overlay/completion_dropdown.zig b/src/tui/mode/overlay/completion_dropdown.zig index c059640..6ed7ef1 100644 --- a/src/tui/mode/overlay/completion_dropdown.zig +++ b/src/tui/mode/overlay/completion_dropdown.zig @@ -155,7 +155,6 @@ fn update_query_text(self: *Type, cursor: ed.Cursor) error{OutOfMemory}!void { else => |e_| return e_, }; Type.update_query(self, query) catch return; - tp.self_pid().send(.{ "cmd", "completion" }) catch |e| self.logger.err(module_name, e); return; } From 97745a992ae6f1b0d42eb414ac5dd20a1ace7e5a Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sun, 1 Feb 2026 17:56:47 +0100 Subject: [PATCH 3/7] fix: refresh inital completion cursor position on re-triggers --- src/tui/mode/overlay/completion_dropdown.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tui/mode/overlay/completion_dropdown.zig b/src/tui/mode/overlay/completion_dropdown.zig index 6ed7ef1..3aed39c 100644 --- a/src/tui/mode/overlay/completion_dropdown.zig +++ b/src/tui/mode/overlay/completion_dropdown.zig @@ -44,7 +44,6 @@ var max_description: usize = 0; pub fn init(self: *Type) error{ Stop, OutOfMemory }!void { try self.value.commands.init(self); self.value.editor = tui.get_active_editor() orelse return error.Stop; - self.value.cursor = self.value.editor.get_primary().cursor; self.value.view = self.value.editor.view; } @@ -52,6 +51,7 @@ pub fn load_entries(self: *Type) !usize { max_description = 0; var max_label_len: usize = 0; + self.value.cursor = self.value.editor.get_primary().cursor; self.value.query = null; var iter: []const u8 = self.value.editor.completions.data.items; while (iter.len > 0) { From 99e3e6aeae5e8e2b951dffa4bdd8957095c66b12 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sun, 1 Feb 2026 17:57:32 +0100 Subject: [PATCH 4/7] fix: update_completion should also update completion query text Also, resize dropdown based on new completion suggestions. --- src/tui/mode/overlay/completion_dropdown.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tui/mode/overlay/completion_dropdown.zig b/src/tui/mode/overlay/completion_dropdown.zig index 3aed39c..5708532 100644 --- a/src/tui/mode/overlay/completion_dropdown.zig +++ b/src/tui/mode/overlay/completion_dropdown.zig @@ -374,7 +374,8 @@ const cmds = struct { } clear_entries(self); - _ = try load_entries(self); + self.longest_hint = try load_entries(self); + try update_query_text(self, self.value.editor.get_primary().cursor); } pub const update_completion_meta: Meta = .{}; }; From 7cf45d587897ea25fc13ccc1a848cb3b97307fca Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sun, 1 Feb 2026 17:59:04 +0100 Subject: [PATCH 5/7] refactor: simplify add_completion_done --- src/tui/editor.zig | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 411d80f..2abb705 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -6601,12 +6601,8 @@ pub const Editor = struct { pub fn add_completion_done(self: *Self) anyerror!bool { self.completions.deinit(self.allocator); - self.completions = .empty; - if (self.completions_request) |*request| { - self.completions.deinit(self.allocator); - self.completions = request.*; - self.completions_request = .done; - } + self.completions = if (self.completions_request) |*request| request.* else .empty; + self.completions_request = .done; var open_completions = self.completions.data.items.len > 0; const update_completion = "update_completion"; From f35e522260bdde13b0ecc46f35056a12486d398c Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sun, 1 Feb 2026 17:59:29 +0100 Subject: [PATCH 6/7] refactor: log number of returned completion if log_execution is on --- src/tui/editor.zig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 2abb705..0974e3b 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -6604,6 +6604,13 @@ pub const Editor = struct { self.completions = if (self.completions_request) |*request| request.* else .empty; self.completions_request = .done; + if (command.log_execute) { + var iter: []const u8 = self.completions.data.items; + var count: usize = 0; + while (iter.len > 0) : (count += 1) try cbor.skipValue(&iter); + self.logger.print("completions: {d}", .{count}); + } + var open_completions = self.completions.data.items.len > 0; const update_completion = "update_completion"; if (command.get_id(update_completion)) |cmd_id| { From 01cbdf8545bb9ef9b01b119f90a3cd0ee069b897 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sun, 1 Feb 2026 18:12:51 +0100 Subject: [PATCH 7/7] fix: `every_keystroke` completion mode should fallback to `automatic` when active This prevents `every_keystroke` mode from re-triggering on every keystroke if a completion suggestions are already available. Instead it will now filter the returned suggestions normally. This dramatically reduces load on the LSP. closes #479 --- src/tui/editor.zig | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 0974e3b..4af99ac 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -6552,7 +6552,15 @@ pub const Editor = struct { } pub fn run_triggers(self: *Self, cursel: *const CurSel, char: u8, event: TriggerEvent) void { - switch (tui.config().completion_trigger) { + var mode = tui.config().completion_trigger; + + if (mode == .every_keystroke) { + const update_completion = "update_completion"; + const in_completion = command.get_id(update_completion) != null; + mode = if (in_completion) .automatic else .every_keystroke; + } + + switch (mode) { .manual => return, .every_keystroke => return self.run_triggers_every_keystroke(cursel, char, event), .automatic => {},