tui/editor.zig: add disable_selection, and make check_selection play nice with inclusive selections

This commit is contained in:
Meredith Oleander 2025-01-22 18:47:55 +11:00
parent 80c8795c3b
commit a0f8d33781

View file

@ -130,12 +130,48 @@ pub const CurSel = struct {
return res; return res;
} }
fn check_selection(self: *Self) void { fn disable_selection(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) void {
if (self.selection) |sel| if (sel.empty()) { switch (tui.current().get_selection_style()) {
.normal => self.disable_selection_normal(),
.inclusive => self.disable_selection_inclusive(root, metrics),
}
}
fn disable_selection_normal(self: *Self) void {
self.selection = null; self.selection = null;
}
fn disable_selection_inclusive(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) void {
if (self.selection) |sel| {
if (!sel.is_reversed()) self.cursor.move_left(root, metrics) catch {};
self.selection = null;
}
}
fn check_selection(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) void {
switch (tui.current().get_selection_style()) {
.normal => self.check_selection_normal(),
.inclusive => self.check_selection_inclusive(root, metrics),
}
}
fn check_selection_normal(self: *Self) void {
if (self.selection) |sel| if (sel.empty()) {
self.disable_selection_normal();
}; };
} }
fn check_selection_inclusive(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) void {
if (self.selection) |sel| if (sel.empty()) {
self.disable_selection_inclusive(root, metrics);
};
// if (self.selection) |*sel| {
// var temp = sel;
// if (!temp.is_reversed()) temp.end.move_left(root, metrics) catch {};
// if (temp.empty()) self.disable_selection_inclusive(root, metrics);
// }
}
fn expand_selection_to_line(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) !*Selection { fn expand_selection_to_line(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) !*Selection {
const sel = try self.enable_selection(root, metrics); const sel = try self.enable_selection(root, metrics);
sel.normalize(); sel.normalize();
@ -1603,7 +1639,7 @@ pub const Editor = struct {
fn cancel_all_selections(self: *Self) void { fn cancel_all_selections(self: *Self) void {
var primary = self.get_primary().*; var primary = self.get_primary().*;
primary.selection = null; primary.disable_selection(self.buf_root() catch return, self.metrics);
self.cursels.clearRetainingCapacity(); self.cursels.clearRetainingCapacity();
self.cursels.addOneAssumeCapacity().* = primary; self.cursels.addOneAssumeCapacity().* = primary;
for (self.matches.items) |*match_| if (match_.*) |*match| { for (self.matches.items) |*match_| if (match_.*) |*match| {
@ -1632,7 +1668,7 @@ pub const Editor = struct {
fn with_cursors_const(self: *Self, root: Buffer.Root, move: cursor_operator_const) error{Stop}!void { fn with_cursors_const(self: *Self, root: Buffer.Root, move: cursor_operator_const) error{Stop}!void {
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| { for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
cursel.selection = null; cursel.disable_selection(root, self.metrics);
try with_cursor_const(root, move, cursel, self.metrics); try with_cursor_const(root, move, cursel, self.metrics);
}; };
self.collapse_cursors(); self.collapse_cursors();
@ -1644,7 +1680,7 @@ pub const Editor = struct {
fn with_cursors_const_arg(self: *Self, root: Buffer.Root, move: cursor_operator_const_arg, ctx: Context) error{Stop}!void { fn with_cursors_const_arg(self: *Self, root: Buffer.Root, move: cursor_operator_const_arg, ctx: Context) error{Stop}!void {
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| { for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
cursel.selection = null; cursel.disable_selection(root, self.metrics);
try with_cursor_const_arg(root, move, cursel, ctx, self.metrics); try with_cursor_const_arg(root, move, cursel, ctx, self.metrics);
}; };
self.collapse_cursors(); self.collapse_cursors();
@ -1671,7 +1707,7 @@ pub const Editor = struct {
fn with_cursors(self: *Self, root_: Buffer.Root, move: cursor_operator, allocator: Allocator) error{Stop}!Buffer.Root { fn with_cursors(self: *Self, root_: Buffer.Root, move: cursor_operator, allocator: Allocator) error{Stop}!Buffer.Root {
var root = root_; var root = root_;
for (self.cursels.items) |*cursel| { for (self.cursels.items) |*cursel| {
cursel.selection = null; self.selection(root, self.metrics);
root = try with_cursor(root, move, cursel, allocator); root = try with_cursor(root, move, cursel, allocator);
} }
self.collapse_cursors(); self.collapse_cursors();
@ -1682,7 +1718,7 @@ pub const Editor = struct {
const sel = try cursel.enable_selection(root, metrics); const sel = try cursel.enable_selection(root, metrics);
try move(root, &sel.end, metrics); try move(root, &sel.end, metrics);
cursel.cursor = sel.end; cursel.cursor = sel.end;
cursel.check_selection(); cursel.check_selection(root, metrics);
} }
fn with_selections_const(self: *Self, root: Buffer.Root, move: cursor_operator_const) error{Stop}!void { fn with_selections_const(self: *Self, root: Buffer.Root, move: cursor_operator_const) error{Stop}!void {
@ -1699,7 +1735,7 @@ pub const Editor = struct {
const sel = try cursel.enable_selection(root, metrics); const sel = try cursel.enable_selection(root, metrics);
try move(root, &sel.end, ctx, metrics); try move(root, &sel.end, ctx, metrics);
cursel.cursor = sel.end; cursel.cursor = sel.end;
cursel.check_selection(); cursel.check_selection(root, metrics);
} }
fn with_selections_const_arg(self: *Self, root: Buffer.Root, move: cursor_operator_const_arg, ctx: Context) error{Stop}!void { fn with_selections_const_arg(self: *Self, root: Buffer.Root, move: cursor_operator_const_arg, ctx: Context) error{Stop}!void {
@ -1796,7 +1832,7 @@ pub const Editor = struct {
var sel: Selection = cursel.selection orelse return error.Stop; var sel: Selection = cursel.selection orelse return error.Stop;
sel.normalize(); sel.normalize();
cursel.cursor = sel.begin; cursel.cursor = sel.begin;
cursel.selection = null; cursel.disable_selection(root, self.metrics);
var size: usize = 0; var size: usize = 0;
const root_ = try root.delete_range(sel, allocator, &size, self.metrics); const root_ = try root.delete_range(sel, allocator, &size, self.metrics);
self.nudge_delete(sel, cursel, size); self.nudge_delete(sel, cursel, size);
@ -2032,7 +2068,7 @@ pub const Editor = struct {
self.cancel_all_selections(); self.cancel_all_selections();
} }
const primary = self.get_primary(); const primary = self.get_primary();
primary.selection = null; primary.disable_selection(root, self.metrics);
self.selection_mode = .char; self.selection_mode = .char;
try self.send_editor_jump_source(); try self.send_editor_jump_source();
primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return; primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return;
@ -2043,9 +2079,9 @@ pub const Editor = struct {
pub fn primary_double_click(self: *Self, y: c_int, x: c_int) !void { pub fn primary_double_click(self: *Self, y: c_int, x: c_int) !void {
const primary = self.get_primary(); const primary = self.get_primary();
primary.selection = null;
self.selection_mode = .word;
const root = self.buf_root() catch return; const root = self.buf_root() catch return;
primary.disable_selection(root, self.metrics);
self.selection_mode = .word;
primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return; primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return;
_ = try self.select_word_at_cursor(primary); _ = try self.select_word_at_cursor(primary);
self.clamp_mouse(); self.clamp_mouse();
@ -2053,9 +2089,9 @@ pub const Editor = struct {
pub fn primary_triple_click(self: *Self, y: c_int, x: c_int) !void { pub fn primary_triple_click(self: *Self, y: c_int, x: c_int) !void {
const primary = self.get_primary(); const primary = self.get_primary();
primary.selection = null;
self.selection_mode = .line;
const root = self.buf_root() catch return; const root = self.buf_root() catch return;
primary.disable_selection(root, self.metrics);
self.selection_mode = .line;
primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return; primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return;
try self.select_line_at_cursor(primary); try self.select_line_at_cursor(primary);
self.clamp_mouse(); self.clamp_mouse();
@ -2082,7 +2118,7 @@ pub const Editor = struct {
}, },
} }
primary.cursor = sel.end; primary.cursor = sel.end;
primary.check_selection(); primary.check_selection(root, self.metrics);
self.clamp_mouse(); self.clamp_mouse();
} }
@ -2758,7 +2794,7 @@ pub const Editor = struct {
fn dupe_cursel_up(self: *Self, root_: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root { fn dupe_cursel_up(self: *Self, root_: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root {
var root = root_; var root = root_;
const sel: Selection = if (cursel.selection) |sel_| sel_ else Selection.line_from_cursor(cursel.cursor, root, self.metrics); const sel: Selection = if (cursel.selection) |sel_| sel_ else Selection.line_from_cursor(cursel.cursor, root, self.metrics);
cursel.selection = null; cursel.disable_selection(root, self.metrics);
var sfa = std.heap.stackFallback(4096, self.allocator); var sfa = std.heap.stackFallback(4096, self.allocator);
const text = copy_selection(root, sel, sfa.get(), self.metrics) catch return error.Stop; const text = copy_selection(root, sel, sfa.get(), self.metrics) catch return error.Stop;
defer allocator.free(text); defer allocator.free(text);
@ -2780,7 +2816,7 @@ pub const Editor = struct {
fn dupe_cursel_down(self: *Self, root_: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root { fn dupe_cursel_down(self: *Self, root_: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root {
var root = root_; var root = root_;
const sel: Selection = if (cursel.selection) |sel_| sel_ else Selection.line_from_cursor(cursel.cursor, root, self.metrics); const sel: Selection = if (cursel.selection) |sel_| sel_ else Selection.line_from_cursor(cursel.cursor, root, self.metrics);
cursel.selection = null; cursel.disable_selection(root, self.metrics);
var sfa = std.heap.stackFallback(4096, self.allocator); var sfa = std.heap.stackFallback(4096, self.allocator);
const text = copy_selection(root, sel, sfa.get(), self.metrics) catch return error.Stop; const text = copy_selection(root, sel, sfa.get(), self.metrics) catch return error.Stop;
defer allocator.free(text); defer allocator.free(text);
@ -3248,7 +3284,7 @@ pub const Editor = struct {
fn select_word_at_cursor(self: *Self, cursel: *CurSel) !*Selection { fn select_word_at_cursor(self: *Self, cursel: *CurSel) !*Selection {
const root = try self.buf_root(); const root = try self.buf_root();
const sel = try cursel.enable_selection(root, self.metrics); const sel = try cursel.enable_selection(root, self.metrics);
defer cursel.check_selection(); defer cursel.check_selection(root, self.metrics);
sel.normalize(); sel.normalize();
try move_cursor_word_begin(root, &sel.begin, self.metrics); try move_cursor_word_begin(root, &sel.begin, self.metrics);
try move_cursor_word_end(root, &sel.end, self.metrics); try move_cursor_word_end(root, &sel.end, self.metrics);
@ -3298,7 +3334,7 @@ pub const Editor = struct {
} }
fn select_node_at_cursor(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { fn select_node_at_cursor(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void {
cursel.selection = null; cursel.disable_selection(root, self.metrics);
const sel = (try cursel.enable_selection(root, self.metrics)).*; const sel = (try cursel.enable_selection(root, self.metrics)).*;
return cursel.select_node(try self.node_at_selection(sel, root, metrics), root, metrics); return cursel.select_node(try self.node_at_selection(sel, root, metrics), root, metrics);
} }
@ -3316,7 +3352,7 @@ pub const Editor = struct {
try self.send_editor_jump_source(); try self.send_editor_jump_source();
const root = try self.buf_root(); const root = try self.buf_root();
const cursel = self.get_primary(); const cursel = self.get_primary();
cursel.check_selection(); cursel.check_selection(root, self.metrics);
try if (cursel.selection) |_| try if (cursel.selection) |_|
self.expand_selection_to_parent_node(root, cursel, self.metrics) self.expand_selection_to_parent_node(root, cursel, self.metrics)
else else
@ -3350,7 +3386,7 @@ pub const Editor = struct {
try self.send_editor_jump_source(); try self.send_editor_jump_source();
const root = try self.buf_root(); const root = try self.buf_root();
const cursel = self.get_primary(); const cursel = self.get_primary();
cursel.check_selection(); cursel.check_selection(root, self.metrics);
if (cursel.selection) |_| if (cursel.selection) |_|
try if (unnamed) try if (unnamed)
self.shrink_selection_to_child_node(root, cursel, self.metrics) self.shrink_selection_to_child_node(root, cursel, self.metrics)
@ -3385,7 +3421,7 @@ pub const Editor = struct {
try self.send_editor_jump_source(); try self.send_editor_jump_source();
const root = try self.buf_root(); const root = try self.buf_root();
const cursel = self.get_primary(); const cursel = self.get_primary();
cursel.check_selection(); cursel.check_selection(root, self.metrics);
if (cursel.selection) |_| if (cursel.selection) |_|
try if (unnamed) try if (unnamed)
self.select_next_sibling_node(root, cursel, self.metrics) self.select_next_sibling_node(root, cursel, self.metrics)
@ -3420,7 +3456,7 @@ pub const Editor = struct {
try self.send_editor_jump_source(); try self.send_editor_jump_source();
const root = try self.buf_root(); const root = try self.buf_root();
const cursel = self.get_primary(); const cursel = self.get_primary();
cursel.check_selection(); cursel.check_selection(root, self.metrics);
if (cursel.selection) |_| if (cursel.selection) |_|
try if (unnamed) try if (unnamed)
self.select_prev_sibling_node(root, cursel, self.metrics) self.select_prev_sibling_node(root, cursel, self.metrics)