From 65665fb28b85cf00b165ed4fb07e59b6535bbb11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Mon, 27 Oct 2025 16:54:34 -0500 Subject: [PATCH] feat: [hx] in Normal mode select to char right f j in normal mode selects to the char j in the buffer if it exists, else the cursor stays in place --- src/keybind/builtin/helix.json | 2 +- src/tui/editor.zig | 15 +++++++++++++++ src/tui/mode/helix.zig | 29 +++++++++++++++++++---------- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/keybind/builtin/helix.json b/src/keybind/builtin/helix.json index 6282250..103f577 100644 --- a/src/keybind/builtin/helix.json +++ b/src/keybind/builtin/helix.json @@ -117,7 +117,7 @@ ["l", "move_right"], ["t", "find_till_char"], - ["f", "move_to_char", "move_to_char_right"], + ["f", "move_to_char", "select_to_char_right_helix"], ["home", "move_begin"], ["end", "move_end"], diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 01dec2a..398318c 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -2017,6 +2017,20 @@ pub const Editor = struct { return if (someone_stopped) error.Stop else root; } + fn with_cursel_const_once_arg(root: Buffer.Root, move: cursel_operator_mut_once_arg, cursel: *CurSel, ctx: Context, metrics: Buffer.Metrics) error{Stop}!void { + try move(root, cursel, ctx, metrics); + } + + pub fn with_cursels_const_once_arg(self: *Self, root: Buffer.Root, move: cursel_operator_mut_once_arg, ctx: Context) error{Stop}!void { + var someone_stopped = false; + for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| + with_cursel_const_once_arg(root, move, cursel, ctx, self.metrics) catch { + someone_stopped = true; + }; + self.collapse_cursors(); + return if (someone_stopped) error.Stop else {}; + } + fn with_cursel_const(root: Buffer.Root, op: cursel_operator_const, cursel: *CurSel) error{Stop}!void { return op(root, cursel); } @@ -2080,6 +2094,7 @@ pub const Editor = struct { const cursor_predicate = *const fn (root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) bool; const cursor_operator_const = *const fn (root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void; const cursor_operator_const_arg = *const fn (root: Buffer.Root, cursor: *Cursor, ctx: Context, metrics: Buffer.Metrics) error{Stop}!void; + const cursel_operator_mut_once_arg = *const fn (root: Buffer.Root, cursel: *CurSel, ctx: Context, metrics: Buffer.Metrics) error{Stop}!void; const cursor_view_operator_const = *const fn (root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) error{Stop}!void; const cursel_operator_const = *const fn (root: Buffer.Root, cursel: *CurSel) error{Stop}!void; const cursor_operator = *const fn (root: Buffer.Root, cursor: *Cursor, allocator: Allocator) error{Stop}!Buffer.Root; diff --git a/src/tui/mode/helix.zig b/src/tui/mode/helix.zig index 9faf5d5..db58645 100644 --- a/src/tui/mode/helix.zig +++ b/src/tui/mode/helix.zig @@ -375,18 +375,11 @@ const cmds_ = struct { pub fn select_to_char_right_helix(_: *void, ctx: Ctx) Result { const mv = tui.mainview() orelse return; const ed = mv.get_active_editor() orelse return; - const root = try ed.buf_root(); - - for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| { - const sel = try cursel.enable_selection(root, ed.metrics); - try Editor.move_cursor_to_char_right(root, &sel.end, ctx, ed.metrics); - try Editor.move_cursor_right(root, &sel.end, ed.metrics); - cursel.cursor = sel.end; - cursel.check_selection(root, ed.metrics); - }; + const root = ed.buf_root() catch return; + try ed.with_cursels_const_once_arg(root, &select_cursel_to_char_right_helix, ctx); ed.clamp(); } - pub const select_to_char_right_helix_meta: Meta = .{ .description = "Move to char right" }; + pub const select_to_char_right_helix_meta: Meta = .{ .description = "Select to char right" }; pub fn copy_helix(_: *void, _: Ctx) Result { const mv = tui.mainview() orelse return; @@ -418,6 +411,22 @@ const cmds_ = struct { pub const paste_clipboard_before_meta: Meta = .{ .description = "Paste from clipboard before selection" }; }; +fn select_cursel_to_char_right_helix(root: Buffer.Root, cursel: *CurSel, ctx: command.Context, metrics: Buffer.Metrics) error{Stop}!void { + var moving_cursor: Cursor = cursel.*.cursor; + const begin = cursel.*.cursor; + move_cursor_to_char_right_beyond_eol(root, &moving_cursor, metrics, ctx) catch return; + + //Character found, selecting + Editor.move_cursor_right(root, &moving_cursor, metrics) catch { + // We might be at end of file + }; + moving_cursor.target = moving_cursor.col; + const sel = try cursel.enable_selection(root, metrics); + sel.begin = begin; + sel.end = moving_cursor; + cursel.cursor = moving_cursor; +} + fn move_cursor_find_egc_beyond_eol(root: Buffer.Root, cursor: *Cursor, ctx: command.Context, metrics: Buffer.Metrics, move: find_char_function) error{Stop}!void { move(root, cursor, metrics, ctx); }