refactor: completely remove inclusive selection mode

Having inclusive mode change a few critical functions behind the sceans
is not a good way to share functionality. Basically every function is
broken in one or the other mode. So we remove it entirely and instead
will rely on different functions for different behaviors.
This commit is contained in:
CJ van den Berg 2025-11-27 17:22:58 +01:00
parent dd88be893e
commit 8d8f4b82cb
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
7 changed files with 75 additions and 111 deletions

View file

@ -115,24 +115,12 @@ pub const CurSel = struct {
self.* = .{};
}
pub fn enable_selection(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) *Selection {
self.selection = self.to_selection(root, metrics);
pub fn enable_selection(self: *Self) *Selection {
self.selection = self.to_selection();
return if (self.selection) |*sel| sel else unreachable;
}
pub fn enable_selection_normal(self: *Self) *Selection {
self.selection = self.to_selection_normal();
return if (self.selection) |*sel| sel else unreachable;
}
fn to_selection(self: *const Self, root: Buffer.Root, metrics: Buffer.Metrics) Selection {
return switch (tui.get_selection_style()) {
.normal => self.to_selection_normal(),
.inclusive => self.to_selection_inclusive(root, metrics),
};
}
fn to_selection_normal(self: *const Self) Selection {
fn to_selection(self: *const Self) Selection {
return if (self.selection) |sel| sel else Selection.from_cursor(&self.cursor);
}
@ -140,7 +128,7 @@ pub const CurSel = struct {
return self.selection orelse Selection.from_cursor_inclusive(&self.cursor, root, metrics);
}
pub fn disable_selection(self: *Self, _: Buffer.Root, _: Buffer.Metrics) void {
pub fn disable_selection(self: *Self) void {
self.selection = null;
}
@ -148,12 +136,12 @@ pub const CurSel = struct {
self.selection = null;
}
pub fn check_selection(self: *Self, _: Buffer.Root, _: Buffer.Metrics) void {
pub fn check_selection(self: *Self) void {
self.selection = if (self.selection) |sel| if (sel.empty()) null else sel else null;
}
fn expand_selection_to_line(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) *Selection {
const sel = self.enable_selection(root, metrics);
const sel = self.enable_selection();
sel.normalize();
sel.begin.move_begin();
if (!(sel.end.row > sel.begin.row and sel.end.col == 0)) {
@ -1883,7 +1871,7 @@ pub const Editor = struct {
fn cancel_all_selections(self: *Self) void {
var primary = self.get_primary().*;
primary.disable_selection(self.buf_root() catch return, self.metrics);
primary.disable_selection();
self.cursels.clearRetainingCapacity();
self.cursels.addOneAssumeCapacity().* = primary;
for (self.matches.items) |*match_| if (match_.*) |*match| {
@ -1937,7 +1925,7 @@ pub const Editor = struct {
fn with_cursors_const_once(self: *Self, root: Buffer.Root, move: cursor_operator_const) error{Stop}!void {
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
cursel.disable_selection(root, self.metrics);
cursel.disable_selection();
try with_cursor_const(root, move, cursel, self.metrics);
};
self.collapse_cursors();
@ -1948,7 +1936,7 @@ pub const Editor = struct {
_ = ctx.args.match(.{tp.extract(&repeat)}) catch false;
while (repeat > 0) : (repeat -= 1) {
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
cursel.disable_selection(root, self.metrics);
cursel.disable_selection();
try with_cursor_const(root, move, cursel, self.metrics);
};
self.collapse_cursors();
@ -1961,7 +1949,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 {
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
cursel.disable_selection(root, self.metrics);
cursel.disable_selection();
try with_cursor_const_arg(root, move, cursel, ctx, self.metrics);
};
self.collapse_cursors();
@ -1986,10 +1974,10 @@ pub const Editor = struct {
}
pub fn with_selection_const(root: Buffer.Root, move: cursor_operator_const, cursel: *CurSel, metrics: Buffer.Metrics) error{Stop}!void {
const sel = cursel.enable_selection(root, metrics);
const sel = cursel.enable_selection();
try move(root, &sel.end, metrics);
cursel.cursor = sel.end;
cursel.check_selection(root, metrics);
cursel.check_selection();
}
pub fn with_selections_const_once(self: *Self, root: Buffer.Root, move: cursor_operator_const) error{Stop}!void {
@ -2018,10 +2006,10 @@ pub const Editor = struct {
}
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 = cursel.enable_selection(root, metrics);
const sel = cursel.enable_selection();
try move(root, &sel.end, ctx, metrics);
cursel.cursor = sel.end;
cursel.check_selection(root, metrics);
cursel.check_selection();
}
fn with_selections_const_arg(self: *Self, root: Buffer.Root, move: cursor_operator_const_arg, ctx: Context) error{Stop}!void {
@ -2035,7 +2023,7 @@ pub const Editor = struct {
}
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 = cursel.enable_selection(root, metrics);
const sel = cursel.enable_selection();
try move(root, &sel.end, view, metrics);
cursel.cursor = sel.end;
}
@ -2500,7 +2488,7 @@ pub const Editor = struct {
self.cancel_all_selections();
}
const primary = self.get_primary();
primary.disable_selection(root, self.metrics);
primary.disable_selection();
self.selection_mode = .char;
try self.send_editor_jump_source();
primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return;
@ -2514,7 +2502,7 @@ pub const Editor = struct {
pub fn primary_double_click(self: *Self, y: c_int, x: c_int) !void {
const primary = self.get_primary();
const root = self.buf_root() catch return;
primary.disable_selection(root, self.metrics);
primary.disable_selection();
self.selection_mode = .word;
primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return;
_ = try self.select_word_at_cursor(primary);
@ -2526,7 +2514,7 @@ pub const Editor = struct {
pub fn primary_triple_click(self: *Self, y: c_int, x: c_int) !void {
const primary = self.get_primary();
const root = self.buf_root() catch return;
primary.disable_selection(root, self.metrics);
primary.disable_selection();
self.selection_mode = .line;
primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return;
try self.select_line_at_cursor(root, primary, .exclude_eol);
@ -2540,7 +2528,7 @@ pub const Editor = struct {
const x_ = if (x < 0) 0 else x;
const primary = self.get_primary();
const root = self.buf_root() catch return;
const sel = primary.enable_selection(root, self.metrics);
const sel = primary.enable_selection();
sel.end.move_abs(root, &self.view, @intCast(y_), @intCast(x_), self.metrics) catch return;
const initial = self.selection_drag_initial orelse sel.*;
switch (self.selection_mode) {
@ -2568,7 +2556,7 @@ pub const Editor = struct {
},
}
primary.cursor = sel.end;
primary.check_selection(root, self.metrics);
primary.check_selection();
self.collapse_cursors();
self.clamp_mouse();
}
@ -2758,7 +2746,7 @@ pub const Editor = struct {
}
pub fn insert(self: *Self, root: Buffer.Root, cursel: *CurSel, s: []const u8, allocator: Allocator) !Buffer.Root {
cursel.check_selection(root, self.metrics);
cursel.check_selection();
var root_ = if (cursel.selection) |_| try self.delete_selection(root, cursel, allocator) else root;
const cursor = &cursel.cursor;
const begin = cursel.cursor;
@ -2911,7 +2899,7 @@ pub const Editor = struct {
const primary = self.get_primary();
const root = self.buf_root() catch return;
if (primary.selection) |_| {} else {
const sel = primary.enable_selection(root, self.metrics);
const sel = primary.enable_selection();
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);
@ -3237,7 +3225,7 @@ pub const Editor = struct {
.left => if (sel.is_reversed()) sel.end else sel.begin,
.right => if (sel.is_reversed()) sel.begin else sel.end,
};
cursel.disable_selection(root, self.metrics);
cursel.disable_selection();
} else {
try with_cursor_const(root, switch (direction) {
.left => move_cursor_left,
@ -3657,7 +3645,7 @@ pub const Editor = struct {
pub const add_cursor_all_matches_meta: 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 = cursel.enable_selection(root, self.metrics);
const sel = cursel.enable_selection();
sel.normalize();
var row = sel.begin.row;
while (row <= sel.end.row) : (row += 1) {
@ -3751,7 +3739,7 @@ pub const Editor = struct {
cursel.cursor = sel.begin;
var add_eol = false;
if (cursel.selection) |_| {
cursel.disable_selection(root, self.metrics);
cursel.disable_selection();
} else {
var test_eof = sel.end;
test_eof.move_right(root, self.metrics) catch { // test for EOF
@ -3786,7 +3774,7 @@ pub const Editor = struct {
cursel.cursor = sel.end;
if (cursel.selection) |_| {
cursel.disable_selection(root, self.metrics);
cursel.disable_selection();
} else {
var test_eof = sel.end;
test_eof.move_right(root, self.metrics) catch { // test for EOF
@ -3840,7 +3828,7 @@ pub const Editor = struct {
cursel.cursor = sel.end;
if (cursel.selection) |_| {
cursel.disable_selection(root, self.metrics);
cursel.disable_selection();
} else {
var test_eof = sel.end;
test_eof.move_right(root, self.metrics) catch { // test for EOF
@ -3944,7 +3932,7 @@ pub const Editor = struct {
if (first == 0) return root;
const off = first % self.indent_size;
const cols = if (off == 0) self.indent_size else off;
const sel = cursel.enable_selection(root, self.metrics);
const sel = cursel.enable_selection();
try sel.begin.move_to(root, sel.begin.row, first, self.metrics);
try sel.end.move_to(root, sel.end.row, first - cols, self.metrics);
var saved = false;
@ -4169,8 +4157,7 @@ pub const Editor = struct {
pub const cancel_meta: Meta = .{ .description = "Cancel current action" };
pub fn enable_selection(self: *Self, _: Context) Result {
const root = try self.buf_root();
_ = self.get_primary().enable_selection(root, self.metrics);
_ = self.get_primary().enable_selection();
}
pub const enable_selection_meta: Meta = .{ .description = "Enable selection" };
@ -4399,7 +4386,7 @@ pub const Editor = struct {
self.cancel_all_selections();
const primary = self.get_primary();
const root = try self.buf_root();
const sel = primary.enable_selection(root, self.metrics);
const sel = primary.enable_selection();
try expand_selection_to_all(root, sel, self.metrics);
primary.cursor = sel.end;
self.clamp();
@ -4409,8 +4396,8 @@ 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(root, self.metrics);
defer cursel.check_selection(root, self.metrics);
const sel = cursel.enable_selection();
defer cursel.check_selection();
sel.normalize();
try move_cursor_word_begin(root, &sel.begin, self.metrics);
move_cursor_word_end(root, &sel.end, self.metrics) catch {};
@ -4419,7 +4406,7 @@ pub const Editor = struct {
}
pub fn select_line_at_cursor(self: *Self, root: Buffer.Root, cursel: *CurSel, mode: enum { include_eol, exclude_eol, hold_cursor }) !void {
const sel = cursel.enable_selection(root, self.metrics);
const sel = cursel.enable_selection();
sel.normalize();
try move_cursor_begin(root, &sel.begin, self.metrics);
move_cursor_end(root, &sel.end, self.metrics) catch {};
@ -4483,12 +4470,12 @@ pub const Editor = struct {
}
fn top_node_at_cursel(self: *const Self, cursel: *const CurSel, root: Buffer.Root, metrics: Buffer.Metrics) error{Stop}!syntax.Node {
const sel = cursel.to_selection(root, metrics);
const sel = cursel.to_selection();
return try self.top_node_at_selection(sel, root, metrics);
}
fn expand_selection_to_parent_node(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void {
const sel = cursel.enable_selection(root, metrics).*;
const sel = cursel.enable_selection().*;
var node = try self.top_node_at_selection(sel, root, metrics);
if (node.isNull()) return error.Stop;
var node_sel = CurSel.selection_from_node(node, root, metrics);
@ -4502,7 +4489,7 @@ pub const Editor = struct {
try self.send_editor_jump_source();
const root = try self.buf_root();
const cursel = self.get_primary();
cursel.check_selection(root, self.metrics);
cursel.check_selection();
try if (cursel.selection) |_|
self.expand_selection_to_parent_node(root, cursel, self.metrics)
else
@ -4513,7 +4500,7 @@ pub const Editor = struct {
pub const expand_selection_meta: 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(root, metrics).*;
const sel = cursel.enable_selection().*;
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);
@ -4522,7 +4509,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(root, metrics).*;
const sel = cursel.enable_selection().*;
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);
@ -4536,7 +4523,7 @@ pub const Editor = struct {
try self.send_editor_jump_source();
const root = try self.buf_root();
const cursel = self.get_primary();
cursel.check_selection(root, self.metrics);
cursel.check_selection();
if (cursel.selection) |_| {
try if (unnamed)
self.shrink_selection_to_child_node(root, cursel, self.metrics)
@ -4570,7 +4557,7 @@ pub const Editor = struct {
try self.send_editor_jump_source();
const root = try self.buf_root();
const cursel = self.get_primary();
cursel.check_selection(root, self.metrics);
cursel.check_selection();
if (cursel.selection) |_| {
try if (unnamed)
self.select_next_sibling_node(root, cursel, self.metrics)
@ -4604,7 +4591,7 @@ pub const Editor = struct {
try self.send_editor_jump_source();
const root = try self.buf_root();
const cursel = self.get_primary();
cursel.check_selection(root, self.metrics);
cursel.check_selection();
try if (unnamed)
self.select_prev_sibling_node(root, cursel, self.metrics)
else
@ -4680,7 +4667,7 @@ pub const Editor = struct {
root_ = self.collapse_trailing_ws_line(root_, row, b_allocator);
const leading_ws_ = find_first_non_ws(root_, cursel.cursor.row, self.metrics);
if (leading_ws_ > leading_ws and leading_ws_ > cursel.cursor.col) {
const sel = cursel.enable_selection(root_, self.metrics);
const sel = cursel.enable_selection();
sel.* = .{
.begin = .{ .row = cursel.cursor.row, .col = cursel.cursor.col },
.end = .{ .row = cursel.cursor.row, .col = leading_ws_ },
@ -4866,7 +4853,7 @@ pub const Editor = struct {
root = try self.insert(root, &begin, chars_begin, b.allocator);
var end: CurSel = .{ .cursor = sel.end };
root = try self.insert(root, &end, chars_end, b.allocator);
cursel.disable_selection(root, self.metrics);
cursel.disable_selection();
} else blk: {
const egc, _, _ = cursel.cursor.egc_at(root, self.metrics) catch {
root = try self.insert(root, cursel, chars_right, b.allocator);
@ -5469,10 +5456,7 @@ pub const Editor = struct {
const col = cursor.col;
for (self.matches.items) |*match_| if (match_.*) |*match| {
if (match.has_selection) continue;
switch (tui.get_selection_style()) {
.normal => if (cursor.within(match.to_selection())) return match,
.inclusive => {},
}
if (cursor.within(match.to_selection())) return match;
if (row < match.begin.row or (row == match.begin.row and col < match.begin.col)) return match;
};
return null;
@ -6161,7 +6145,7 @@ pub const Editor = struct {
state.chunks = 1;
primary.cursor = state.old_primary.cursor;
} else {
const sel = primary.enable_selection(root, self.metrics);
const sel = primary.enable_selection();
sel.begin = state.begin;
sel.end = state.pos.cursor;
if (state.old_primary_reversed) sel.reverse();
@ -6190,7 +6174,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(root, self.metrics);
var sel = cursel.enable_selection();
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;
@ -6219,7 +6203,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(root, self.metrics);
var sel = cursel.enable_selection();
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;
@ -6248,7 +6232,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(root, self.metrics);
var sel = cursel.enable_selection();
move_cursor_right(root, &sel.end, self.metrics) catch return error.Stop;
saved.cursor = sel.end;
break :ret sel;