Merge branch 'master' into wio-sokol-gui
This commit is contained in:
commit
02ec222ebf
9 changed files with 547 additions and 88 deletions
|
|
@ -201,6 +201,24 @@ pub fn switch_case(allocator: std.mem.Allocator, text: []const u8) TransformErro
|
|||
to_upper(allocator, text);
|
||||
}
|
||||
|
||||
pub fn toggle_case(allocator: std.mem.Allocator, text: []const u8) TransformError![]u8 {
|
||||
var result: std.Io.Writer.Allocating = .init(allocator);
|
||||
defer result.deinit();
|
||||
const writer = &result.writer;
|
||||
const view: Utf8View = .initUnchecked(text);
|
||||
var it = view.iterator();
|
||||
while (it.nextCodepoint()) |cp| {
|
||||
const cp_ = if (uucode.get(.changes_when_lowercased, cp))
|
||||
uucode.get(.simple_lowercase_mapping, cp) orelse cp
|
||||
else
|
||||
uucode.get(.simple_uppercase_mapping, cp) orelse cp;
|
||||
var utf8_buf: [6]u8 = undefined;
|
||||
const size = try utf8Encode(cp_, &utf8_buf);
|
||||
try writer.writeAll(utf8_buf[0..size]);
|
||||
}
|
||||
return result.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub fn is_lowercase(text: []const u8) bool {
|
||||
return utf8_predicate_all(.is_lowercase, text);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ hint_window_style: WidgetStyle = .thick_boxed,
|
|||
info_box_style: WidgetStyle = .bar_left_spacious,
|
||||
info_box_width_limit: usize = 80,
|
||||
|
||||
palette_placement: PalettePlacement = .top_center,
|
||||
|
||||
centered_view: bool = false,
|
||||
centered_view_width: usize = 145,
|
||||
centered_view_min_screen_width: usize = 145,
|
||||
|
|
@ -256,3 +258,10 @@ pub const TerminalOnExit = enum {
|
|||
close,
|
||||
hold,
|
||||
};
|
||||
|
||||
pub const PalettePlacement = enum {
|
||||
top_center,
|
||||
top_left,
|
||||
top_right,
|
||||
center,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@
|
|||
["alt+l", "to_lower"],
|
||||
["alt+q", "reflow"],
|
||||
["alt+c", "switch_case"],
|
||||
["ctrl+k c", "toggle_case"],
|
||||
["ctrl+_", "underline"],
|
||||
["ctrl+=", "underline_with_char", "=", "solid"],
|
||||
["ctrl+plus", "underline_with_char", "="],
|
||||
|
|
@ -187,8 +188,8 @@
|
|||
["alt+[", "select_prev_sibling", true],
|
||||
["alt+]", "select_next_sibling", true],
|
||||
["alt+a", "select_all_siblings"],
|
||||
["alt+shift+home", "move_scroll_left"],
|
||||
["alt+shift+end", "move_scroll_right"],
|
||||
["alt+shift+home", "scroll_left"],
|
||||
["alt+shift+end", "scroll_right"],
|
||||
["alt+shift+up", "add_cursor_up"],
|
||||
["alt+shift+down", "add_cursor_down"],
|
||||
["alt+shift+f12", "goto_type_definition"],
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@
|
|||
["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"],
|
||||
|
|
@ -96,6 +98,8 @@
|
|||
["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"]],
|
||||
|
|
@ -110,6 +114,8 @@
|
|||
["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"]],
|
||||
|
|
@ -118,6 +124,8 @@
|
|||
["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"]],
|
||||
|
||||
|
|
@ -128,6 +136,8 @@
|
|||
["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"]],
|
||||
|
|
@ -136,6 +146,8 @@
|
|||
["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"]],
|
||||
|
||||
["<C-u>", "move_scroll_half_page_up_vim"],
|
||||
["<C-d>", "move_scroll_half_page_down_vim"],
|
||||
|
|
@ -214,6 +226,8 @@
|
|||
["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"],
|
||||
|
|
@ -222,6 +236,8 @@
|
|||
["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"],
|
||||
|
|
|
|||
|
|
@ -1673,23 +1673,15 @@ pub const Editor = struct {
|
|||
const style_ = style_cache_lookup(ctx.theme, ctx.cache, scope, id);
|
||||
const style = if (style_) |sty| sty.style else return;
|
||||
|
||||
if (sel.end.row < ctx.self.view.row) return;
|
||||
if (sel.begin.row > ctx.self.view.row + ctx.self.view.rows) return;
|
||||
if (sel.begin.row < ctx.self.view.row) sel.begin.row = ctx.self.view.row;
|
||||
if (sel.end.row > ctx.self.view.row + ctx.self.view.rows) sel.end.row = ctx.self.view.row + ctx.self.view.rows;
|
||||
|
||||
if (sel.end.col < ctx.self.view.col) return;
|
||||
if (sel.begin.col > ctx.self.view.col + ctx.self.view.cols) return;
|
||||
if (sel.begin.col < ctx.self.view.col) sel.begin.col = ctx.self.view.col;
|
||||
if (sel.end.col > ctx.self.view.col + ctx.self.view.cols) sel.end.col = ctx.self.view.col + ctx.self.view.cols;
|
||||
ctx.clamp_to_view(&sel.begin);
|
||||
ctx.clamp_to_view(&sel.end);
|
||||
|
||||
for (sel.begin.row..sel.end.row + 1) |row| {
|
||||
const begin_col = if (row == sel.begin.row) sel.begin.col else 0;
|
||||
const begin_col = if (row == sel.begin.row) sel.begin.col else ctx.self.view.col;
|
||||
const end_col = if (row == sel.end.row) sel.end.col else ctx.self.view.col + ctx.self.view.cols;
|
||||
const y = @max(ctx.self.view.row, row) - ctx.self.view.row;
|
||||
const x = @max(ctx.self.view.col, begin_col) - ctx.self.view.col;
|
||||
const end_x = @max(ctx.self.view.col, end_col) - ctx.self.view.col;
|
||||
if (x >= end_x) return;
|
||||
const y = row - ctx.self.view.row;
|
||||
const x = begin_col - ctx.self.view.col;
|
||||
const end_x = end_col - ctx.self.view.col;
|
||||
for (x..end_x) |x_|
|
||||
try ctx.render_cell(y, x_, style);
|
||||
}
|
||||
|
|
@ -1701,6 +1693,19 @@ pub const Editor = struct {
|
|||
cell.set_style(style);
|
||||
_ = ctx.self.plane.putc(&cell) catch {};
|
||||
}
|
||||
fn clamp_to_view(ctx: *const @This(), cursor: *Cursor) void {
|
||||
const row_off: u32 = @intCast(ctx.self.view.row);
|
||||
const col_off: u32 = @intCast(ctx.self.view.col);
|
||||
if (cursor.row < row_off) {
|
||||
cursor.row = row_off;
|
||||
cursor.col = col_off;
|
||||
}
|
||||
if (cursor.row >= row_off + ctx.self.view.rows) {
|
||||
cursor.row = row_off + ctx.self.view.rows;
|
||||
cursor.col = col_off + ctx.self.view.cols;
|
||||
}
|
||||
cursor.col = std.math.clamp(cursor.col, col_off, col_off + ctx.self.view.cols);
|
||||
}
|
||||
};
|
||||
var ctx: Ctx = .{
|
||||
.self = self,
|
||||
|
|
@ -3002,17 +3007,15 @@ pub const Editor = struct {
|
|||
self.update_animation_step(dest);
|
||||
}
|
||||
|
||||
fn scroll_up(self: *Self) void {
|
||||
const scroll_step_vertical = tui.config().scroll_step_vertical;
|
||||
fn scroll_up_internal(self: *Self, count: usize) void {
|
||||
var dest_row = self.scroll_dest;
|
||||
dest_row = if (dest_row > scroll_step_vertical) dest_row - scroll_step_vertical else 0;
|
||||
dest_row -|= count;
|
||||
self.update_scroll_dest_abs(dest_row);
|
||||
}
|
||||
|
||||
fn scroll_down(self: *Self) void {
|
||||
const scroll_step_vertical = tui.config().scroll_step_vertical;
|
||||
fn scroll_down_internal(self: *Self, count: usize) void {
|
||||
var dest_row = self.scroll_dest;
|
||||
dest_row += scroll_step_vertical;
|
||||
dest_row += count;
|
||||
self.update_scroll_dest_abs(dest_row);
|
||||
}
|
||||
|
||||
|
|
@ -3035,7 +3038,7 @@ pub const Editor = struct {
|
|||
else if (tui.fast_scroll())
|
||||
self.scroll_pageup()
|
||||
else
|
||||
self.scroll_up();
|
||||
self.scroll_up_internal(tui.config().scroll_step_vertical);
|
||||
}
|
||||
|
||||
pub fn mouse_scroll_down(self: *Self) void {
|
||||
|
|
@ -3044,7 +3047,7 @@ pub const Editor = struct {
|
|||
else if (tui.fast_scroll())
|
||||
self.scroll_pagedown()
|
||||
else
|
||||
self.scroll_down();
|
||||
self.scroll_down_internal(tui.config().scroll_step_vertical);
|
||||
}
|
||||
|
||||
pub fn scroll_to(self: *Self, row: usize) void {
|
||||
|
|
@ -3969,6 +3972,132 @@ 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);
|
||||
|
|
@ -4411,6 +4540,20 @@ pub const Editor = struct {
|
|||
}
|
||||
pub const unindent_meta: Meta = .{ .description = "Unindent current line", .arguments = &.{.integer} };
|
||||
|
||||
pub fn scroll_up(self: *Self, ctx: Context) Result {
|
||||
var count: usize = 1;
|
||||
_ = ctx.args.match(.{tp.extract(&count)}) catch false;
|
||||
self.scroll_up_internal(count);
|
||||
}
|
||||
pub const scroll_up_meta: Meta = .{ .description = "Scroll up", .arguments = &.{.integer} };
|
||||
|
||||
pub fn scroll_down(self: *Self, ctx: Context) Result {
|
||||
var count: usize = 1;
|
||||
_ = ctx.args.match(.{tp.extract(&count)}) catch false;
|
||||
self.scroll_down_internal(count);
|
||||
}
|
||||
pub const scroll_down_meta: Meta = .{ .description = "Scroll down", .arguments = &.{.integer} };
|
||||
|
||||
pub fn move_scroll_up(self: *Self, ctx: Context) Result {
|
||||
const root = try self.buf_root();
|
||||
self.with_cursors_const_repeat(root, move_cursor_up, ctx) catch {};
|
||||
|
|
@ -4427,15 +4570,19 @@ pub const Editor = struct {
|
|||
}
|
||||
pub const move_scroll_down_meta: Meta = .{ .description = "Move and scroll down", .arguments = &.{.integer} };
|
||||
|
||||
pub fn move_scroll_left(self: *Self, _: Context) Result {
|
||||
self.view.move_left(tui.config().scroll_step_horizontal) catch {};
|
||||
pub fn scroll_left(self: *Self, ctx: Context) Result {
|
||||
var count: usize = 1;
|
||||
_ = ctx.args.match(.{tp.extract(&count)}) catch false;
|
||||
self.view.move_left(count) catch {};
|
||||
}
|
||||
pub const move_scroll_left_meta: Meta = .{ .description = "Scroll left" };
|
||||
pub const scroll_left_meta: Meta = .{ .description = "Scroll left", .arguments = &.{.integer} };
|
||||
|
||||
pub fn move_scroll_right(self: *Self, _: Context) Result {
|
||||
self.view.move_right(tui.config().scroll_step_horizontal) catch {};
|
||||
pub fn scroll_right(self: *Self, ctx: Context) Result {
|
||||
var count: usize = 1;
|
||||
_ = ctx.args.match(.{tp.extract(&count)}) catch false;
|
||||
self.view.move_right(count) catch {};
|
||||
}
|
||||
pub const move_scroll_right_meta: Meta = .{ .description = "Scroll right" };
|
||||
pub const scroll_right_meta: Meta = .{ .description = "Scroll right", .arguments = &.{.integer} };
|
||||
|
||||
pub fn mouse_scroll_left(self: *Self) void {
|
||||
const scroll_step_horizontal = tui.config().scroll_step_horizontal;
|
||||
|
|
@ -7110,27 +7257,43 @@ pub const Editor = struct {
|
|||
.arguments = &.{.integer},
|
||||
};
|
||||
|
||||
fn to_upper_cursel(self: *Self, root_: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root {
|
||||
fn get_selection_or_select_word(self: *Self, root: Buffer.Root, cursel: *CurSel) error{Stop}!*Selection {
|
||||
if (cursel.selection) |*sel| {
|
||||
return sel;
|
||||
} else {
|
||||
var sel = cursel.enable_selection(root, self.metrics);
|
||||
try move_cursor_word_begin(root, &sel.begin, self.metrics);
|
||||
try move_cursor_word_end(root, &sel.end, self.metrics);
|
||||
return sel;
|
||||
}
|
||||
}
|
||||
|
||||
fn transform_cursel(
|
||||
comptime transform: fn (std.mem.Allocator, []const u8) Buffer.unicode.TransformError![]u8,
|
||||
self: *Self,
|
||||
root_: Buffer.Root,
|
||||
cursel: *CurSel,
|
||||
allocator: Allocator,
|
||||
) error{Stop}!Buffer.Root {
|
||||
var root = root_;
|
||||
const saved = cursel.*;
|
||||
const sel = if (cursel.selection) |*sel| sel else ret: {
|
||||
var sel = cursel.enable_selection(root, self.metrics);
|
||||
move_cursor_word_begin(root, &sel.begin, self.metrics) catch return error.Stop;
|
||||
move_cursor_word_end(root, &sel.end, self.metrics) catch return error.Stop;
|
||||
break :ret sel;
|
||||
};
|
||||
const sel = try self.get_selection_or_select_word(root, cursel);
|
||||
var sfa = std.heap.stackFallback(4096, self.allocator);
|
||||
const sfa_allocator = sfa.get();
|
||||
const cut_text = copy_selection(root, sel.*, sfa_allocator, self.metrics) catch return error.Stop;
|
||||
defer sfa_allocator.free(cut_text);
|
||||
const ucased = Buffer.unicode.to_upper(sfa_allocator, cut_text) catch return error.Stop;
|
||||
defer sfa_allocator.free(ucased);
|
||||
const transformed = transform(sfa_allocator, cut_text) catch return error.Stop;
|
||||
defer sfa_allocator.free(transformed);
|
||||
root = try self.delete_selection(root, cursel, allocator);
|
||||
root = self.insert(root, cursel, ucased, allocator) catch return error.Stop;
|
||||
root = self.insert(root, cursel, transformed, allocator) catch return error.Stop;
|
||||
cursel.* = saved;
|
||||
return root;
|
||||
}
|
||||
|
||||
fn to_upper_cursel(self: *Self, root_: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root {
|
||||
return transform_cursel(Buffer.unicode.to_upper, self, root_, cursel, allocator);
|
||||
}
|
||||
|
||||
pub fn to_upper(self: *Self, _: Context) Result {
|
||||
const b = try self.buf_for_update();
|
||||
const root = try self.with_cursels_mut_once(b.root, to_upper_cursel, b.allocator);
|
||||
|
|
@ -7139,25 +7302,8 @@ pub const Editor = struct {
|
|||
}
|
||||
pub const to_upper_meta: Meta = .{ .description = "Convert selection or word to upper case" };
|
||||
|
||||
fn to_lower_cursel(self: *Self, root_: Buffer.Root, cursel: *CurSel, buffer_allocator: Allocator) error{Stop}!Buffer.Root {
|
||||
var root = root_;
|
||||
const saved = cursel.*;
|
||||
const sel = if (cursel.selection) |*sel| sel else ret: {
|
||||
var sel = cursel.enable_selection(root, self.metrics);
|
||||
move_cursor_word_begin(root, &sel.begin, self.metrics) catch return error.Stop;
|
||||
move_cursor_word_end(root, &sel.end, self.metrics) catch return error.Stop;
|
||||
break :ret sel;
|
||||
};
|
||||
var sfa = std.heap.stackFallback(4096, self.allocator);
|
||||
const sfa_allocator = sfa.get();
|
||||
const cut_text = copy_selection(root, sel.*, sfa_allocator, self.metrics) catch return error.Stop;
|
||||
defer sfa_allocator.free(cut_text);
|
||||
const ucased = Buffer.unicode.to_lower(sfa_allocator, cut_text) catch return error.Stop;
|
||||
defer sfa_allocator.free(ucased);
|
||||
root = try self.delete_selection(root, cursel, buffer_allocator);
|
||||
root = self.insert(root, cursel, ucased, buffer_allocator) catch return error.Stop;
|
||||
cursel.* = saved;
|
||||
return root;
|
||||
fn to_lower_cursel(self: *Self, root_: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root {
|
||||
return transform_cursel(Buffer.unicode.to_lower, self, root_, cursel, allocator);
|
||||
}
|
||||
|
||||
pub fn to_lower(self: *Self, _: Context) Result {
|
||||
|
|
@ -7199,6 +7345,18 @@ pub const Editor = struct {
|
|||
}
|
||||
pub const switch_case_meta: Meta = .{ .description = "Switch the case of selection or character at cursor" };
|
||||
|
||||
fn toggle_case_cursel(self: *Self, root_: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root {
|
||||
return transform_cursel(Buffer.unicode.toggle_case, self, root_, cursel, allocator);
|
||||
}
|
||||
|
||||
pub fn toggle_case(self: *Self, _: Context) Result {
|
||||
const b = try self.buf_for_update();
|
||||
const root = try self.with_cursels_mut_once(b.root, toggle_case_cursel, b.allocator);
|
||||
try self.update_buf(root);
|
||||
self.clamp();
|
||||
}
|
||||
pub const toggle_case_meta: Meta = .{ .description = "Toggle the case of each character in selection or character at cursor" };
|
||||
|
||||
pub fn forced_mark_clean(self: *Self, _: Context) Result {
|
||||
if (self.buffer) |b| {
|
||||
b.mark_clean();
|
||||
|
|
|
|||
|
|
@ -430,6 +430,17 @@ const cmds_ = struct {
|
|||
}
|
||||
pub const select_textobject_inner_meta: Meta = .{ .description = "select inside object helix" };
|
||||
|
||||
pub fn surround_add(_: *void, ctx: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const b = try ed.buf_for_update();
|
||||
const root = try ed.with_cursels_mut_once_arg(b.root, surround_cursel_add, ed.allocator, ctx);
|
||||
try ed.update_buf(root);
|
||||
ed.clamp();
|
||||
ed.need_render();
|
||||
}
|
||||
pub const surround_add_meta: Meta = .{ .description = "surround add" };
|
||||
|
||||
pub fn select_textobject_around(_: *void, ctx: Ctx) Result {
|
||||
var action: []const u8 = "";
|
||||
|
||||
|
|
@ -481,8 +492,8 @@ const cmds_ = struct {
|
|||
pub fn replace_with_character_helix(_: *void, ctx: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
var root = ed.buf_root() catch return;
|
||||
root = try ed.with_cursels_mut_once_arg(root, replace_cursel_with_character, ed.allocator, ctx);
|
||||
const b = try ed.buf_for_update();
|
||||
const root = try ed.with_cursels_mut_once_arg(b.root, replace_cursel_with_character, ed.allocator, ctx);
|
||||
try ed.update_buf(root);
|
||||
ed.clamp();
|
||||
ed.need_render();
|
||||
|
|
@ -865,6 +876,50 @@ fn replace_cursel_with_character(ed: *Editor, root: Buffer.Root, cursel: *CurSel
|
|||
return insert_replace_selection(ed, root, cursel, replacement, allocator) catch return error.Stop;
|
||||
}
|
||||
|
||||
fn find_open_close_pair(bracket: []const u8) struct { left: []const u8, right: []const u8 } {
|
||||
for (Buffer.unicode.open_close_pairs) |pair| {
|
||||
if (std.mem.eql(u8, bracket, pair[0]) or std.mem.eql(u8, bracket, pair[1])) {
|
||||
return .{ .left = pair[0], .right = pair[1] };
|
||||
}
|
||||
}
|
||||
return .{ .left = bracket, .right = bracket };
|
||||
}
|
||||
|
||||
fn surround_cursel_add(ed: *Editor, root: Buffer.Root, cursel: *CurSel, allocator: Allocator, ctx: command.Context) error{Stop}!Buffer.Root {
|
||||
var encloser: []const u8 = undefined;
|
||||
if (!(ctx.args.match(.{tp.extract(&encloser)}) catch return error.Stop))
|
||||
return error.Stop;
|
||||
|
||||
const enclose_pair = find_open_close_pair(encloser);
|
||||
var root_: Buffer.Root = root;
|
||||
cursel.check_selection(root, ed.metrics);
|
||||
|
||||
const sel = cursel.enable_selection(root_, ed.metrics);
|
||||
var begin = sel.begin;
|
||||
var end = sel.end;
|
||||
if (sel.is_reversed()) {
|
||||
end = sel.begin;
|
||||
begin = sel.end;
|
||||
}
|
||||
if (begin.row == end.row and end.col == begin.col) {
|
||||
end.move_right(root_, ed.metrics) catch {};
|
||||
}
|
||||
_, _, root_ = root_.insert_chars(end.row, end.col, enclose_pair.right, allocator, ed.metrics) catch return error.Stop;
|
||||
_, _, root_ = root_.insert_chars(begin.row, begin.col, enclose_pair.left, allocator, ed.metrics) catch return error.Stop;
|
||||
|
||||
if (begin.row == end.row) {
|
||||
try end.move_right(root_, ed.metrics); // for left-bracket column shift on same row
|
||||
}
|
||||
try end.move_right(root_, ed.metrics); // skip past right bracket
|
||||
cursel.selection = Selection{ .begin = begin, .end = end };
|
||||
ed.nudge_insert(.{ .begin = begin, .end = end }, cursel, encloser.len * 2);
|
||||
|
||||
if (end.right_of(begin)) {
|
||||
try cursel.*.cursor.move_right(root_, ed.metrics);
|
||||
}
|
||||
return root_;
|
||||
}
|
||||
|
||||
fn move_noop(_: Buffer.Root, _: *Cursor, _: Buffer.Metrics) error{Stop}!void {}
|
||||
|
||||
fn move_cursor_word_right_end_helix(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
|
||||
|
|
|
|||
|
|
@ -187,10 +187,36 @@ fn prepare_resize_menu(self: *Self, _: *MenuType, _: Widget.Box) Widget.Box {
|
|||
}
|
||||
|
||||
fn prepare_resize(self: *Self) Widget.Box {
|
||||
const screen = tui.screen();
|
||||
const padding = tui.get_widget_style(widget_type).padding;
|
||||
const w = self.menu_width();
|
||||
const x = self.menu_pos_x();
|
||||
const h = self.menu.menu.widgets.items.len;
|
||||
return .{ .y = 0, .x = x, .w = w, .h = h };
|
||||
return switch (tui.config().palette_placement) {
|
||||
.top_center => .{
|
||||
.y = 0,
|
||||
.x = self.menu_pos_x(),
|
||||
.w = w,
|
||||
.h = h,
|
||||
},
|
||||
.top_left => .{
|
||||
.y = 0,
|
||||
.x = 0,
|
||||
.w = w,
|
||||
.h = h,
|
||||
},
|
||||
.top_right => .{
|
||||
.y = 0,
|
||||
.x = if (screen.w > (w - padding.right)) (screen.w - w - padding.right) else 0,
|
||||
.w = w,
|
||||
.h = h,
|
||||
},
|
||||
.center => .{
|
||||
.y = if (screen.h > h) (screen.h - h) / 2 else 0,
|
||||
.x = self.menu_pos_x(),
|
||||
.w = w,
|
||||
.h = h,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn do_resize(self: *Self) void {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,17 @@ pub const Placement = enum {
|
|||
top_center,
|
||||
top_left,
|
||||
top_right,
|
||||
center,
|
||||
primary_cursor,
|
||||
|
||||
fn from_config(conf: @import("config").PalettePlacement) Placement {
|
||||
return switch (conf) {
|
||||
.top_center => .top_center,
|
||||
.top_left => .top_left,
|
||||
.top_right => .top_right,
|
||||
.center => .center,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const ActivateMode = enum {
|
||||
|
|
@ -110,7 +120,10 @@ pub fn Create(options: type) type {
|
|||
.mode = try keybind.mode("overlay/palette", allocator, .{
|
||||
.insert_command = "overlay_insert_bytes",
|
||||
}),
|
||||
.placement = if (@hasDecl(options, "placement")) options.placement else .top_center,
|
||||
.placement = if (@hasDecl(options, "placement"))
|
||||
options.placement
|
||||
else
|
||||
Placement.from_config(tui.config().palette_placement),
|
||||
};
|
||||
try self.commands.init(self);
|
||||
errdefer self.commands.deinit();
|
||||
|
|
@ -205,6 +218,7 @@ pub fn Create(options: type) type {
|
|||
.top_center => self.prepare_resize_top_center(screen, w),
|
||||
.top_left => self.prepare_resize_top_left(screen, w),
|
||||
.top_right => self.prepare_resize_top_right(screen, w, padding),
|
||||
.center => self.prepare_resize_center(screen, w),
|
||||
.primary_cursor => self.prepare_resize_primary_cursor(screen, w, padding),
|
||||
};
|
||||
}
|
||||
|
|
@ -249,6 +263,14 @@ pub fn Create(options: type) type {
|
|||
return self.prepare_resize_at_y_x(screen, w, cursor.row + 1 + padding.top, cursor.col);
|
||||
}
|
||||
|
||||
fn prepare_resize_center(self: *Self, screen: Widget.Box, w: usize) Widget.Box {
|
||||
const x = if (screen.w > w) (screen.w - w) / 2 else 0;
|
||||
const h = @min(self.items + self.menu.header_count, self.view_rows + self.menu.header_count);
|
||||
const y = if (screen.h > h) (screen.h - h) / 2 else 0;
|
||||
self.view_rows = get_view_rows(screen) -| y;
|
||||
return .{ .y = y, .x = x, .w = w, .h = h };
|
||||
}
|
||||
|
||||
fn after_resize_menu(self: *Self, _: *Menu.State(*Self), _: Widget.Box) void {
|
||||
return self.after_resize();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,6 +220,42 @@ 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;
|
||||
|
|
@ -300,6 +336,46 @@ 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;
|
||||
|
|
@ -379,6 +455,46 @@ 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 {
|
||||
|
|
@ -444,56 +560,94 @@ 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_bracket_textobject(root, cursel, metrics, "(", ")", .inside);
|
||||
return try select_scope_textobject(root, cursel, metrics, "(", ")", .inside);
|
||||
}
|
||||
|
||||
fn select_around_parentheses_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void {
|
||||
return try select_bracket_textobject(root, cursel, metrics, "(", ")", .around);
|
||||
return try select_scope_textobject(root, cursel, metrics, "(", ")", .around);
|
||||
}
|
||||
|
||||
fn select_inside_square_brackets_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void {
|
||||
return try select_bracket_textobject(root, cursel, metrics, "[", "]", .inside);
|
||||
return try select_scope_textobject(root, cursel, metrics, "[", "]", .inside);
|
||||
}
|
||||
|
||||
fn select_around_square_brackets_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void {
|
||||
return try select_bracket_textobject(root, cursel, metrics, "[", "]", .around);
|
||||
return try select_scope_textobject(root, cursel, metrics, "[", "]", .around);
|
||||
}
|
||||
|
||||
fn select_inside_braces_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void {
|
||||
return try select_bracket_textobject(root, cursel, metrics, "{", "}", .inside);
|
||||
return try select_scope_textobject(root, cursel, metrics, "{", "}", .inside);
|
||||
}
|
||||
|
||||
fn select_around_braces_textobject(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void {
|
||||
return try select_bracket_textobject(root, cursel, metrics, "{", "}", .around);
|
||||
return try select_scope_textobject(root, cursel, metrics, "{", "}", .around);
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
const current = cursel.cursor;
|
||||
var prev = cursel.cursor;
|
||||
var next = cursel.cursor;
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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 {};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue