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"],
|
["dgg", "cut_buffer_begin"],
|
||||||
["\"_dd", "delete_line"],
|
["\"_dd", "delete_line"],
|
||||||
|
|
||||||
|
["diw", "cut_inside_word"],
|
||||||
|
["daw", "cut_around_word"],
|
||||||
|
|
||||||
["cc", ["enter_mode", "insert"], ["cut_internal_vim"]],
|
["cc", ["enter_mode", "insert"], ["cut_internal_vim"]],
|
||||||
["C", ["enter_mode", "insert"], ["cut_to_end_vim"]],
|
["C", ["enter_mode", "insert"], ["cut_to_end_vim"]],
|
||||||
["D", "cut_to_end_vim"],
|
["D", "cut_to_end_vim"],
|
||||||
["cw", ["enter_mode", "insert"], ["cut_word_right_vim"]],
|
["cw", ["enter_mode", "insert"], ["cut_word_right_vim"]],
|
||||||
["cb", ["enter_mode", "insert"], ["cut_word_left_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"]],
|
["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-u>", "move_scroll_half_page_up_vim"],
|
||||||
["<C-d>", "move_scroll_half_page_down_vim"],
|
["<C-d>", "move_scroll_half_page_down_vim"],
|
||||||
|
|
||||||
|
|
@ -159,6 +168,9 @@
|
||||||
["B", "select_word_left"],
|
["B", "select_word_left"],
|
||||||
["e", "select_word_right_end_vim"],
|
["e", "select_word_right_end_vim"],
|
||||||
|
|
||||||
|
["iw", "select_inside_word"],
|
||||||
|
["aw", "select_around_word"],
|
||||||
|
|
||||||
["^", "smart_move_begin"],
|
["^", "smart_move_begin"],
|
||||||
["$", "select_end"],
|
["$", "select_end"],
|
||||||
[":", "open_command_palette"],
|
[":", "open_command_palette"],
|
||||||
|
|
|
||||||
|
|
@ -2628,7 +2628,15 @@ pub const Editor = struct {
|
||||||
return cursor.test_at(root, is_whitespace, metrics);
|
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);
|
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 {
|
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 {
|
pub fn move_word_left(self: *Self, ctx: Context) Result {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,13 @@ const std = @import("std");
|
||||||
const command = @import("command");
|
const command = @import("command");
|
||||||
const cmd = command.executeName;
|
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;
|
var commands: Commands = undefined;
|
||||||
|
|
||||||
pub fn init() !void {
|
pub fn init() !void {
|
||||||
|
|
@ -138,6 +145,125 @@ const cmds_ = struct {
|
||||||
//TODO
|
//TODO
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const copy_line_meta: Meta = .{ .description = "Copies the current line" };
|
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