From 5199dcdd27781897b4b4f9e9b124d8df83a8466b Mon Sep 17 00:00:00 2001 From: Levi Date: Tue, 8 Apr 2025 15:05:09 -0300 Subject: [PATCH] feat: Vim mode: till_char (#224) --- src/keybind/builtin/vim.json | 4 +++ src/tui/editor.zig | 67 ++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index 9aa765b..1733265 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -87,6 +87,8 @@ ["F", "move_to_char", "move_to_char_left"], ["f", "move_to_char", "move_to_char_right"], + ["T", "move_to_char", "move_till_char_left"], + ["t", "move_to_char", "move_till_char_right"], ["", ["move_down"], ["move_begin"]], ["", ["move_down"], ["move_begin"]], @@ -131,6 +133,8 @@ ["f", "move_to_char", "select_to_char_right"], ["F", "move_to_char", "select_to_char_left_vim"], + ["t", "move_to_char", "select_till_char_right"], + ["T", "move_to_char", "select_till_char_left_vim"], ["p", ["paste_internal_vim"], ["enter_mode", "normal"]], ["P", ["paste_internal_vim"], ["enter_mode", "normal"]], diff --git a/src/tui/editor.zig b/src/tui/editor.zig index d4e80ff..cd29e72 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -3103,6 +3103,42 @@ pub const Editor = struct { } } + fn move_cursor_till_char_left(root: Buffer.Root, cursor: *Cursor, ctx: Context, metrics: Buffer.Metrics) error{Stop}!void { + var egc: []const u8 = undefined; + if (!(ctx.args.match(.{tp.extract(&egc)}) catch return error.Stop)) + return error.Stop; + try move_cursor_left(root, cursor, metrics); + var prev = cursor.*; + try move_cursor_left(root, &prev, metrics); + while (true) { + const prev_egc, _, _ = root.egc_at(prev.row, prev.col, metrics) catch return error.Stop; + if (std.mem.eql(u8, prev_egc, egc)) + return; + if (is_eol_left(root, cursor, metrics)) + return; + move_cursor_left(root, cursor, metrics) catch return error.Stop; + move_cursor_left(root, &prev, metrics) catch return error.Stop; + } + } + + pub fn move_cursor_till_char_right(root: Buffer.Root, cursor: *Cursor, ctx: Context, metrics: Buffer.Metrics) error{Stop}!void { + var egc: []const u8 = undefined; + if (!(ctx.args.match(.{tp.extract(&egc)}) catch return error.Stop)) + return error.Stop; + try move_cursor_right(root, cursor, metrics); + var next = cursor.*; + try move_cursor_right(root, &next, metrics); + while (true) { + const next_egc, _, _ = root.egc_at(next.row, next.col, metrics) catch return error.Stop; + if (std.mem.eql(u8, next_egc, egc)) + return; + if (is_eol_right(root, cursor, metrics)) + return; + move_cursor_right(root, cursor, metrics) catch return error.Stop; + move_cursor_right(root, &next, metrics) catch return error.Stop; + } + } + pub fn move_to_char_left(self: *Self, ctx: Context) Result { const root = try self.buf_root(); self.with_cursors_const_arg(root, move_cursor_to_char_left, ctx) catch {}; @@ -3117,6 +3153,20 @@ pub const Editor = struct { } pub const move_to_char_right_meta: Meta = .{ .arguments = &.{.integer} }; + pub fn move_till_char_left(self: *Self, ctx: Context) Result { + const root = try self.buf_root(); + self.with_cursors_const_arg(root, move_cursor_till_char_left, ctx) catch {}; + self.clamp(); + } + pub const move_till_char_left_meta: Meta = .{ .arguments = &.{.integer} }; + + pub fn move_till_char_right(self: *Self, ctx: Context) Result { + const root = try self.buf_root(); + self.with_cursors_const_arg(root, move_cursor_till_char_right, ctx) catch {}; + self.clamp(); + } + pub const move_till_char_right_meta: Meta = .{ .arguments = &.{.integer} }; + pub fn move_or_select_to_char_left(self: *Self, ctx: Context) Result { const selected = if (self.get_primary().selection) |_| true else false; if (selected) try self.select_to_char_left(ctx) else try self.move_to_char_left(ctx); @@ -3771,6 +3821,16 @@ pub const Editor = struct { } pub const select_to_char_left_vim_meta: Meta = .{ .arguments = &.{.integer} }; + pub fn select_till_char_left_vim(self: *Self, ctx: Context) Result { + const root = try self.buf_root(); + for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| { + if (cursel.selection) |*sel| try sel.begin.move_right(root, self.metrics); + }; + self.with_selections_const_arg(root, move_cursor_till_char_left, ctx) catch {}; + self.clamp(); + } + pub const select_till_char_left_vim_meta: Meta = .{ .arguments = &.{.integer} }; + pub fn select_to_char_right(self: *Self, ctx: Context) Result { const root = try self.buf_root(); self.with_selections_const_arg(root, move_cursor_to_char_right, ctx) catch {}; @@ -3778,6 +3838,13 @@ pub const Editor = struct { } pub const select_to_char_right_meta: Meta = .{ .arguments = &.{.integer} }; + pub fn select_till_char_right(self: *Self, ctx: Context) Result { + const root = try self.buf_root(); + self.with_selections_const_arg(root, move_cursor_till_char_right, ctx) catch {}; + self.clamp(); + } + pub const select_till_char_right_meta: Meta = .{ .arguments = &.{.integer} }; + pub fn select_begin(self: *Self, ctx: Context) Result { const root = try self.buf_root(); try self.with_selections_const_repeat(root, move_cursor_begin, ctx);