diff --git a/build.zig b/build.zig index 05582a5..b400a66 100644 --- a/build.zig +++ b/build.zig @@ -370,6 +370,7 @@ pub fn build_exe( .{ .name = "input", .module = input_mod }, .{ .name = "thespian", .module = thespian_mod }, .{ .name = "log", .module = log_mod }, + .{ .name = "Buffer", .module = Buffer_mod }, }, }); diff --git a/src/buffer/Selection.zig b/src/buffer/Selection.zig index e7c0c7a..415ddd4 100644 --- a/src/buffer/Selection.zig +++ b/src/buffer/Selection.zig @@ -6,6 +6,8 @@ end: Cursor = Cursor{}, const Self = @This(); +pub const Style = enum { normal, inclusive }; + pub inline fn eql(self: Self, other: Self) bool { return self.begin.eql(other.begin) and self.end.eql(other.end); } diff --git a/src/keybind/builtin/helix.json b/src/keybind/builtin/helix.json index 7f912a5..d17fb85 100644 --- a/src/keybind/builtin/helix.json +++ b/src/keybind/builtin/helix.json @@ -8,6 +8,7 @@ "name": "NOR", "line_numbers": "relative", "cursor": "block", + "selection": "inclusive", "press": [ ["ctrl+b", "move_scroll_page_up"], ["ctrl+f", "move_scroll_page_down"], @@ -252,6 +253,7 @@ "name": "SEL", "line_numbers": "relative", "cursor": "block", + "selection": "inclusive", "press": [ ["ctrl+b", "select_page_up"], ["ctrl+f", "select_page_down"], diff --git a/src/keybind/keybind.zig b/src/keybind/keybind.zig index b820d66..880b7d6 100644 --- a/src/keybind/keybind.zig +++ b/src/keybind/keybind.zig @@ -13,6 +13,7 @@ const input = @import("input"); const command = @import("command"); const EventHandler = @import("EventHandler"); const KeyEvent = input.KeyEvent; +const SelectionStyle = @import("Buffer").Selection.Style; const parse_flow = @import("parse_flow.zig"); const parse_vim = @import("parse_vim.zig"); @@ -59,6 +60,7 @@ const Handler = struct { .name = self.bindings.name, .line_numbers = self.bindings.line_numbers, .cursor_shape = self.bindings.cursor_shape, + .selection_style = self.bindings.selection_style, }; } pub fn deinit(self: *@This()) void { @@ -79,6 +81,7 @@ pub const Mode = struct { line_numbers: LineNumbers = .absolute, keybind_hints: *const KeybindHints, cursor_shape: ?CursorShape = null, + selection_style: SelectionStyle, pub fn deinit(self: *Mode) void { self.allocator.free(self.mode); @@ -364,14 +367,15 @@ const BindingSet = struct { name: []const u8, line_numbers: LineNumbers = .absolute, cursor_shape: ?CursorShape = null, + selection_style: SelectionStyle, insert_command: []const u8 = "", hints_map: KeybindHints = .{}, const KeySyntax = enum { flow, vim }; const OnMatchFailure = enum { insert, ignore }; - fn load(allocator: std.mem.Allocator, namespace_name: []const u8, mode_bindings: std.json.Value, fallback: ?*const BindingSet, siblings: *Namespace) (error{OutOfMemory} || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError)!@This() { - var self: @This() = .{ .name = undefined }; + fn load(allocator: std.mem.Allocator, namespace_name: []const u8, mode_bindings: std.json.Value, fallback: ?*const BindingSet, namespace: *Namespace) (error{OutOfMemory} || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError)!@This() { + var self: @This() = .{ .name = undefined, .selection_style = undefined }; const JsonConfig = struct { press: []const []const std.json.Value = &[_][]std.json.Value{}, @@ -382,6 +386,7 @@ const BindingSet = struct { line_numbers: LineNumbers = .absolute, cursor: ?CursorShape = null, inherit: ?[]const u8 = null, + selection: ?SelectionStyle = null, }; const parsed = try std.json.parseFromValue(JsonConfig, allocator, mode_bindings, .{ .ignore_unknown_fields = true, @@ -392,10 +397,11 @@ const BindingSet = struct { self.name = try allocator.dupe(u8, parsed.value.name orelse namespace_name); self.line_numbers = parsed.value.line_numbers; self.cursor_shape = parsed.value.cursor; + self.selection_style = parsed.value.selection orelse .normal; try self.load_event(allocator, &self.press, input.event.press, parsed.value.press); try self.load_event(allocator, &self.release, input.event.release, parsed.value.release); if (parsed.value.inherit) |sibling_fallback| { - if (siblings.get_mode(sibling_fallback)) |sib| { + if (namespace.get_mode(sibling_fallback)) |sib| { for (sib.press.items) |binding| try append_if_not_match(allocator, &self.press, binding); for (sib.release.items) |binding| try append_if_not_match(allocator, &self.release, binding); } @@ -467,7 +473,7 @@ const BindingSet = struct { } fn copy(allocator: std.mem.Allocator, fallback: *const BindingSet) error{OutOfMemory}!@This() { - var self: @This() = .{ .name = fallback.name }; + var self: @This() = .{ .name = fallback.name, .selection_style = fallback.selection_style }; self.on_match_failure = fallback.on_match_failure; for (fallback.press.items) |binding| try self.press.append(allocator, binding); for (fallback.release.items) |binding| try self.release.append(allocator, binding); diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 0c3a598..62e4f45 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -97,7 +97,14 @@ pub const CurSel = struct { self.* = .{}; } - fn enable_selection(self: *Self) *Selection { + fn enable_selection(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) !*Selection { + return switch (tui.current().get_selection_style()) { + .normal => self.enable_selection_normal(), + .inclusive => try self.enable_selection_inclusive(root, metrics), + }; + } + + fn enable_selection_normal(self: *Self) *Selection { return if (self.selection) |*sel| sel else cod: { @@ -106,7 +113,7 @@ pub const CurSel = struct { }; } - fn enable_selection_helix(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) !*Selection { + fn enable_selection_inclusive(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) !*Selection { return if (self.selection) |*sel| sel else cod: { @@ -116,7 +123,7 @@ pub const CurSel = struct { }; } - fn get_helix_render_cursor(self: *const Self, root: Buffer.Root, metrics: Buffer.Metrics) !Cursor { + fn to_inclusive_cursor(self: *const Self, root: Buffer.Root, metrics: Buffer.Metrics) !Cursor { var res = self.cursor; if (self.selection) |sel| if (!sel.is_reversed()) try res.move_left(root, metrics); @@ -129,8 +136,8 @@ pub const CurSel = struct { }; } - fn expand_selection_to_line(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) *Selection { - const sel = self.enable_selection(); + fn expand_selection_to_line(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) !*Selection { + const sel = try self.enable_selection(root, metrics); sel.normalize(); sel.begin.move_begin(); if (!(sel.end.row > sel.begin.row and sel.end.col == 0)) { @@ -281,7 +288,6 @@ pub const Editor = struct { render_whitespace: WhitespaceMode, indent_size: usize, tab_width: usize, - enable_helix_selection: bool = false, last: struct { root: ?Buffer.Root = null, @@ -381,7 +387,6 @@ pub const Editor = struct { const frame_rate = tp.env.get().num("frame-rate"); const indent_size = tui.current().config.indent_size; const tab_width = tui.current().config.tab_width; - const helix_mode = std.mem.eql(u8, tui.current().config.input_mode, "helix"); self.* = Self{ .allocator = allocator, .plane = n, @@ -401,7 +406,6 @@ pub const Editor = struct { .enable_terminal_cursor = tui.current().config.enable_terminal_cursor, .render_whitespace = from_whitespace_mode(tui.current().config.whitespace_mode), .diagnostics = std.ArrayList(Diagnostic).init(allocator), - .enable_helix_selection = helix_mode, }; } @@ -961,35 +965,28 @@ pub const Editor = struct { _ = root.walk_from_line_begin_const(self.view.row, ctx.walker, &ctx_, self.metrics) catch {}; } self.render_syntax(theme, cache, root) catch {}; - if (self.enable_helix_selection) - self.render_cursors_helix(theme, ctx_.cell_map) catch {} - else - self.render_cursors(theme, ctx_.cell_map) catch {}; + self.render_cursors(theme, ctx_.cell_map) catch {}; self.render_whitespace_map(theme, ctx_.cell_map) catch {}; self.render_diagnostics(theme, hl_row, ctx_.cell_map) catch {}; } fn render_cursors(self: *Self, theme: *const Widget.Theme, cell_map: CellMap) !void { + const style = tui.current().get_selection_style(); const frame = tracy.initZone(@src(), .{ .name = "editor render cursors" }); defer frame.deinit(); - for (self.cursels.items[0 .. self.cursels.items.len - 1]) |*cursel_| if (cursel_.*) |*cursel| - try self.render_cursor_secondary(&cursel.cursor, theme, cell_map); - try self.render_cursor_primary(&self.get_primary().cursor, theme, cell_map); + for (self.cursels.items[0 .. self.cursels.items.len - 1]) |*cursel_| if (cursel_.*) |*cursel| { + const cursor = try self.get_rendered_cursor(style, cursel); + try self.render_cursor_secondary(&cursor, theme, cell_map); + }; + const cursor = try self.get_rendered_cursor(style, self.get_primary()); + try self.render_cursor_primary(&cursor, theme, cell_map); } - fn render_cursors_helix(self: *Self, theme: *const Widget.Theme, cell_map: CellMap) !void { - // const frame = tracy.initZone(@src(), .{ .name = "editor render cursors" }); - // defer frame.deinit(); - const root = self.buf_root() catch return; - for (self.cursels.items[0 .. self.cursels.items.len - 1]) |*cursel_| { - if (cursel_.*) |cursel| { - const cursor = try cursel.get_helix_render_cursor(root, self.metrics); - try self.render_cursor_secondary(&cursor, theme, cell_map); - } - } - var primary = self.get_primary(); - const cursor = try primary.get_helix_render_cursor(root, self.metrics); - try self.render_cursor_primary(&cursor, theme, cell_map); + fn get_rendered_cursor(self: *Self, style: anytype, cursel: anytype) !Cursor { + return switch (style) { + .normal => cursel.cursor, + .inclusive => try cursel.to_inclusive_cursor(try self.buf_root(), self.metrics), + }; } fn render_cursor_primary(self: *Self, cursor: *const Cursor, theme: *const Widget.Theme, cell_map: CellMap) !void { @@ -1701,8 +1698,8 @@ pub const Editor = struct { return root; } - fn with_selection_const(root: Buffer.Root, move: cursor_operator_const, cursel: *CurSel, metrics: Buffer.Metrics, helix_cursor: bool) error{Stop}!void { - const sel = if (helix_cursor) cursel.enable_selection_helix(root, metrics) catch return else cursel.enable_selection(); + fn with_selection_const(root: Buffer.Root, move: cursor_operator_const, cursel: *CurSel, metrics: Buffer.Metrics) error{Stop}!void { + const sel = try cursel.enable_selection(root, metrics); try move(root, &sel.end, metrics); cursel.cursor = sel.end; cursel.check_selection(); @@ -1711,15 +1708,15 @@ pub const Editor = struct { fn with_selections_const(self: *Self, root: Buffer.Root, move: cursor_operator_const) error{Stop}!void { var someone_stopped = false; for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| - with_selection_const(root, move, cursel, self.metrics, self.enable_helix_selection) catch { + with_selection_const(root, move, cursel, self.metrics) catch { someone_stopped = true; }; self.collapse_cursors(); return if (someone_stopped) error.Stop else {}; } - fn with_selection_const_arg(root: Buffer.Root, move: cursor_operator_const_arg, cursel: *CurSel, ctx: Context, metrics: Buffer.Metrics, helix_cursor: bool) error{Stop}!void { - const sel = if (helix_cursor) cursel.enable_selection_helix(root, metrics) catch return else cursel.enable_selection(); + fn with_selection_const_arg(root: Buffer.Root, move: cursor_operator_const_arg, cursel: *CurSel, ctx: Context, metrics: Buffer.Metrics) error{Stop}!void { + const sel = try cursel.enable_selection(root, metrics); try move(root, &sel.end, ctx, metrics); cursel.cursor = sel.end; cursel.check_selection(); @@ -1728,15 +1725,15 @@ pub const Editor = struct { fn with_selections_const_arg(self: *Self, root: Buffer.Root, move: cursor_operator_const_arg, ctx: Context) error{Stop}!void { var someone_stopped = false; for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| - with_selection_const_arg(root, move, cursel, ctx, self.metrics, self.enable_helix_selection) catch { + with_selection_const_arg(root, move, cursel, ctx, self.metrics) catch { someone_stopped = true; }; self.collapse_cursors(); return if (someone_stopped) error.Stop else {}; } - fn with_selection_and_view_const(root: Buffer.Root, move: cursor_view_operator_const, cursel: *CurSel, view: *const View, metrics: Buffer.Metrics, helix_cursor: bool) error{Stop}!void { - const sel = if (helix_cursor) cursel.enable_selection_helix(root, metrics) catch return else cursel.enable_selection(); + fn with_selection_and_view_const(root: Buffer.Root, move: cursor_view_operator_const, cursel: *CurSel, view: *const View, metrics: Buffer.Metrics) error{Stop}!void { + const sel = try cursel.enable_selection(root, metrics); try move(root, &sel.end, view, metrics); cursel.cursor = sel.end; } @@ -1744,7 +1741,7 @@ pub const Editor = struct { fn with_selections_and_view_const(self: *Self, root: Buffer.Root, move: cursor_view_operator_const, view: *const View) error{Stop}!void { var someone_stopped = false; for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| - with_selection_and_view_const(root, move, cursel, view, self.metrics, self.enable_helix_selection) catch { + with_selection_and_view_const(root, move, cursel, view, self.metrics) catch { someone_stopped = true; }; self.collapse_cursors(); @@ -1835,7 +1832,7 @@ pub const Editor = struct { all_stop = false; continue; } - with_selection_const(root, move, cursel, self.metrics, self.enable_helix_selection) catch continue; + with_selection_const(root, move, cursel, self.metrics) catch continue; root = self.delete_selection(root, cursel, allocator) catch continue; all_stop = false; }; @@ -2088,20 +2085,20 @@ pub const Editor = struct { const y_ = if (y < 0) 0 else y; const x_ = if (x < 0) 0 else x; const primary = self.get_primary(); - const sel = primary.enable_selection(); const root = self.buf_root() catch return; + const sel = primary.enable_selection(root, self.metrics) catch return; sel.end.move_abs(root, &self.view, @intCast(y_), @intCast(x_), self.metrics) catch return; switch (self.selection_mode) { .char => {}, .word => if (sel.begin.right_of(sel.end)) - with_selection_const(root, move_cursor_word_begin, primary, self.metrics, self.enable_helix_selection) catch return + with_selection_const(root, move_cursor_word_begin, primary, self.metrics) catch return else - with_selection_const(root, move_cursor_word_end, primary, self.metrics, self.enable_helix_selection) catch return, + with_selection_const(root, move_cursor_word_end, primary, self.metrics) catch return, .line => if (sel.begin.right_of(sel.end)) - with_selection_const(root, move_cursor_begin, primary, self.metrics, self.enable_helix_selection) catch return + with_selection_const(root, move_cursor_begin, primary, self.metrics) catch return else { - with_selection_const(root, move_cursor_end, primary, self.metrics, self.enable_helix_selection) catch return; - with_selection_const(root, move_cursor_right, primary, self.metrics, self.enable_helix_selection) catch return; + with_selection_const(root, move_cursor_end, primary, self.metrics) catch return; + with_selection_const(root, move_cursor_right, primary, self.metrics) catch return; }, } primary.cursor = sel.end; @@ -2321,7 +2318,7 @@ pub const Editor = struct { var root = b.root; if (self.cursels.items.len == 1) if (primary.selection) |_| {} else { - const sel = primary.enable_selection(); + const sel = primary.enable_selection(root, self.metrics) catch return; try move_cursor_begin(root, &sel.begin, self.metrics); try move_cursor_end(root, &sel.end, self.metrics); try move_cursor_right(root, &sel.end, self.metrics); @@ -2350,7 +2347,7 @@ pub const Editor = struct { var text = std.ArrayList(u8).init(self.allocator); if (self.cursels.items.len == 1) if (primary.selection) |_| {} else { - const sel = primary.enable_selection(); + const sel = primary.enable_selection(root, self.metrics) catch return; try move_cursor_begin(root, &sel.begin, self.metrics); try move_cursor_end(root, &sel.end, self.metrics); try move_cursor_right(root, &sel.end, self.metrics); @@ -2697,7 +2694,7 @@ pub const Editor = struct { pub const add_cursor_all_matches_meta = .{ .description = "Add cursors to all highlighted matches" }; fn add_cursors_to_cursel_line_ends(self: *Self, root: Buffer.Root, cursel: *CurSel) !void { - const sel = if (self.enable_helix_selection) cursel.enable_selection_helix(root, self.metrics) catch return else cursel.enable_selection(); + const sel = try cursel.enable_selection(root, self.metrics); sel.normalize(); var row = sel.begin.row; while (row <= sel.end.row) : (row += 1) { @@ -2727,7 +2724,7 @@ pub const Editor = struct { fn pull_cursel_up(self: *Self, root_: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root { var root = root_; const saved = cursel.*; - const sel = cursel.expand_selection_to_line(root, self.metrics); + const sel = cursel.expand_selection_to_line(root, self.metrics) catch return error.Stop; var sfa = std.heap.stackFallback(4096, self.allocator); const cut_text = copy_selection(root, sel.*, sfa.get(), self.metrics) catch return error.Stop; defer allocator.free(cut_text); @@ -2754,7 +2751,7 @@ pub const Editor = struct { fn pull_cursel_down(self: *Self, root_: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root { var root = root_; const saved = cursel.*; - const sel = cursel.expand_selection_to_line(root, self.metrics); + const sel = cursel.expand_selection_to_line(root, self.metrics) catch return error.Stop; var sfa = std.heap.stackFallback(4096, self.allocator); const cut_text = copy_selection(root, sel.*, sfa.get(), self.metrics) catch return error.Stop; defer allocator.free(cut_text); @@ -2824,7 +2821,7 @@ pub const Editor = struct { fn toggle_cursel_prefix(self: *Self, root_: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root { var root = root_; const saved = cursel.*; - const sel = cursel.expand_selection_to_line(root, self.metrics); + const sel = cursel.expand_selection_to_line(root, self.metrics) catch return error.Stop; var sfa = std.heap.stackFallback(4096, self.allocator); const alloc = sfa.get(); const text = copy_selection(root, sel.*, alloc, self.metrics) catch return error.Stop; @@ -2895,7 +2892,7 @@ pub const Editor = struct { if (first == 0) return error.Stop; const off = first % self.indent_size; const cols = if (off == 0) self.indent_size else off; - const sel = cursel.enable_selection(); + const sel = cursel.enable_selection(root, self.metrics) catch return error.Stop; sel.begin.move_begin(); try sel.end.move_to(root, sel.end.row, cols, self.metrics); var saved = false; @@ -3259,8 +3256,8 @@ pub const Editor = struct { try self.send_editor_jump_source(); self.cancel_all_selections(); const primary = self.get_primary(); - const sel = primary.enable_selection(); const root = try self.buf_root(); + const sel = try primary.enable_selection(root, self.metrics); try expand_selection_to_all(root, sel, self.metrics); primary.cursor = sel.end; self.clamp(); @@ -3270,7 +3267,7 @@ pub const Editor = struct { fn select_word_at_cursor(self: *Self, cursel: *CurSel) !*Selection { const root = try self.buf_root(); - const sel = cursel.enable_selection(); + const sel = try cursel.enable_selection(root, self.metrics); defer cursel.check_selection(); sel.normalize(); try move_cursor_word_begin(root, &sel.begin, self.metrics); @@ -3281,7 +3278,7 @@ pub const Editor = struct { fn select_line_at_cursor(self: *Self, cursel: *CurSel) !void { const root = try self.buf_root(); - const sel = cursel.enable_selection(); + const sel = try cursel.enable_selection(root, self.metrics); sel.normalize(); try move_cursor_begin(root, &sel.begin, self.metrics); try move_cursor_end(root, &sel.end, self.metrics); @@ -3322,12 +3319,12 @@ pub const Editor = struct { fn select_node_at_cursor(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { cursel.selection = null; - const sel = cursel.enable_selection().*; + const sel = (try cursel.enable_selection(root, self.metrics)).*; return cursel.select_node(try self.node_at_selection(sel, root, metrics), root, metrics); } fn expand_selection_to_parent_node(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - const sel = cursel.enable_selection().*; + const sel = (try cursel.enable_selection(root, metrics)).*; const node = try self.node_at_selection(sel, root, metrics); if (node.isNull()) return error.Stop; const parent = node.getParent(); @@ -3350,7 +3347,7 @@ pub const Editor = struct { pub const expand_selection_meta = .{ .description = "Expand selection to AST parent node" }; fn shrink_selection_to_child_node(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - const sel = cursel.enable_selection().*; + const sel = (try cursel.enable_selection(root, metrics)).*; const node = try self.node_at_selection(sel, root, metrics); if (node.isNull() or node.getChildCount() == 0) return error.Stop; const child = node.getChild(0); @@ -3359,7 +3356,7 @@ pub const Editor = struct { } fn shrink_selection_to_named_child_node(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - const sel = cursel.enable_selection().*; + const sel = (try cursel.enable_selection(root, metrics)).*; const node = try self.node_at_selection(sel, root, metrics); if (node.isNull() or node.getNamedChildCount() == 0) return error.Stop; const child = node.getNamedChild(0); @@ -3385,7 +3382,7 @@ pub const Editor = struct { pub const shrink_selection_meta = .{ .description = "Shrink selection to first AST child node" }; fn select_next_sibling_node(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - const sel = cursel.enable_selection().*; + const sel = (try cursel.enable_selection(root, metrics)).*; const node = try self.node_at_selection(sel, root, metrics); if (node.isNull()) return error.Stop; const sibling = syntax.Node.externs.ts_node_next_sibling(node); @@ -3394,7 +3391,7 @@ pub const Editor = struct { } fn select_next_named_sibling_node(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - const sel = cursel.enable_selection().*; + const sel = (try cursel.enable_selection(root, metrics)).*; const node = try self.node_at_selection(sel, root, metrics); if (node.isNull()) return error.Stop; const sibling = syntax.Node.externs.ts_node_next_named_sibling(node); @@ -3420,7 +3417,7 @@ pub const Editor = struct { pub const select_next_sibling_meta = .{ .description = "Move selection to next AST sibling node" }; fn select_prev_sibling_node(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - const sel = cursel.enable_selection().*; + const sel = (try cursel.enable_selection(root, metrics)).*; const node = try self.node_at_selection(sel, root, metrics); if (node.isNull()) return error.Stop; const sibling = syntax.Node.externs.ts_node_prev_sibling(node); @@ -3429,7 +3426,7 @@ pub const Editor = struct { } fn select_prev_named_sibling_node(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { - const sel = cursel.enable_selection().*; + const sel = (try cursel.enable_selection(root, metrics)).*; const node = try self.node_at_selection(sel, root, metrics); if (node.isNull()) return error.Stop; const sibling = syntax.Node.externs.ts_node_prev_named_sibling(node); @@ -4603,7 +4600,7 @@ pub const Editor = struct { state.chunks = 1; primary.cursor = state.old_primary.cursor; } else { - const sel = primary.enable_selection(); + const sel = try primary.enable_selection(root, self.metrics); sel.begin = state.begin; sel.end = state.pos.cursor; if (state.old_primary_reversed) sel.reverse(); @@ -4632,7 +4629,7 @@ pub const Editor = struct { var root = root_; const saved = cursel.*; const sel = if (cursel.selection) |*sel| sel else ret: { - var sel = cursel.enable_selection(); + var sel = cursel.enable_selection(root, self.metrics) catch return error.Stop; 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; @@ -4660,7 +4657,7 @@ pub const Editor = struct { var root = root_; const saved = cursel.*; const sel = if (cursel.selection) |*sel| sel else ret: { - var sel = cursel.enable_selection(); + var sel = cursel.enable_selection(root, self.metrics) catch return error.Stop; 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; @@ -4688,7 +4685,7 @@ pub const Editor = struct { var root = root_; var saved = cursel.*; const sel = if (cursel.selection) |*sel| sel else ret: { - var sel = cursel.enable_selection(); + var sel = cursel.enable_selection(root, self.metrics) catch return error.Stop; move_cursor_right(root, &sel.end, self.metrics) catch return error.Stop; saved.cursor = sel.end; break :ret sel; diff --git a/src/tui/tui.zig b/src/tui/tui.zig index cfa83dd..e22fbca 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -951,13 +951,11 @@ const cmds = struct { pub fn enter_helix_mode(_: *Self, _: Ctx) Result { try @import("mode/helix.zig").init(); - if (get_active_editor()) |editor| editor.enable_helix_selection = true; } pub const enter_helix_mode_meta = .{}; pub fn exit_helix_mode(_: *Self, _: Ctx) Result { @import("mode/helix.zig").deinit(); - if (get_active_editor()) |editor| editor.enable_helix_selection = false; } pub const exit_helix_mode_meta = .{}; }; @@ -1174,3 +1172,7 @@ pub fn is_cursor_beam(self: *Self) bool { else => false, }; } + +pub fn get_selection_style(self: *Self) @import("Buffer").Selection.Style { + return if (self.input_mode) |mode| mode.selection_style else .normal; +}