From 04c1ece3a8e7bc70f09c7e814d346df54c28919e Mon Sep 17 00:00:00 2001 From: jmcaine Date: Wed, 29 Oct 2025 22:01:11 -0700 Subject: [PATCH 1/9] feat: delete_line implemented --- src/tui/editor.zig | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index ca0ed0f..b3892d3 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -2406,7 +2406,7 @@ pub const Editor = struct { primary.disable_selection(root, self.metrics); self.selection_mode = .line; primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return; - try self.select_line_at_cursor(primary); + try self.select_line_at_cursor(root, primary, false); self.selection_drag_initial = primary.selection; self.clamp_mouse(); } @@ -3031,6 +3031,16 @@ pub const Editor = struct { } pub const delete_to_end_meta: Meta = .{ .description = "Delete to end of line" }; + pub fn delete_line(self: *Self, _: Context) Result { + const b = try self.buf_for_update(); + const primary = self.get_primary(); + try self.select_line_at_cursor(b.root, primary, true); + const root = try self.delete_selection(b.root, primary, b.allocator); + try self.update_buf(root); + self.clamp(); + } + pub const delete_line_meta: Meta = .{ .description = "Delete current line" }; + pub fn cut_to_end_vim(self: *Self, _: Context) Result { const b = try self.buf_for_update(); const root = try self.cut_to(move_cursor_end_vim, b.root); @@ -4102,12 +4112,14 @@ pub const Editor = struct { return sel; } - fn select_line_at_cursor(self: *Self, cursel: *CurSel) !void { - const root = try self.buf_root(); + fn select_line_at_cursor(self: *Self, root: Buffer.Root, cursel: *CurSel, include_newline: bool) !void { const sel = try cursel.enable_selection(root, self.metrics); sel.normalize(); try move_cursor_begin(root, &sel.begin, self.metrics); move_cursor_end(root, &sel.end, self.metrics) catch {}; + if (include_newline) { + move_cursor_right(root, &sel.end, self.metrics) catch {}; // catch{} because may be impossible to get eol (e.g., we're at eof) + } cursel.cursor = sel.end; } From 23ea7333a7a88e13dee7c0c27b94afe7af3016cc Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Thu, 30 Oct 2025 09:36:10 +0100 Subject: [PATCH 2/9] refactor: remove obsolete vim mode delete_line placeholder --- src/tui/mode/vim.zig | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/tui/mode/vim.zig b/src/tui/mode/vim.zig index 9cefd76..38eacbe 100644 --- a/src/tui/mode/vim.zig +++ b/src/tui/mode/vim.zig @@ -140,19 +140,4 @@ const cmds_ = struct { } pub const copy_line_meta: Meta = .{ .description = "Copies the current line" }; - - pub fn delete_line(self: *void, ctx: Ctx) Result { - _ = self; // autofix - _ = ctx; // autofix - //TODO - return undefined; - //try self.move_begin(ctx); - //const b = try self.buf_for_update(); - //var root = try self.delete_to(move_cursor_end, b.root, b.allocator); - //root = try self.delete_to(move_cursor_right, b.root, b.allocator); - //try self.delete_forward(ctx); - //try self.update_buf(root); - //self.clamp(); - } - pub const delete_line_meta: Meta = .{ .description = "Delete the current line without copying" }; }; From 62873353b8c009cefd42c67237a145a1bd0f1a08 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Thu, 30 Oct 2025 09:38:28 +0100 Subject: [PATCH 3/9] refactor: use an enum to select select_line_at_cursor mode --- src/tui/editor.zig | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index b3892d3..ec77cac 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -2406,7 +2406,7 @@ pub const Editor = struct { primary.disable_selection(root, self.metrics); self.selection_mode = .line; primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return; - try self.select_line_at_cursor(root, primary, false); + try self.select_line_at_cursor(root, primary, .exclude_eol); self.selection_drag_initial = primary.selection; self.clamp_mouse(); } @@ -3034,7 +3034,7 @@ pub const Editor = struct { pub fn delete_line(self: *Self, _: Context) Result { const b = try self.buf_for_update(); const primary = self.get_primary(); - try self.select_line_at_cursor(b.root, primary, true); + try self.select_line_at_cursor(b.root, primary, .include_eol); const root = try self.delete_selection(b.root, primary, b.allocator); try self.update_buf(root); self.clamp(); @@ -4112,13 +4112,14 @@ pub const Editor = struct { return sel; } - fn select_line_at_cursor(self: *Self, root: Buffer.Root, cursel: *CurSel, include_newline: bool) !void { + fn select_line_at_cursor(self: *Self, root: Buffer.Root, cursel: *CurSel, mode: enum { include_eol, exclude_eol }) !void { const sel = try cursel.enable_selection(root, self.metrics); sel.normalize(); try move_cursor_begin(root, &sel.begin, self.metrics); move_cursor_end(root, &sel.end, self.metrics) catch {}; - if (include_newline) { - move_cursor_right(root, &sel.end, self.metrics) catch {}; // catch{} because may be impossible to get eol (e.g., we're at eof) + switch (mode) { + .include_eol => move_cursor_right(root, &sel.end, self.metrics) catch {}, // catch{} because may be impossible to get eol (e.g., we're at eof) + else => {}, } cursel.cursor = sel.end; } From dff0b233d1a05c84e3457854608abb36e6a7ae0c Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Thu, 30 Oct 2025 11:08:36 +0100 Subject: [PATCH 4/9] feat: add flow mode keybinding for delete_line --- src/keybind/builtin/flow.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keybind/builtin/flow.json b/src/keybind/builtin/flow.json index 9e0c3cd..4edfb38 100644 --- a/src/keybind/builtin/flow.json +++ b/src/keybind/builtin/flow.json @@ -201,6 +201,7 @@ ["shift+kp_page_down", "select_page_down"], ["shift+enter", "smart_insert_line_before"], ["shift+backspace", "delete_backward"], + ["ctrl+shift+k", "delete_line"], ["shift+tab", "unindent"], ["f2", "rename_symbol"], ["f3", "goto_next_match"], From c27795bc958c35e472212afddff8264c474d0f2f Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Thu, 30 Oct 2025 11:16:07 +0100 Subject: [PATCH 5/9] feat: add multi cursor support to delete_line --- src/tui/editor.zig | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index ec77cac..f8e87bc 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -3033,9 +3033,11 @@ pub const Editor = struct { pub fn delete_line(self: *Self, _: Context) Result { const b = try self.buf_for_update(); - const primary = self.get_primary(); - try self.select_line_at_cursor(b.root, primary, .include_eol); - const root = try self.delete_selection(b.root, primary, b.allocator); + var root = b.root; + for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| { + try self.select_line_at_cursor(root, cursel, .include_eol); + root = try self.delete_selection(root, cursel, b.allocator); + }; try self.update_buf(root); self.clamp(); } From 772e2e7d298dfc8c1c7e5549ea77de3d54a6a101 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Thu, 30 Oct 2025 11:16:41 +0100 Subject: [PATCH 6/9] refactor: use select_line_at_cursor to simplify cut command --- src/tui/editor.zig | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index f8e87bc..b6f3087 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -2698,19 +2698,8 @@ pub const Editor = struct { const primary = self.get_primary(); const b = self.buf_for_update() catch return; var root = b.root; - if (self.cursels.items.len == 1) - if (primary.selection) |_| {} else { - const sel = primary.enable_selection(root, self.metrics) catch return; - try move_cursor_begin(root, &sel.begin, self.metrics); - move_cursor_end(root, &sel.end, self.metrics) catch |e| switch (e) { - error.Stop => {}, - else => return e, - }; - move_cursor_right(root, &sel.end, self.metrics) catch |e| switch (e) { - error.Stop => {}, - else => return e, - }; - }; + if (self.cursels.items.len == 1 and primary.selection == null) + try self.select_line_at_cursor(root, primary, .include_eol); var count: usize = 0; for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| { count += 1; From e42f3ff3a581936d746684490a8c1cc8d06a82b5 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Thu, 30 Oct 2025 11:19:58 +0100 Subject: [PATCH 7/9] refactor: use select_line_at_cursor to simplify cut_internal_vim --- src/tui/editor.zig | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index b6f3087..feb5ffe 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -2678,13 +2678,8 @@ pub const Editor = struct { const primary = self.get_primary(); const b = self.buf_for_update() catch return; var root = b.root; - if (self.cursels.items.len == 1) - if (primary.selection) |_| {} else { - const sel = primary.enable_selection(root, self.metrics) catch return; - try move_cursor_begin(root, &sel.begin, self.metrics); - try move_cursor_end(root, &sel.end, self.metrics); - try move_cursor_right(root, &sel.end, self.metrics); - }; + if (self.cursels.items.len == 1 and primary.selection == null) + try self.select_line_at_cursor(root, primary, .include_eol); for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| { const cut_text, root = try self.cut_selection(root, cursel, tui.clipboard_allocator()); tui.clipboard_add_chunk(cut_text); From 4087e0a3f95b1ed50d93eb4c080b65dbdffe1319 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Thu, 30 Oct 2025 11:38:50 +0100 Subject: [PATCH 8/9] fix: preserve cursor column and target in delete_line This is the expected behaviour (for me at least) and makes delete_line significantly more useful than plain `cut` with no selection. closes #342 --- src/tui/editor.zig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index feb5ffe..90d1d67 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -3019,8 +3019,13 @@ pub const Editor = struct { const b = try self.buf_for_update(); var root = b.root; for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| { + const col = cursel.cursor.col; + const target = cursel.cursor.target; try self.select_line_at_cursor(root, cursel, .include_eol); root = try self.delete_selection(root, cursel, b.allocator); + cursel.cursor.col = col; + cursel.cursor.target = target; + cursel.cursor.clamp_to_buffer(root, self.metrics); }; try self.update_buf(root); self.clamp(); From fc8642768d5b61dd414b8252ae3d9b5bae5e9b50 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Thu, 30 Oct 2025 12:45:17 +0100 Subject: [PATCH 9/9] refactor: merge select_line_around_cursor into select_line_at_cursor --- src/tui/editor.zig | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 90d1d67..948ac8b 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -3861,9 +3861,10 @@ pub const Editor = struct { pub const enable_selection_meta: Meta = .{ .description = "Enable selection" }; pub fn select_line_vim(self: *Self, _: Context) Result { + const root = try self.buf_root(); self.selection_mode = .line; for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| - try self.select_line_around_cursor(cursel); + try self.select_line_at_cursor(root, cursel, .hold_cursor); self.collapse_cursors(); self.clamp(); @@ -4103,7 +4104,7 @@ pub const Editor = struct { return sel; } - fn select_line_at_cursor(self: *Self, root: Buffer.Root, cursel: *CurSel, mode: enum { include_eol, exclude_eol }) !void { + fn select_line_at_cursor(self: *Self, root: Buffer.Root, cursel: *CurSel, mode: enum { include_eol, exclude_eol, hold_cursor }) !void { const sel = try cursel.enable_selection(root, self.metrics); sel.normalize(); try move_cursor_begin(root, &sel.begin, self.metrics); @@ -4112,15 +4113,10 @@ pub const Editor = struct { .include_eol => move_cursor_right(root, &sel.end, self.metrics) catch {}, // catch{} because may be impossible to get eol (e.g., we're at eof) else => {}, } - cursel.cursor = sel.end; - } - - pub 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); + switch (mode) { + .hold_cursor => {}, + else => cursel.cursor = sel.end, + } } fn selection_reverse(_: Buffer.Root, cursel: *CurSel) !void {