Compare commits

...

7 commits

Author SHA1 Message Date
01cbdf8545
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
2026-02-01 18:12:51 +01:00
f35e522260
refactor: log number of returned completion if log_execution is on 2026-02-01 17:59:29 +01:00
7cf45d5878
refactor: simplify add_completion_done 2026-02-01 17:59:04 +01:00
99e3e6aeae
fix: update_completion should also update completion query text
Also, resize dropdown based on new completion suggestions.
2026-02-01 17:57:32 +01:00
97745a992a
fix: refresh inital completion cursor position on re-triggers 2026-02-01 17:56:47 +01:00
e45f2ced71
fix: do not constantly re-trigger completion when already completing 2026-02-01 17:56:07 +01:00
485f06f576
refactor: split up completion_dropdown.handle_event function 2026-02-01 17:02:13 +01:00
2 changed files with 47 additions and 30 deletions

View file

@ -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 => {},
@ -6601,11 +6609,14 @@ 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;
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;

View file

@ -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) {
@ -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,13 +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;
tp.self_pid().send(.{ "cmd", "completion" }) catch |e| self.logger.err(module_name, e);
Type.update_query(self, query) catch return;
return;
}
@ -369,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 = .{};
};