flow/src/buffer/Selection.zig
CJ van den Berg a5c360a2ec
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.
2025-11-27 17:22:58 +01:00

152 lines
4.2 KiB
Zig

const cbor = @import("cbor");
const Writer = @import("std").Io.Writer;
const Buffer = @import("Buffer.zig");
const Cursor = @import("Cursor.zig");
begin: Cursor = Cursor{},
end: Cursor = Cursor{},
const Self = @This();
pub inline fn eql(self: Self, other: Self) bool {
return self.begin.eql(other.begin) and self.end.eql(other.end);
}
pub fn from_cursor(cursor: *const Cursor) Self {
return .{ .begin = cursor.*, .end = cursor.* };
}
pub fn from_cursor_inclusive(cursor: *const Cursor, root: Buffer.Root, metrics: Buffer.Metrics) Self {
var sel: Self = .{ .begin = cursor.*, .end = cursor.* };
sel.end.move_right(root, metrics) catch {};
return sel;
}
pub fn from_pos(sel: Self, root: Buffer.Root, metrics: Buffer.Metrics) Self {
return .{
.begin = .{
.row = sel.begin.row,
.col = root.pos_to_width(sel.begin.row, sel.begin.col, metrics) catch root.line_width(sel.begin.row, metrics) catch 0,
},
.end = .{
.row = sel.end.row,
.col = root.pos_to_width(sel.end.row, sel.end.col, metrics) catch root.line_width(sel.end.row, metrics) catch 0,
},
};
}
pub fn from_range(range: anytype, root: Buffer.Root, metrics: Buffer.Metrics) Self {
return from_pos(from_range_raw(range), root, metrics);
}
pub fn from_range_raw(range: anytype) Self {
return .{
.begin = .{ .row = range.start_point.row, .col = range.start_point.column },
.end = .{ .row = range.end_point.row, .col = range.end_point.column },
};
}
pub fn line_from_cursor(cursor: Cursor, root: Buffer.Root, mtrx: Buffer.Metrics) Self {
var begin = cursor;
var end = cursor;
begin.move_begin();
end.move_end(root, mtrx);
end.move_right(root, mtrx) catch {};
return .{ .begin = begin, .end = end };
}
pub fn empty(self: *const Self) bool {
return self.begin.eql(self.end);
}
pub fn reverse(self: *Self) void {
const tmp = self.begin;
self.begin = self.end;
self.end = tmp;
}
pub inline fn is_reversed(self: *const Self) bool {
return self.begin.right_of(self.end);
}
pub fn normalize(self: *Self) void {
if (self.is_reversed()) self.reverse();
}
pub fn write(self: *const Self, writer: *Writer) !void {
try cbor.writeArrayHeader(writer, 2);
try self.begin.write(writer);
try self.end.write(writer);
}
pub fn extract(self: *Self, iter: *[]const u8) !bool {
var iter2 = iter.*;
const len = cbor.decodeArrayHeader(&iter2) catch return false;
if (len != 2) return false;
if (!try self.begin.extract(&iter2)) return false;
if (!try self.end.extract(&iter2)) return false;
iter.* = iter2;
return true;
}
pub fn nudge_insert(self: *Self, nudge: Self) void {
self.begin.nudge_insert(nudge);
self.end.nudge_insert(nudge);
}
pub fn nudge_delete(self: *Self, nudge: Self) bool {
if (!self.begin.nudge_delete(nudge))
return false;
return self.end.nudge_delete(nudge);
}
pub fn merge(self: *Self, other_: Self) bool {
var other = other_;
other.normalize();
if (self.is_reversed()) {
var this = self.*;
this.normalize();
if (this.merge_normal(other)) {
self.begin = this.end;
self.end = this.begin;
return true;
}
return false;
}
return self.merge_normal(other);
}
fn merge_normal(self: *Self, other: Self) bool {
var merged = false;
if (self.begin.within(other)) {
self.begin = other.begin;
merged = true;
}
if (self.end.within(other)) {
self.end = other.end;
merged = true;
}
return merged or
(other.begin.right_of(self.begin) and
self.end.right_of(other.end));
}
pub fn expand(self: *Self, other_: Self) void {
var other = other_;
other.normalize();
if (self.is_reversed()) {
var this = self.*;
this.normalize();
this.expand_normal(other);
self.begin = this.end;
self.end = this.begin;
} else self.expand_normal(other);
}
fn expand_normal(self: *Self, other: Self) void {
if (self.begin.right_of(other.begin))
self.begin = other.begin;
if (other.end.right_of(self.end))
self.end = other.end;
}