From 8ba6e1843a193a6e1040058dc0c74e5ad335e78d Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Wed, 26 Nov 2025 23:09:17 +0100 Subject: [PATCH 1/3] refactor: don't special case cursor rendering in inclusive mode This is too confusing. Rendering cursors differently, only in inclusive mode and only if there is an active selection is too confusing and pushes a lot of edge cases into otherwise simple commands. This will likely break a lot of the existing helix commands, but is better in the long run to fix them anyway. --- src/tui/editor.zig | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index ddcda8f..83d2832 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -146,13 +146,6 @@ pub const CurSel = struct { }; } - fn to_cursor_inclusive(self: *const Self, root: Buffer.Root, metrics: Buffer.Metrics) Cursor { - var cursor = self.cursor; - if (self.selection) |sel| if (!sel.is_reversed()) - cursor.move_left(root, metrics) catch {}; - return cursor; - } - pub fn disable_selection(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) void { switch (tui.get_selection_style()) { .normal => self.disable_selection_normal(), @@ -1181,26 +1174,18 @@ pub const Editor = struct { } fn render_cursors(self: *Self, theme: *const Widget.Theme, cell_map: CellMap) !void { - const style = tui.get_selection_style(); const frame = tracy.initZone(@src(), .{ .name = "editor render cursors" }); defer frame.deinit(); if (tui.config().enable_terminal_cursor and tui.rdr().vx.caps.multi_cursor) tui.rdr().clear_all_multi_cursors() catch {}; for (self.cursels.items[0 .. self.cursels.items.len - 1]) |*cursel_| if (cursel_.*) |*cursel| { - const cursor = self.get_rendered_cursor(style, cursel); + const cursor = cursel.cursor; try self.render_cursor_secondary(&cursor, theme, cell_map); }; - const cursor = self.get_rendered_cursor(style, self.get_primary()); + const cursor = self.get_primary().cursor; try self.render_cursor_primary(&cursor, theme, cell_map); } - fn get_rendered_cursor(self: *Self, style: anytype, cursel: anytype) Cursor { - return switch (style) { - .normal => cursel.cursor, - .inclusive => cursel.to_cursor_inclusive(self.buf_root() catch return cursel.cursor, self.metrics), - }; - } - fn render_cursor_primary(self: *Self, cursor: *const Cursor, theme: *const Widget.Theme, cell_map: CellMap) !void { if (!tui.is_mainview_focused() or !self.enable_terminal_cursor) { if (self.screen_cursor(cursor)) |pos| { From c7c271e90309334f83b0a5c87bdd5ea6978a9ea6 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Wed, 26 Nov 2025 23:16:50 +0100 Subject: [PATCH 2/3] refactor: CurSel.to_selection is internal --- 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 83d2832..fd417c0 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -125,7 +125,7 @@ pub const CurSel = struct { return if (self.selection) |*sel| sel else unreachable; } - pub fn to_selection(self: *const Self, root: Buffer.Root, metrics: Buffer.Metrics) Selection { + fn to_selection(self: *const Self, root: Buffer.Root, metrics: Buffer.Metrics) Selection { return switch (tui.get_selection_style()) { .normal => self.to_selection_normal(), .inclusive => self.to_selection_inclusive(root, metrics), From f99e10652cda71cae166bfdf4bceff2b50bd6cf1 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Thu, 27 Nov 2025 11:28:00 +0100 Subject: [PATCH 3/3] refactor: add Editor.with_cursels_const_repeat --- src/tui/editor.zig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index fd417c0..5e34ca3 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -2117,6 +2117,21 @@ pub const Editor = struct { return if (someone_stopped) error.Stop else {}; } + pub fn with_cursels_const_repeat(self: *Self, root: Buffer.Root, move: cursel_operator_const, ctx: Context) error{Stop}!void { + var someone_stopped = false; + var repeat: usize = 1; + _ = ctx.args.match(.{tp.extract(&repeat)}) catch false; + while (repeat > 0) : (repeat -= 1) { + for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| + with_cursel_const(root, move, cursel, self.metrics) catch { + someone_stopped = true; + }; + self.collapse_cursors(); + if (someone_stopped) break; + } + return if (someone_stopped) error.Stop else {}; + } + fn with_cursel_mut_arg(self: *Self, root: Buffer.Root, op: cursel_operator_mut_arg, cursel: *CurSel, allocator: Allocator, ctx: Context) error{Stop}!Buffer.Root { return op(self, root, cursel, allocator, ctx); }