diff --git a/src/keybind/builtin/vim.json b/src/keybind/builtin/vim.json index 8b3d9106..07d82099 100644 --- a/src/keybind/builtin/vim.json +++ b/src/keybind/builtin/vim.json @@ -88,8 +88,6 @@ ["di]", "cut_inside_square_brackets"], ["di{", "cut_inside_braces"], ["di}", "cut_inside_braces"], - ["di'", "cut_inside_single_quotes"], - ["di\"", "cut_inside_double_quotes"], ["daw", "cut_around_word"], ["da(", "cut_around_parentheses"], @@ -98,8 +96,6 @@ ["da]", "cut_around_square_brackets"], ["da{", "cut_around_braces"], ["da}", "cut_around_braces"], - ["da'", "cut_around_single_quotes"], - ["da\"", "cut_around_double_quotes"], ["cc", ["enter_mode", "insert"], ["cut_internal_vim"]], ["C", ["enter_mode", "insert"], ["cut_to_end_vim"]], @@ -114,8 +110,6 @@ ["ci]", ["enter_mode", "insert"], ["cut_inside_square_brackets"]], ["ci{", ["enter_mode", "insert"], ["cut_inside_braces"]], ["ci}", ["enter_mode", "insert"], ["cut_inside_braces"]], - ["ci'", ["enter_mode", "insert"], ["cut_inside_single_quotes"]], - ["ci\"", ["enter_mode", "insert"], ["cut_inside_double_quotes"]], ["caw", ["enter_mode", "insert"], ["cut_around_word"]], ["ca(", ["enter_mode", "insert"], ["cut_around_parentheses"]], @@ -124,8 +118,6 @@ ["ca]", ["enter_mode", "insert"], ["cut_around_square_brackets"]], ["ca{", ["enter_mode", "insert"], ["cut_around_braces"]], ["ca}", ["enter_mode", "insert"], ["cut_around_braces"]], - ["ca'", ["enter_mode", "insert"], ["cut_around_single_quotes"]], - ["ca\"", ["enter_mode", "insert"], ["cut_around_double_quotes"]], ["yy", ["copy_line_internal_vim"], ["cancel"]], @@ -136,8 +128,6 @@ ["yi]", ["copy_inside_square_brackets"], ["cancel"]], ["yi{", ["copy_inside_braces"], ["cancel"]], ["yi}", ["copy_inside_braces"], ["cancel"]], - ["yi'", ["copy_inside_single_quotes"], ["cancel"]], - ["yi\"", ["copy_inside_double_quotes"], ["cancel"]], ["yaw", ["copy_around_word"], ["cancel"]], ["ya(", ["copy_around_parentheses"], ["cancel"]], @@ -146,8 +136,6 @@ ["ya]", ["copy_around_square_brackets"], ["cancel"]], ["ya{", ["copy_around_braces"], ["cancel"]], ["ya}", ["copy_around_braces"], ["cancel"]], - ["ya'", ["copy_around_single_quotes"], ["cancel"]], - ["ya\"", ["copy_around_double_quotes"], ["cancel"]], ["", "move_scroll_half_page_up_vim"], ["", "move_scroll_half_page_down_vim"], @@ -226,8 +214,6 @@ ["i]", "select_inside_square_brackets"], ["i{", "select_inside_braces"], ["i}", "select_inside_braces"], - ["i'", "select_inside_single_quotes"], - ["i\"", "select_inside_double_quotes"], ["aw", "select_around_word"], ["a(", "select_around_parentheses"], @@ -236,8 +222,6 @@ ["a]", "select_around_square_brackets"], ["a{", "select_around_braces"], ["a}", "select_around_braces"], - ["a'", "select_around_single_quotes"], - ["a\"", "select_around_double_quotes"], ["^", "smart_move_begin"], ["$", "select_end"], diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 7748fe53..b0d75484 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -3974,132 +3974,6 @@ pub const Editor = struct { } pub const goto_bracket_meta: Meta = .{ .description = "Goto matching bracket" }; - const QuoteRole = enum { opening, closing }; - - fn row_start_cursor(root: Buffer.Root, cursor: Cursor, metrics: Buffer.Metrics) Cursor { - var c = cursor; - - while (true) { - var prev = c; - prev.move_left(root, metrics) catch break; - if (prev.row != c.row) break; - c = prev; - } - - return c; - } - - fn quote_is_escaped(root: Buffer.Root, quote_cursor: Cursor, metrics: Buffer.Metrics) bool { - var cursor = quote_cursor; - var backslashes: usize = 0; - - while (true) { - var prev = cursor; - prev.move_left(root, metrics) catch break; - if (prev.row != cursor.row) break; - - const egc, _, _ = root.egc_at(prev.row, prev.col, metrics) catch break; - if (!std.mem.eql(u8, egc, "\\")) break; - - backslashes += 1; - cursor = prev; - } - - return (backslashes % 2) == 1; - } - - fn find_unescaped_quote( - root: Buffer.Root, - start: Cursor, - metrics: Buffer.Metrics, - direction: enum { left, right }, - quote: []const u8, - ) error{Stop}!Cursor { - var cursor = start; - var i: usize = 0; - - while (i < bracket_search_radius) : (i += 1) { - switch (direction) { - .left => cursor.move_left(root, metrics) catch return error.Stop, - .right => cursor.move_right(root, metrics) catch return error.Stop, - } - - const egc, _, _ = root.egc_at(cursor.row, cursor.col, metrics) catch { - return error.Stop; - }; - - if (!std.mem.eql(u8, egc, quote)) continue; - if (quote_is_escaped(root, cursor, metrics)) continue; - - return cursor; - } - - return error.Stop; - } - - fn quote_role_on_row( - root: Buffer.Root, - quote_cursor: Cursor, - metrics: Buffer.Metrics, - quote: []const u8, - ) error{Stop}!QuoteRole { - var cursor = row_start_cursor(root, .{ .row = quote_cursor.row, .col = 0 }, metrics); - var opening = true; - - while (cursor.row == quote_cursor.row and cursor.col <= quote_cursor.col) { - const egc, _, _ = root.egc_at(cursor.row, cursor.col, metrics) catch { - return error.Stop; - }; - - if (std.mem.eql(u8, egc, quote) and !quote_is_escaped(root, cursor, metrics)) { - if (cursor.col == quote_cursor.col) { - return if (opening) .opening else .closing; - } - opening = !opening; - } - - cursor.move_right(root, metrics) catch break; - } - - return error.Stop; - } - - pub fn find_quote_pair( - root: Buffer.Root, - original_cursor: Cursor, - metrics: Buffer.Metrics, - quote: []const u8, - ) error{Stop}!struct { struct { usize, usize }, struct { usize, usize } } { - - // If the cursor is already on a quote, use it directly as the anchor. - // Otherwise find the nearest quote, preferring rightward. - const cursor_egc, _, _ = root.egc_at(original_cursor.row, original_cursor.col, metrics) catch return error.Stop; - const anchor = if (std.mem.eql(u8, cursor_egc, quote)) - original_cursor - else - find_unescaped_quote(root, original_cursor, metrics, .right, quote) catch - find_unescaped_quote(root, original_cursor, metrics, .left, quote) catch - return error.Stop; - - const role = try quote_role_on_row(root, anchor, metrics, quote); - - const other = switch (role) { - .opening => try find_unescaped_quote(root, anchor, metrics, .right, quote), - .closing => try find_unescaped_quote(root, anchor, metrics, .left, quote), - }; - - return switch (role) { - .opening => .{ - .{ anchor.row, anchor.col }, - .{ other.row, other.col }, - }, - .closing => .{ - .{ other.row, other.col }, - .{ anchor.row, anchor.col }, - }, - }; - } - pub fn move_or_select_to_char_right(self: *Self, ctx: Context) Result { const selected = if (self.get_primary().selection) |_| true else false; if (selected) try self.select_to_char_right(ctx) else try self.move_to_char_right(ctx); diff --git a/src/tui/mode/vim.zig b/src/tui/mode/vim.zig index 823cc812..043ed35a 100644 --- a/src/tui/mode/vim.zig +++ b/src/tui/mode/vim.zig @@ -220,42 +220,6 @@ const cmds_ = struct { } pub const select_around_braces_meta: Meta = .{ .description = "Select around {}" }; - pub fn select_inside_single_quotes(_: *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_single_quotes_textobject, ed.metrics); - } - pub const select_inside_single_quotes_meta: Meta = .{ .description = "Select inside ''" }; - - pub fn select_around_single_quotes(_: *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_single_quotes_textobject, ed.metrics); - } - pub const select_around_single_quotes_meta: Meta = .{ .description = "Select around ''" }; - - pub fn select_inside_double_quotes(_: *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_double_quotes_textobject, ed.metrics); - } - pub const select_inside_double_quotes_meta: Meta = .{ .description = "Select inside \"\"" }; - - pub fn select_around_double_quotes(_: *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_double_quotes_textobject, ed.metrics); - } - pub const select_around_double_quotes_meta: Meta = .{ .description = "Select around \"\"" }; - pub fn cut_inside_word(_: *void, ctx: Ctx) Result { const mv = tui.mainview() orelse return; const ed = mv.get_active_editor() orelse return; @@ -336,46 +300,6 @@ const cmds_ = struct { } pub const cut_around_braces_meta: Meta = .{ .description = "Cut around {}" }; - pub fn cut_inside_single_quotes(_: *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_single_quotes_textobject, ed.metrics); - try ed.cut_internal_vim(ctx); - } - pub const cut_inside_single_quotes_meta: Meta = .{ .description = "Cut inside ''" }; - - pub fn cut_around_single_quotes(_: *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_single_quotes_textobject, ed.metrics); - try ed.cut_internal_vim(ctx); - } - pub const cut_around_single_quotes_meta: Meta = .{ .description = "Cut around ''" }; - - pub fn cut_inside_double_quotes(_: *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_double_quotes_textobject, ed.metrics); - try ed.cut_internal_vim(ctx); - } - pub const cut_inside_double_quotes_meta: Meta = .{ .description = "Cut inside \"\"" }; - - pub fn cut_around_double_quotes(_: *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_double_quotes_textobject, ed.metrics); - try ed.cut_internal_vim(ctx); - } - pub const cut_around_double_quotes_meta: Meta = .{ .description = "Cut around \"\"" }; - pub fn copy_inside_word(_: *void, ctx: Ctx) Result { const mv = tui.mainview() orelse return; const ed = mv.get_active_editor() orelse return; @@ -455,46 +379,6 @@ const cmds_ = struct { try ed.copy_internal_vim(ctx); } pub const copy_around_braces_meta: Meta = .{ .description = "Copy around {}" }; - - pub fn copy_inside_single_quotes(_: *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_single_quotes_textobject, ed.metrics); - try ed.copy_internal_vim(ctx); - } - pub const copy_inside_single_quotes_meta: Meta = .{ .description = "Copy inside ''" }; - - pub fn copy_around_single_quotes(_: *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_single_quotes_textobject, ed.metrics); - try ed.copy_internal_vim(ctx); - } - pub const copy_around_single_quotes_meta: Meta = .{ .description = "Copy around ''" }; - - pub fn copy_inside_double_quotes(_: *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_double_quotes_textobject, ed.metrics); - try ed.copy_internal_vim(ctx); - } - pub const copy_inside_double_quotes_meta: Meta = .{ .description = "Copy inside \"\"" }; - - pub fn copy_around_double_quotes(_: *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_double_quotes_textobject, ed.metrics); - try ed.copy_internal_vim(ctx); - } - pub const copy_around_double_quotes_meta: Meta = .{ .description = "Copy around \"\"" }; }; fn is_tab_or_space(c: []const u8) bool { @@ -560,94 +444,56 @@ fn select_word_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Me } fn select_inside_parentheses_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - return try select_scope_textobject(root, cursel, metrics, "(", ")", .inside); + return try select_bracket_textobject(root, cursel, metrics, "(", ")", .inside); } fn select_around_parentheses_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - return try select_scope_textobject(root, cursel, metrics, "(", ")", .around); + return try select_bracket_textobject(root, cursel, metrics, "(", ")", .around); } fn select_inside_square_brackets_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - return try select_scope_textobject(root, cursel, metrics, "[", "]", .inside); + return try select_bracket_textobject(root, cursel, metrics, "[", "]", .inside); } fn select_around_square_brackets_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - return try select_scope_textobject(root, cursel, metrics, "[", "]", .around); + return try select_bracket_textobject(root, cursel, metrics, "[", "]", .around); } fn select_inside_braces_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - return try select_scope_textobject(root, cursel, metrics, "{", "}", .inside); + return try select_bracket_textobject(root, cursel, metrics, "{", "}", .inside); } fn select_around_braces_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - return try select_scope_textobject(root, cursel, metrics, "{", "}", .around); + return try select_bracket_textobject(root, cursel, metrics, "{", "}", .around); } -fn select_inside_single_quotes_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - return try select_scope_textobject(root, cursel, metrics, "'", "'", .inside); -} - -fn select_around_single_quotes_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - return try select_scope_textobject(root, cursel, metrics, "'", "'", .around); -} - -fn select_inside_double_quotes_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - return try select_scope_textobject(root, cursel, metrics, "\"", "\"", .inside); -} - -fn select_around_double_quotes_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - return try select_scope_textobject(root, cursel, metrics, "\"", "\"", .around); -} - -fn select_scope_textobject( - root: Buffer.Root, - cursel: *CurSel, - metrics: Buffer.Metrics, - opening_char: []const u8, - closing_char: []const u8, - scope: enum { inside, around }, -) !void { +fn select_bracket_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics, opening_char: []const u8, closing_char: []const u8, scope: enum { inside, around }) !void { const current = cursel.cursor; var prev = cursel.cursor; var next = cursel.cursor; - if (std.mem.eql(u8, opening_char, closing_char)) { - const opening_pos, const closing_pos = - try Editor.find_quote_pair(root, current, metrics, opening_char); + const bracket_egc, _, _ = root.egc_at(current.row, current.col, metrics) catch { + return error.Stop; + }; + if (std.mem.eql(u8, bracket_egc, opening_char)) { + const closing_row, const closing_col = try Editor.match_bracket(root, current, metrics); + + prev = current; + next.row = closing_row; + next.col = closing_col; + } else if (std.mem.eql(u8, bracket_egc, closing_char)) { + const opening_row, const opening_col = try Editor.match_bracket(root, current, metrics); + + prev.row = opening_row; + prev.col = opening_col; + next = current; + } else { + const opening_pos, const closing_pos = find_bracket_pair(root, cursel, metrics, .left, opening_char) catch try find_bracket_pair(root, cursel, metrics, .right, opening_char); prev.row = opening_pos[0]; prev.col = opening_pos[1]; next.row = closing_pos[0]; next.col = closing_pos[1]; - } else { - const bracket_egc, _, _ = root.egc_at(current.row, current.col, metrics) catch { - return error.Stop; - }; - - if (std.mem.eql(u8, bracket_egc, opening_char)) { - const closing_row, const closing_col = - try Editor.match_bracket(root, current, metrics); - - prev = current; - next.row = closing_row; - next.col = closing_col; - } else if (std.mem.eql(u8, bracket_egc, closing_char)) { - const opening_row, const opening_col = - try Editor.match_bracket(root, current, metrics); - - prev.row = opening_row; - prev.col = opening_col; - next = current; - } else { - const pair = find_bracket_pair(root, cursel, metrics, .left, opening_char) catch blk: { - break :blk try find_bracket_pair(root, cursel, metrics, .right, opening_char); - }; - - prev.row = pair[0][0]; - prev.col = pair[0][1]; - next.row = pair[1][0]; - next.col = pair[1][1]; - } } prev.move_right(root, metrics) catch {};