From d974d510b1c2cbb78079163007b177585ce89598 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Wed, 4 Feb 2026 10:09:16 +0100 Subject: [PATCH 1/2] refactor: rename is_non_word_char --- src/tui/editor.zig | 6 +++--- src/tui/mode/helix.zig | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 7cea194..8bbf631 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -2458,7 +2458,7 @@ pub const Editor = struct { const cursel_operator_mut = *const fn (self: *Self, root: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root; const cursel_operator_mut_arg = *const fn (self: *Self, root: Buffer.Root, cursel: *CurSel, allocator: Allocator, ctx: Context) error{Stop}!Buffer.Root; - pub fn is_not_word_char(c: []const u8) bool { + pub fn is_non_word_char(c: []const u8) bool { if (c.len == 0) return true; return switch (c[0]) { ' ' => true, @@ -2493,7 +2493,7 @@ pub const Editor = struct { } pub fn is_word_char(c: []const u8) bool { - return !is_not_word_char(c); + return !is_non_word_char(c); } fn is_word_char_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { @@ -2501,7 +2501,7 @@ pub const Editor = struct { } pub fn is_non_word_char_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { - return cursor.test_at(root, is_not_word_char, metrics); + return cursor.test_at(root, is_non_word_char, metrics); } pub fn is_word_boundary_left(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { diff --git a/src/tui/mode/helix.zig b/src/tui/mode/helix.zig index 0230b82..2721df2 100644 --- a/src/tui/mode/helix.zig +++ b/src/tui/mode/helix.zig @@ -829,8 +829,8 @@ fn move_cursor_word_left_helix(root: Buffer.Root, cursor: *Cursor, metrics: Buff var next_next = next; next_next.move_left(root, metrics) catch return; - const cur = next.test_at(root, Editor.is_not_word_char, metrics); - const nxt = next_next.test_at(root, Editor.is_not_word_char, metrics); + const cur = next.test_at(root, Editor.is_non_word_char, metrics); + const nxt = next_next.test_at(root, Editor.is_non_word_char, metrics); if (cur != nxt) { try Editor.move_cursor_left(root, cursor, metrics); return; From 9c8d5f8aabbd45ef34a55eb901a898758177ff74 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Wed, 4 Feb 2026 10:09:38 +0100 Subject: [PATCH 2/2] fix: use completion specific boundary search to the right for guesing completion range closes #484 --- src/tui/editor.zig | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 8bbf631..99e0482 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -4995,7 +4995,7 @@ pub const Editor = struct { _ = self.pop_tabstop(); } - fn is_trigger_left(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics, triggers: []const TriggerSymbol) bool { + fn is_completion_boundary_left(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics, triggers: []const TriggerSymbol) bool { if (cursor.col == 0) return true; var next = cursor.*; next.move_left(root, metrics) catch return true; @@ -5007,17 +5007,27 @@ pub const Editor = struct { return false; } + fn is_completion_boundary_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics, triggers: []const TriggerSymbol) bool { + var pos = cursor.*; + const egc, _, _ = pos.egc_at(root, metrics) catch return true; + if (is_non_word_char(egc)) return true; + const c = egc[0]; + for (triggers) |t| if (c == t.char) return true; + return false; + } + pub fn guest_completion_range(self: *Self) Selection { var cursel = self.get_primary().*; var sel = Selection.from_cursor(&cursel.cursor); if (cursel.cursor.col == 0) return sel; const root = self.buf_root() catch return sel; - while (!is_trigger_left(root, &sel.begin, self.metrics, self.get_event_triggers(.insert).items)) + while (!is_completion_boundary_left(root, &sel.begin, self.metrics, self.get_event_triggers(.insert).items)) move_cursor_left(root, &sel.begin, self.metrics) catch return sel; if (tui.config().completion_insert_mode == .replace) - move_cursor_word_right(root, &sel.end, self.metrics) catch return sel; + while (!is_completion_boundary_at_cursor(root, &sel.end, self.metrics, self.get_event_triggers(.insert).items)) + move_cursor_right(root, &sel.end, self.metrics) catch return sel; return sel; }