From 7faea783f33cd9e4fb18778d10ed54d5b913d597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Mon, 13 Oct 2025 15:19:27 -0500 Subject: [PATCH] refactor: hx paste(before, replace, after) Code simplification and zig idiomatics to improve code readability. --- src/keybind/builtin/helix.json | 4 +- src/tui/editor.zig | 13 +---- src/tui/mode/helix.zig | 96 +++++++++++++++++++--------------- 3 files changed, 57 insertions(+), 56 deletions(-) diff --git a/src/keybind/builtin/helix.json b/src/keybind/builtin/helix.json index 15e015d..a33e6d0 100644 --- a/src/keybind/builtin/helix.json +++ b/src/keybind/builtin/helix.json @@ -131,7 +131,7 @@ ["g s", "smart_move_begin"], ["g d", "goto_definition"], ["g y", "goto_type_definition"], - ["g r", "goto_reference"], + ["g r", "references"], ["g i", "goto_implementation"], ["g t", "goto_window_top"], ["g c", "goto_window_center"], @@ -426,7 +426,7 @@ ["g s", "smart_move_begin"], ["g d", "goto_definition"], ["g y", "goto_type_definition"], - ["g r", "goto_reference"], + ["g r", "references"], ["g i", "goto_implementation"], ["g t", "goto_window_top"], ["g c", "goto_window_center"], diff --git a/src/tui/editor.zig b/src/tui/editor.zig index e7364fe..01dec2a 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -2229,7 +2229,7 @@ pub const Editor = struct { return false; } - fn is_eol_right(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { + pub fn is_eol_right(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { const line_width = root.line_width(cursor.row, metrics) catch return true; if (cursor.col >= line_width) return true; @@ -2252,15 +2252,6 @@ pub const Editor = struct { return false; } - pub fn move_cursor_carriage_return(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void { - if (is_eol_right(root, cursor, metrics)) { - try move_cursor_right(root, cursor, metrics); - } else { - try move_cursor_down(root, cursor, metrics); - try move_cursor_begin(root, cursor, metrics); - } - } - pub fn move_cursor_left(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void { try cursor.move_left(root, metrics); } @@ -2317,7 +2308,7 @@ pub const Editor = struct { if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics); } - fn move_cursor_down(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void { + pub fn move_cursor_down(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void { cursor.move_down(root, metrics) catch |e| switch (e) { error.Stop => cursor.move_end(root, metrics), }; diff --git a/src/tui/mode/helix.zig b/src/tui/mode/helix.zig index 33abc5a..f4456bf 100644 --- a/src/tui/mode/helix.zig +++ b/src/tui/mode/helix.zig @@ -408,7 +408,6 @@ const cmds_ = struct { pub fn paste_clipboard_before(_: *void, ctx: Ctx) Result { try paste_helix(ctx, insert_before); } - pub const paste_clipboard_before_meta: Meta = .{ .description = "Paste from clipboard before selection" }; }; @@ -443,85 +442,75 @@ fn move_cursor_word_right_end_helix(root: Buffer.Root, cursor: *Cursor, metrics: try cursor.move_right(root, metrics); } -fn insert_before(editor: *Editor, root: Buffer.Root, cursel: *CurSel, s: []const u8, allocator: Allocator) !Buffer.Root { +fn insert_before(editor: *Editor, root: Buffer.Root, cursel: *CurSel, text: []const u8, allocator: Allocator) !Buffer.Root { var root_: Buffer.Root = root; const cursor: *Cursor = &cursel.cursor; cursel.check_selection(root, editor.metrics); - if (s[s.len - 1] == '\n') { - if (cursel.selection) |*sel_| { - sel_.*.normalize(); - cursor.move_to(root, sel_.*.begin.row, sel_.*.begin.col, editor.metrics) catch {}; - } else { + if (cursel.selection) |sel_| { + var sel = sel_; + sel.normalize(); + cursor.move_to(root, sel.begin.row, sel.begin.col, editor.metrics) catch {}; + + if (text[text.len - 1] == '\n') { cursor.move_begin(); } - } else { - if (cursel.selection) |*sel_| { - sel_.*.normalize(); - cursor.move_to(root, sel_.*.begin.row, sel_.*.begin.col, editor.metrics) catch {}; - } + } else if (text[text.len - 1] == '\n') { + cursor.move_begin(); } + cursel.disable_selection_normal(); const begin = cursel.cursor; - - cursor.row, cursor.col, root_ = try root_.insert_chars(cursor.row, cursor.col, s, allocator, editor.metrics); + cursor.row, cursor.col, root_ = try root_.insert_chars(cursor.row, cursor.col, text, allocator, editor.metrics); cursor.target = cursor.col; - editor.nudge_insert(.{ .begin = begin, .end = cursor.* }, cursel, s.len); cursel.selection = Selection{ .begin = begin, .end = cursor.* }; + editor.nudge_insert(.{ .begin = begin, .end = cursor.* }, cursel, text.len); return root_; } -fn insert_replace_selection(editor: *Editor, root: Buffer.Root, cursel: *CurSel, s: []const u8, allocator: Allocator) !Buffer.Root { +fn insert_replace_selection(editor: *Editor, root: Buffer.Root, cursel: *CurSel, text: []const u8, allocator: Allocator) !Buffer.Root { + // replaces the selection, if no selection, replaces the current + // character and sets the selection to the replacement text var root_: Buffer.Root = root; cursel.check_selection(root, editor.metrics); - if (cursel.selection) |_| { - root_ = try editor.delete_selection(root, cursel, allocator); - } else { - // Replace current character when no explicit selection - try Editor.with_selection_const(root, move_noop, cursel, editor.metrics); - root_ = try editor.delete_selection(root, cursel, allocator); + if (cursel.selection == null) { + // Select current character to replace it + Editor.with_selection_const(root, move_noop, cursel, editor.metrics) catch {}; } + root_ = editor.delete_selection(root, cursel, allocator) catch root; const cursor = &cursel.cursor; const begin = cursel.cursor; - - cursor.row, cursor.col, root_ = try root_.insert_chars(cursor.row, cursor.col, s, allocator, editor.metrics); + cursor.row, cursor.col, root_ = try root_.insert_chars(cursor.row, cursor.col, text, allocator, editor.metrics); cursor.target = cursor.col; - editor.nudge_insert(.{ .begin = begin, .end = cursor.* }, cursel, s.len); cursel.selection = Selection{ .begin = begin, .end = cursor.* }; + editor.nudge_insert(.{ .begin = begin, .end = cursor.* }, cursel, text.len); return root_; } -fn insert_after(editor: *Editor, root: Buffer.Root, cursel: *CurSel, s: []const u8, allocator: Allocator) !Buffer.Root { +fn insert_after(editor: *Editor, root: Buffer.Root, cursel: *CurSel, text: []const u8, allocator: Allocator) !Buffer.Root { var root_: Buffer.Root = root; const cursor = &cursel.cursor; cursel.check_selection(root, editor.metrics); - if (s[s.len - 1] == '\n') { - if (cursel.selection) |*sel_| { - sel_.*.normalize(); - if (sel_.*.end.row == sel_.*.begin.row or sel_.*.end.col != 0) { - cursel.disable_selection_normal(); - Editor.move_cursor_carriage_return(root, cursor, editor.metrics) catch {}; - } - } else { - cursel.disable_selection_normal(); - Editor.move_cursor_carriage_return(root, cursor, editor.metrics) catch {}; - } + if (text[text.len - 1] == '\n') { + move_cursor_carriage_return(root, cursel.*, cursor, editor.metrics) catch {}; } else { - if (cursel.selection) |*sel_| { - sel_.*.normalize(); - cursor.move_to(root, sel_.*.end.row, sel_.*.end.col, editor.metrics) catch {}; + if (cursel.selection) |sel_| { + var sel = sel_; + sel.normalize(); + cursor.move_to(root, sel.end.row, sel.end.col, editor.metrics) catch {}; } else { cursor.move_right(root_, editor.metrics) catch {}; } - cursel.disable_selection_normal(); } + + cursel.disable_selection_normal(); const begin = cursel.cursor; - cursor.row, cursor.col, root_ = try root_.insert_chars(cursor.row, cursor.col, s, allocator, editor.metrics); + cursor.row, cursor.col, root_ = try root_.insert_chars(cursor.row, cursor.col, text, allocator, editor.metrics); cursor.target = cursor.col; - editor.nudge_insert(.{ .begin = begin, .end = cursor.* }, cursel, s.len); cursel.selection = Selection{ .begin = begin, .end = cursor.* }; + editor.nudge_insert(.{ .begin = begin, .end = cursor.* }, cursel, text.len); return root_; } @@ -668,6 +657,7 @@ fn copy_internal_helix() command.Result { try text.appendSlice(editor.allocator, serial_separator); } try text.appendSlice(editor.allocator, copy_text); + editor.allocator.free(copy_text); } }; if (text.items.len > 0) { @@ -680,6 +670,26 @@ fn copy_internal_helix() command.Result { } } +fn move_cursor_carriage_return(root: Buffer.Root, cursel: CurSel, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void { + if (is_cursel_from_extend_line_below(cursel)) { + //The cursor is already beginning next line + return; + } + if (!Editor.is_eol_right(root, cursor, metrics)) { + try Editor.move_cursor_end(root, cursor, metrics); + } + try Editor.move_cursor_right(root, cursor, metrics); +} + +fn is_cursel_from_extend_line_below(cursel: CurSel) bool { + if (cursel.selection) |sel_| { + var sel = sel_; + sel.normalize(); + return sel.end.row != sel.begin.row and sel.end.col == 0; + } + return false; +} + const private = @This(); // exports for unittests pub const test_internal = struct {