From 715bb6bbcf7501e18fcbd3c7b9d76eac02072d56 Mon Sep 17 00:00:00 2001 From: lulvz Date: Tue, 11 Feb 2025 15:19:04 +0000 Subject: [PATCH 1/6] feat(vim): Add VISUAL line mode to vim mode, fix vertical movement behaviour --- src/keybind/builtin/vim.json | 68 ++++++++++++++++++++++++++--- src/tui/editor.zig | 84 ++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 7 deletions(-) diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index 3291471..261b240 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -20,8 +20,8 @@ ["s", ["cut_forward_internal"], ["enter_mode", "insert"]], ["u", "undo"], - ["j", "move_down"], - ["k", "move_up"], + ["j", "move_down_vim"], + ["k", "move_up_vim"], ["l", "move_right_vim"], ["h", "move_left_vim"], ["", "move_right_vim"], @@ -33,15 +33,20 @@ ["o", ["smart_insert_line_after"], ["enter_mode", "insert"]], ["O", ["smart_insert_line_before"], ["enter_mode", "insert"]], + ["", "indent"], + ["", "unindent"], + ["v", "enter_mode", "visual"], - ["V", ["move_begin"], ["enter_mode", "visual"], ["select_end"]], + ["V", ["enter_mode", "visual line"], ["select_line_vim"]], ["n", "goto_next_match"], ["0", "move_begin"], ["^", "smart_move_begin"], ["$", "move_end"], [":", "open_command_palette"], + ["p", "paste_internal_vim"], + ["P", "paste_internal_vim"], ["gd", "goto_definition"], ["gi", "goto_implementation"], @@ -59,8 +64,11 @@ ["yy", ["copy_line_internal_vim"], ["cancel"]], - ["", "move_scroll_page_up"], - ["", "move_scroll_page_down"], + ["", "move_scroll_half_page_up_vim"], + ["", "move_scroll_half_page_down_vim"], + + ["zz", "scroll_view_center"], + ["u", "undo"], ["", "redo"], ["", "jump_back"], @@ -83,12 +91,26 @@ "cursor": "block", "selection": "normal", "press": [ - ["", "enter_mode", "normal"], + ["", ["cancel"], ["enter_mode", "normal"]], ["k", "select_up"], ["j", "select_down"], ["h", "select_left"], ["l", "select_right"], + ["0", "move_begin"], + ["^", "smart_move_begin"], + ["$", "move_end"], + + ["p", ["paste_internal_vim"], ["enter_mode", "normal"]], + ["P", ["paste_internal_vim"], ["enter_mode", "normal"]], + + ["", "move_scroll_half_page_up_vim"], + ["", "move_scroll_half_page_down_vim"], + + ["zz", "scroll_view_center"], + ["", "indent"], + ["", "unindent"], + ["y", ["copy_internal_vim"], ["cancel"], ["enter_mode", "normal"]], ["x", ["cut_forward_internal"], ["cancel"], ["enter_mode", "normal"]], @@ -96,6 +118,38 @@ ["s", ["cut_forward_internal"], ["cancel"], ["enter_mode", "insert"]] ] }, + "visual line": { + "syntax": "vim", + "on_match_failure": "ignore", + "name": "VISUAL LINE", + "line_numbers": "relative", + "cursor": "block", + "selection": "normal", + "press": [ + ["", ["cancel"], ["enter_mode", "normal"]], + ["k", "select_up"], + ["j", "select_down"], + + ["0", "move_begin"], + ["^", "smart_move_begin"], + ["$", "move_end"], + + ["p", ["paste_internal_vim"], ["enter_mode", "normal"]], + ["P", ["paste_internal_vim"], ["enter_mode", "normal"]], + + ["", "move_scroll_half_page_up_vim"], + ["", "move_scroll_half_page_down_vim"], + + ["", "indent"], + ["", "unindent"], + + ["y", ["copy_line_internal_vim"], ["cancel"], ["enter_mode", "normal"]], + + ["x", ["cut_internal_vim"], ["cancel"], ["enter_mode", "normal"]], + ["d", ["cut_internal_vim"], ["cancel"], ["enter_mode", "normal"]], + ["s", ["cut_internal_vim"], ["cancel"], ["enter_mode", "insert"]] + ] + }, "insert": { "syntax": "vim", "name": "INSERT", @@ -103,7 +157,7 @@ "cursor": "beam", "press": [ ["jk", "enter_mode", "normal"], - ["", "enter_mode", "normal"], + ["", ["move_left_vim"], ["enter_mode", "normal"]], ["", "delete_forward"], ["", "delete_backward"], ["", "smart_insert_line"], diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 3d4780e..02db304 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -2039,6 +2039,14 @@ pub const Editor = struct { return false; } + fn is_eol_vim(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { + const line_width = root.line_width(cursor.row, metrics) catch return true; + if (line_width == 0) return true; + if (cursor.col == line_width) + return true; + return false; + } + fn move_cursor_left(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void { try cursor.move_left(root, metrics); } @@ -2084,10 +2092,20 @@ pub const Editor = struct { try cursor.move_up(root, metrics); } + fn move_cursor_up_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void { + try cursor.move_up(root, metrics); + 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 { try cursor.move_down(root, metrics); } + fn move_cursor_down_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void { + try cursor.move_down(root, metrics); + if(is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics); + } + fn move_cursor_buffer_begin(_: Buffer.Root, cursor: *Cursor, _: Buffer.Metrics) !void { cursor.move_buffer_begin(); } @@ -2108,10 +2126,20 @@ pub const Editor = struct { cursor.move_half_page_up(root, view, metrics); } + fn move_cursor_half_page_up_vim(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void { + cursor.move_half_page_up(root, view, metrics); + if(is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics); + } + fn move_cursor_half_page_down(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void { cursor.move_half_page_down(root, view, metrics); } + fn move_cursor_half_page_down_vim(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void { + cursor.move_half_page_down(root, view, metrics); + if(is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics); + } + pub fn primary_click(self: *Self, y: c_int, x: c_int) !void { const root = self.buf_root() catch return; if (self.fast_scroll) { @@ -2948,6 +2976,13 @@ pub const Editor = struct { } pub const move_up_meta = .{ .description = "Move cursor up" }; + pub fn move_up_vim(self: *Self, _: Context) Result { + const root = try self.buf_root(); + self.with_cursors_const(root, move_cursor_up_vim) catch {}; + self.clamp(); + } + pub const move_up_vim_meta = .{ .description = "Move cursor up (vim)" }; + pub fn add_cursor_up(self: *Self, _: Context) Result { try self.push_cursor(); const primary = self.get_primary(); @@ -2964,6 +2999,13 @@ pub const Editor = struct { } pub const move_down_meta = .{ .description = "Move cursor down" }; + pub fn move_down_vim(self: *Self, _: Context) Result { + const root = try self.buf_root(); + self.with_cursors_const(root, move_cursor_down_vim) catch {}; + self.clamp(); + } + pub const move_down_vim_meta = .{ .description = "Move cursor down (vim)" }; + pub fn add_cursor_down(self: *Self, _: Context) Result { try self.push_cursor(); const primary = self.get_primary(); @@ -3314,6 +3356,18 @@ pub const Editor = struct { } pub const move_scroll_half_page_up_meta = .{ .description = "Move and scroll half a page up" }; + pub fn move_scroll_half_page_up_vim(self: *Self, _: Context) Result { + if (self.screen_cursor(&self.get_primary().cursor)) |cursor| { + const root = try self.buf_root(); + self.with_cursors_and_view_const(root, move_cursor_half_page_up_vim, &self.view) catch {}; + const new_cursor_row = self.get_primary().cursor.row; + self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row); + } else { + return self.move_half_page_up(.{}); + } + } + pub const move_scroll_half_page_up_vim_meta = .{ .description = "Move and scroll half a page up (vim)" }; + pub fn move_scroll_half_page_down(self: *Self, _: Context) Result { if (self.screen_cursor(&self.get_primary().cursor)) |cursor| { const root = try self.buf_root(); @@ -3326,6 +3380,18 @@ pub const Editor = struct { } pub const move_scroll_half_page_down_meta = .{ .description = "Move and scroll half a page down" }; + pub fn move_scroll_half_page_down_vim(self: *Self, _: Context) Result { + if (self.screen_cursor(&self.get_primary().cursor)) |cursor| { + const root = try self.buf_root(); + self.with_cursors_and_view_const(root, move_cursor_half_page_down_vim, &self.view) catch {}; + const new_cursor_row = self.get_primary().cursor.row; + self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row); + } else { + return self.move_half_page_down(.{}); + } + } + pub const move_scroll_half_page_down_vim_meta = .{ .description = "Move and scroll half a page down (vim)" }; + pub fn smart_move_begin(self: *Self, _: Context) Result { const root = try self.buf_root(); try self.with_cursors_const(root, smart_move_cursor_begin); @@ -3406,6 +3472,16 @@ pub const Editor = struct { } pub const cancel_meta = .{ .description = "Cancel current action" }; + pub fn select_line_vim(self: *Self, _: Context) Result { + const primary = self.get_primary(); + const root = self.buf_root() catch return; + primary.disable_selection(root, self.metrics); + self.selection_mode = .line; + try self.select_line_around_cursor(primary); + self.clamp(); + } + pub const select_line_vim_meta = .{ .description = "Select the line around the cursor (vim)" }; + pub fn select_up(self: *Self, _: Context) Result { const root = try self.buf_root(); try self.with_selections_const(root, move_cursor_up); @@ -3600,6 +3676,14 @@ pub const Editor = struct { cursel.cursor = sel.end; } + fn select_line_around_cursor(self: *Self, cursel: *CurSel) !void { + const root = try self.buf_root(); + const sel = try cursel.enable_selection(root, self.metrics); + sel.normalize(); + try move_cursor_begin(root, &sel.begin, self.metrics); + try move_cursor_end(root, &sel.end, self.metrics); + } + fn selection_reverse(_: Buffer.Root, cursel: *CurSel) !void { if (cursel.selection) |*sel| { sel.reverse(); From b516709594003a7654c7dcf147f95c861e80bdee Mon Sep 17 00:00:00 2001 From: lulvz Date: Tue, 11 Feb 2025 15:44:15 +0000 Subject: [PATCH 2/6] feat(vim): enhance cut and delete commands in vim mode (still missing cut functionality in delete to end) --- src/keybind/builtin/vim.json | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index 261b240..458a6a6 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -62,6 +62,12 @@ ["dd", "cut_internal_vim"], ["\"_dd", "delete_line"], + ["cc", ["delete_line"], ["enter_mode", "insert"]], + ["C", ["delete_to_end"], ["enter_mode", "insert"]], + ["D", "delete_to_end"], + ["cw", ["cut_word_right_vim"], ["enter_mode", "insert"]], + ["cb", ["cut_word_left_vim"], ["enter_mode", "insert"]], + ["yy", ["copy_line_internal_vim"], ["cancel"]], ["", "move_scroll_half_page_up_vim"], @@ -115,7 +121,11 @@ ["x", ["cut_forward_internal"], ["cancel"], ["enter_mode", "normal"]], ["d", ["cut_forward_internal"], ["cancel"], ["enter_mode", "normal"]], - ["s", ["cut_forward_internal"], ["cancel"], ["enter_mode", "insert"]] + ["s", ["cut_forward_internal"], ["cancel"], ["enter_mode", "insert"]], + + ["c", ["cut_forward_internal"], ["cancel"], ["enter_mode", "insert"]], + ["C", ["delete_to_end"], ["enter_mode", "insert"]], + ["D", "delete_to_end"] ] }, "visual line": { @@ -147,7 +157,11 @@ ["x", ["cut_internal_vim"], ["cancel"], ["enter_mode", "normal"]], ["d", ["cut_internal_vim"], ["cancel"], ["enter_mode", "normal"]], - ["s", ["cut_internal_vim"], ["cancel"], ["enter_mode", "insert"]] + ["s", ["cut_internal_vim"], ["cancel"], ["enter_mode", "insert"]], + + ["c", ["cut_forward_internal"], ["cancel"], ["enter_mode", "insert"]], + ["C", ["delete_to_end"], ["enter_mode", "insert"]], + ["D", "delete_to_end"] ] }, "insert": { From 0ea63accd952c0d68d7532fe339bed18e42ff9ce Mon Sep 17 00:00:00 2001 From: lulvz Date: Tue, 11 Feb 2025 16:13:39 +0000 Subject: [PATCH 3/6] feat(vim): implement cut to end of line functionality in vim mode --- src/keybind/builtin/vim.json | 2 +- src/tui/editor.zig | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index 458a6a6..54c1a0e 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -62,7 +62,7 @@ ["dd", "cut_internal_vim"], ["\"_dd", "delete_line"], - ["cc", ["delete_line"], ["enter_mode", "insert"]], + ["cc", ["cut_internal_vim"], ["enter_mode", "insert"]], ["C", ["delete_to_end"], ["enter_mode", "insert"]], ["D", "delete_to_end"], ["cw", ["cut_word_right_vim"], ["enter_mode", "insert"]], diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 02db304..4f42bd2 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -2088,6 +2088,10 @@ pub const Editor = struct { cursor.move_end(root, metrics); } + fn move_cursor_end_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void { + move_cursor_right_until(root, cursor, is_eol_vim, metrics); + } + fn move_cursor_up(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void { try cursor.move_up(root, metrics); } @@ -2776,6 +2780,15 @@ pub const Editor = struct { } pub const delete_to_end_meta = .{ .description = "Delete to end of line" }; + pub fn cut_to_end_vim(self: *Self, _: Context) Result { + const b = try self.buf_for_update(); + const text, const root = try self.cut_to(move_cursor_end_vim, b.root); + self.set_clipboard_internal(text); + try self.update_buf(root); + self.clamp(); + } + pub const cut_to_end_vim_meta = .{ .description = "Cut to end of line (vim)" }; + pub fn join_next_line(self: *Self, _: Context) Result { const b = try self.buf_for_update(); try self.with_cursors_const(b.root, move_cursor_end); From e443e8397bbf0bb5b26ed91336c8ed7202b67961 Mon Sep 17 00:00:00 2001 From: lulvz Date: Wed, 12 Feb 2025 21:38:27 +0000 Subject: [PATCH 4/6] feat(vim): Add word movement for visual mode, and complete vim mode cut to end of line --- src/keybind/builtin/vim.json | 24 +++++++++++++++--------- src/tui/editor.zig | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index b6c801e..2647a2f 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -56,15 +56,15 @@ ["gD", "goto_declaration"], ["G", "move_buffer_end"], - ["d$", "delete_to_end"], + ["d$", "cut_to_end_vim"], ["dw", "cut_word_right_vim"], ["db", "cut_word_left_vim"], ["dd", "cut_internal_vim"], ["\"_dd", "delete_line"], ["cc", ["cut_internal_vim"], ["enter_mode", "insert"]], - ["C", ["delete_to_end"], ["enter_mode", "insert"]], - ["D", "delete_to_end"], + ["C", ["cut_to_end_vim"], ["enter_mode", "insert"]], + ["D", "cut_to_end_vim"], ["cw", ["cut_word_right_vim"], ["enter_mode", "insert"]], ["cb", ["cut_word_left_vim"], ["enter_mode", "insert"]], @@ -103,6 +103,12 @@ ["h", "select_left"], ["l", "select_right"], + ["b", "select_word_left_vim"], + ["w", "select_word_right_vim"], + ["W", "select_word_right"], + ["B", "select_word_left"], + ["e", "select_word_right_end_vim"], + ["0", "move_begin"], ["^", "smart_move_begin"], ["$", "move_end"], @@ -124,8 +130,8 @@ ["s", ["cut_forward_internal"], ["cancel"], ["enter_mode", "insert"]], ["c", ["cut_forward_internal"], ["cancel"], ["enter_mode", "insert"]], - ["C", ["delete_to_end"], ["enter_mode", "insert"]], - ["D", "delete_to_end"] + ["C", ["cut_to_end_vim"], ["enter_mode", "insert"]], + ["D", "cut_to_end_vim"] ] }, "visual line": { @@ -160,8 +166,8 @@ ["s", ["cut_internal_vim"], ["cancel"], ["enter_mode", "insert"]], ["c", ["cut_forward_internal"], ["cancel"], ["enter_mode", "insert"]], - ["C", ["delete_to_end"], ["enter_mode", "insert"]], - ["D", "delete_to_end"] + ["C", ["cut_to_end_vim"], ["enter_mode", "insert"]], + ["D", "cut_to_end_vim"] ] }, "insert": { @@ -170,8 +176,8 @@ "line_numbers": "absolute", "cursor": "beam", "press": [ - - ["", "enter_mode", "normal"], + ["jk", "enter_mode", "normal"], + ["", ["move_left_vim"], ["enter_mode", "normal"]], ["", "delete_forward"], ["", "delete_backward"], ["", "smart_insert_line"], diff --git a/src/tui/editor.zig b/src/tui/editor.zig index d3ca4a2..507bb93 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -3536,6 +3536,13 @@ pub const Editor = struct { } pub const select_word_left_meta = .{ .description = "Select left by word" }; + pub fn select_word_left_vim(self: *Self, _: Context) Result { + const root = try self.buf_root(); + try self.with_selections_const(root, move_cursor_word_left_vim); + self.clamp(); + } + pub const select_word_left_vim_meta = .{ .description = "Select left by word (vim)" }; + pub fn select_word_right(self: *Self, _: Context) Result { const root = try self.buf_root(); try self.with_selections_const(root, move_cursor_word_right); @@ -3543,6 +3550,20 @@ pub const Editor = struct { } pub const select_word_right_meta = .{ .description = "Select right by word" }; + pub fn select_word_right_vim(self: *Self, _: Context) Result { + const root = try self.buf_root(); + try self.with_selections_const(root, move_cursor_word_right_vim); + self.clamp(); + } + pub const select_word_right_vim_meta = .{ .description = "Select right by word (vim)" }; + + pub fn select_word_right_end_vim(self: *Self, _: Context) Result { + const root = try self.buf_root(); + try self.with_selections_const(root, move_cursor_word_right_end_vim); + self.clamp(); + } + pub const select_word_right_end_vim_meta = .{ .description = "Select right by end of word (vim)" }; + pub fn select_word_begin(self: *Self, _: Context) Result { const root = try self.buf_root(); try self.with_selections_const(root, move_cursor_word_begin); From 69e1513441274ee7c4c696c81ed3b01a574132b5 Mon Sep 17 00:00:00 2001 From: lulvz Date: Wed, 12 Feb 2025 21:52:07 +0000 Subject: [PATCH 5/6] fix(vim): Removed unnecessary cancel commands in vim mode cut functions --- src/keybind/builtin/vim.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index 2647a2f..144f7ab 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -125,11 +125,11 @@ ["y", ["copy_internal_vim"], ["cancel"], ["enter_mode", "normal"]], - ["x", ["cut_forward_internal"], ["cancel"], ["enter_mode", "normal"]], - ["d", ["cut_forward_internal"], ["cancel"], ["enter_mode", "normal"]], - ["s", ["cut_forward_internal"], ["cancel"], ["enter_mode", "insert"]], + ["x", ["cut_forward_internal"], ["enter_mode", "normal"]], + ["d", ["cut_forward_internal"], ["enter_mode", "normal"]], + ["s", ["cut_forward_internal"], ["enter_mode", "insert"]], - ["c", ["cut_forward_internal"], ["cancel"], ["enter_mode", "insert"]], + ["c", ["cut_forward_internal"], ["enter_mode", "insert"]], ["C", ["cut_to_end_vim"], ["enter_mode", "insert"]], ["D", "cut_to_end_vim"] ] @@ -161,11 +161,11 @@ ["y", ["copy_line_internal_vim"], ["cancel"], ["enter_mode", "normal"]], - ["x", ["cut_internal_vim"], ["cancel"], ["enter_mode", "normal"]], - ["d", ["cut_internal_vim"], ["cancel"], ["enter_mode", "normal"]], - ["s", ["cut_internal_vim"], ["cancel"], ["enter_mode", "insert"]], + ["x", ["cut_internal_vim"], ["enter_mode", "normal"]], + ["d", ["cut_internal_vim"], ["enter_mode", "normal"]], + ["s", ["cut_internal_vim"], ["enter_mode", "insert"]], - ["c", ["cut_forward_internal"], ["cancel"], ["enter_mode", "insert"]], + ["c", ["cut_internal_vim"], ["enter_mode", "insert"]], ["C", ["cut_to_end_vim"], ["enter_mode", "insert"]], ["D", "cut_to_end_vim"] ] From 1b016774c7929b29729517b0ad240ceae1eb9b85 Mon Sep 17 00:00:00 2001 From: lulvz Date: Thu, 13 Feb 2025 13:38:04 +0000 Subject: [PATCH 6/6] fix(vim): Remove 'jk' keybinding again and make select_line_vim work on multiple cursors --- src/keybind/builtin/vim.json | 1 - src/tui/editor.zig | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index 144f7ab..a3ba41f 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -176,7 +176,6 @@ "line_numbers": "absolute", "cursor": "beam", "press": [ - ["jk", "enter_mode", "normal"], ["", ["move_left_vim"], ["enter_mode", "normal"]], ["", "delete_forward"], ["", "delete_backward"], diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 507bb93..6df6fd0 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -2032,7 +2032,7 @@ pub const Editor = struct { fn is_eol_vim(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { const line_width = root.line_width(cursor.row, metrics) catch return true; if (line_width == 0) return true; - if (cursor.col == line_width) + if (cursor.col >= line_width) return true; return false; } @@ -3476,11 +3476,11 @@ pub const Editor = struct { pub const cancel_meta = .{ .description = "Cancel current action" }; pub fn select_line_vim(self: *Self, _: Context) Result { - const primary = self.get_primary(); - const root = self.buf_root() catch return; - primary.disable_selection(root, self.metrics); self.selection_mode = .line; - try self.select_line_around_cursor(primary); + for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| + try self.select_line_around_cursor(cursel); + self.collapse_cursors(); + self.clamp(); } pub const select_line_vim_meta = .{ .description = "Select the line around the cursor (vim)" };