feat: [vim] Add word textobject actions
This commit is contained in:
parent
a8437d6139
commit
ba840b72e0
3 changed files with 149 additions and 3 deletions
|
|
@ -81,14 +81,23 @@
|
|||
["dgg", "cut_buffer_begin"],
|
||||
["\"_dd", "delete_line"],
|
||||
|
||||
["diw", "cut_inside_word"],
|
||||
["daw", "cut_around_word"],
|
||||
|
||||
["cc", ["enter_mode", "insert"], ["cut_internal_vim"]],
|
||||
["C", ["enter_mode", "insert"], ["cut_to_end_vim"]],
|
||||
["D", "cut_to_end_vim"],
|
||||
["cw", ["enter_mode", "insert"], ["cut_word_right_vim"]],
|
||||
["cb", ["enter_mode", "insert"], ["cut_word_left_vim"]],
|
||||
|
||||
["ciw", ["enter_mode", "insert"], ["cut_inside_word"]],
|
||||
["caw", ["enter_mode", "insert"], ["cut_around_word"]],
|
||||
|
||||
["yy", ["copy_line_internal_vim"], ["cancel"]],
|
||||
|
||||
["yiw", ["copy_inside_word"], ["cancel"]],
|
||||
["yaw", ["copy_around_word"], ["cancel"]],
|
||||
|
||||
["<C-u>", "move_scroll_half_page_up_vim"],
|
||||
["<C-d>", "move_scroll_half_page_down_vim"],
|
||||
|
||||
|
|
@ -159,6 +168,9 @@
|
|||
["B", "select_word_left"],
|
||||
["e", "select_word_right_end_vim"],
|
||||
|
||||
["iw", "select_inside_word"],
|
||||
["aw", "select_around_word"],
|
||||
|
||||
["^", "smart_move_begin"],
|
||||
["$", "select_end"],
|
||||
[":", "open_command_palette"],
|
||||
|
|
|
|||
|
|
@ -2628,7 +2628,15 @@ pub const Editor = struct {
|
|||
return cursor.test_at(root, is_whitespace, metrics);
|
||||
}
|
||||
|
||||
fn is_non_whitespace_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
|
||||
pub fn is_whitespace_or_eol_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
|
||||
return cursor.test_at(root, is_whitespace_or_eol, metrics);
|
||||
}
|
||||
|
||||
pub fn is_non_whitespace_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
|
||||
return !cursor.test_at(root, is_whitespace, metrics);
|
||||
}
|
||||
|
||||
pub fn is_non_whitespace_or_eol_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
|
||||
return !cursor.test_at(root, is_whitespace_or_eol, metrics);
|
||||
}
|
||||
|
||||
|
|
@ -3745,7 +3753,7 @@ pub const Editor = struct {
|
|||
}
|
||||
|
||||
pub fn move_cursor_right_until_non_whitespace(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
|
||||
move_cursor_right_until(root, cursor, is_non_whitespace_at_cursor, metrics);
|
||||
move_cursor_right_until(root, cursor, is_non_whitespace_or_eol_at_cursor, metrics);
|
||||
}
|
||||
|
||||
pub fn move_word_left(self: *Self, ctx: Context) Result {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,13 @@ const std = @import("std");
|
|||
const command = @import("command");
|
||||
const cmd = command.executeName;
|
||||
|
||||
const tui = @import("../tui.zig");
|
||||
|
||||
const Buffer = @import("Buffer");
|
||||
const Cursor = Buffer.Cursor;
|
||||
const CurSel = @import("../editor.zig").CurSel;
|
||||
const Editor = @import("../editor.zig").Editor;
|
||||
|
||||
var commands: Commands = undefined;
|
||||
|
||||
pub fn init() !void {
|
||||
|
|
@ -138,6 +145,125 @@ const cmds_ = struct {
|
|||
//TODO
|
||||
return undefined;
|
||||
}
|
||||
|
||||
pub const copy_line_meta: Meta = .{ .description = "Copies the current line" };
|
||||
|
||||
pub fn select_inside_word(_: *void, _: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = ed.buf_root() catch return;
|
||||
|
||||
try ed.with_cursels_const(root, select_inside_word_textobject, ed.metrics);
|
||||
}
|
||||
pub const select_inside_word_meta: Meta = .{ .description = "Select inside word" };
|
||||
|
||||
pub fn select_around_word(_: *void, _: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = ed.buf_root() catch return;
|
||||
|
||||
try ed.with_cursels_const(root, select_around_word_textobject, ed.metrics);
|
||||
}
|
||||
pub const select_around_word_meta: Meta = .{ .description = "Select around word" };
|
||||
|
||||
pub fn cut_inside_word(_: *void, ctx: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = ed.buf_root() catch return;
|
||||
|
||||
try ed.with_cursels_const(root, select_inside_word_textobject, ed.metrics);
|
||||
try ed.cut_internal_vim(ctx);
|
||||
}
|
||||
pub const cut_inside_word_meta: Meta = .{ .description = "Cut inside word" };
|
||||
|
||||
pub fn cut_around_word(_: *void, ctx: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = ed.buf_root() catch return;
|
||||
|
||||
try ed.with_cursels_const(root, select_around_word_textobject, ed.metrics);
|
||||
try ed.cut_internal_vim(ctx);
|
||||
}
|
||||
pub const cut_around_word_meta: Meta = .{ .description = "Cut around word" };
|
||||
|
||||
pub fn copy_inside_word(_: *void, ctx: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = ed.buf_root() catch return;
|
||||
|
||||
try ed.with_cursels_const(root, select_inside_word_textobject, ed.metrics);
|
||||
try ed.copy_internal_vim(ctx);
|
||||
}
|
||||
pub const copy_inside_word_meta: Meta = .{ .description = "Copy inside word" };
|
||||
|
||||
pub fn copy_around_word(_: *void, ctx: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = ed.buf_root() catch return;
|
||||
|
||||
try ed.with_cursels_const(root, select_around_word_textobject, ed.metrics);
|
||||
try ed.copy_internal_vim(ctx);
|
||||
}
|
||||
pub const copy_around_word_meta: Meta = .{ .description = "Copy around word" };
|
||||
};
|
||||
|
||||
fn is_tab_or_space(c: []const u8) bool {
|
||||
return (c[0] == ' ') or (c[0] == '\t');
|
||||
}
|
||||
|
||||
fn is_tab_or_space_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
|
||||
return cursor.test_at(root, is_tab_or_space, metrics);
|
||||
}
|
||||
fn is_not_tab_or_space_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
|
||||
return !cursor.test_at(root, is_tab_or_space, metrics);
|
||||
}
|
||||
|
||||
fn select_inside_word_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void {
|
||||
return try select_word_textobject(root, cursel, metrics, .inside);
|
||||
}
|
||||
|
||||
fn select_around_word_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void {
|
||||
return try select_word_textobject(root, cursel, metrics, .around);
|
||||
}
|
||||
|
||||
fn select_word_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics, scope: enum { inside, around }) !void {
|
||||
var prev = cursel.cursor;
|
||||
var next = cursel.cursor;
|
||||
|
||||
if (cursel.cursor.test_at(root, Editor.is_non_word_char, metrics)) {
|
||||
if (cursel.cursor.test_at(root, Editor.is_whitespace_or_eol, metrics)) {
|
||||
Editor.move_cursor_left_until(root, &prev, Editor.is_non_whitespace_at_cursor, metrics);
|
||||
Editor.move_cursor_right_until(root, &next, Editor.is_non_whitespace_at_cursor, metrics);
|
||||
} else {
|
||||
Editor.move_cursor_left_until(root, &prev, Editor.is_whitespace_or_eol_at_cursor, metrics);
|
||||
Editor.move_cursor_right_until(root, &next, Editor.is_whitespace_or_eol_at_cursor, metrics);
|
||||
}
|
||||
prev.move_right(root, metrics) catch {};
|
||||
} else {
|
||||
Editor.move_cursor_left_until(root, &prev, Editor.is_word_boundary_left_vim, metrics);
|
||||
Editor.move_cursor_right_until(root, &next, Editor.is_word_boundary_right_vim, metrics);
|
||||
next.move_right(root, metrics) catch {};
|
||||
}
|
||||
|
||||
if (scope == .around) {
|
||||
const inside_prev = prev;
|
||||
const inside_next = next;
|
||||
|
||||
if (next.test_at(root, is_tab_or_space, metrics)) {
|
||||
Editor.move_cursor_right_until(root, &next, is_not_tab_or_space_at_cursor, metrics);
|
||||
} else {
|
||||
next = inside_next;
|
||||
prev.move_left(root, metrics) catch {};
|
||||
if (prev.test_at(root, is_tab_or_space, metrics)) {
|
||||
Editor.move_cursor_left_until(root, &prev, is_not_tab_or_space_at_cursor, metrics);
|
||||
prev.move_right(root, metrics) catch {};
|
||||
} else {
|
||||
prev = inside_prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const sel = cursel.enable_selection(root, metrics);
|
||||
sel.begin = prev;
|
||||
sel.end = next;
|
||||
cursel.*.cursor = next;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue