diff --git a/src/buffer/Cursor.zig b/src/buffer/Cursor.zig index 5a871cf..afb8173 100644 --- a/src/buffer/Cursor.zig +++ b/src/buffer/Cursor.zig @@ -245,3 +245,9 @@ pub fn nudge_delete(self: *Self, nudge: Selection) bool { self.row -= nudge.end.row - nudge.begin.row; return true; } + +pub fn within(self: *const Self, sel_: Selection) bool { + var sel = sel_; + sel.normalize(); + return !sel.begin.right_of(self.*) and sel.end.right_of(self.*); +} diff --git a/src/buffer/Selection.zig b/src/buffer/Selection.zig index 5ea9df5..3882238 100644 --- a/src/buffer/Selection.zig +++ b/src/buffer/Selection.zig @@ -85,3 +85,53 @@ pub fn nudge_delete(self: *Self, nudge: Self) bool { 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; +} diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 3cf398f..3f9c7b6 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -242,6 +242,16 @@ pub const CurSel = struct { return false; return self.cursor.nudge_delete(nudge); } + + fn merge(self: *Self, other: Selection) bool { + if (self.selection) |*sel_| { + if (sel_.merge(other)) { + self.cursor = sel_.end; + return true; + } + } + return self.cursor.within(other); + } }; pub const Diagnostic = struct { @@ -1827,10 +1837,26 @@ pub const Editor = struct { var old = self.cursels; defer old.deinit(self.allocator); self.cursels = CurSel.List.initCapacity(self.allocator, old.items.len) catch return; - for (old.items[0 .. old.items.len - 1], 0..) |*a_, i| if (a_.*) |*a| { - for (old.items[i + 1 ..], i + 1..) |*b_, j| if (b_.*) |*b| { - if (a.cursor.eql(b.cursor)) - old.items[j] = null; + var a_idx = old.items.len - 1; + while (a_idx > 0) : (a_idx -= 1) if (old.items[a_idx]) |*a| { + var b_idx = a_idx - 1; + while (true) : ({ + if (b_idx == 0) break else b_idx -= 1; + }) if (old.items[b_idx]) |*b| { + const b_cursor = b.cursor; + if (b.selection) |b_sel| { + if (a.merge(b_sel)) { + old.items[b_idx] = null; + continue; + } + } + if (a.selection) |*a_sel| if (b_cursor.within(a_sel.*)) { + if (b.selection) |b_sel| a_sel.expand(b_sel); + old.items[b_idx] = null; + continue; + }; + if (a.cursor.eql(b_cursor)) + old.items[b_idx] = null; }; }; for (old.items) |*item_| if (item_.*) |*item| { @@ -2402,6 +2428,7 @@ pub const Editor = struct { 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; + self.collapse_cursors(); self.clamp_mouse(); try self.send_editor_jump_destination(); if (self.jump_mode) try self.goto_definition(.{}); @@ -2415,6 +2442,7 @@ pub const Editor = struct { primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return; _ = try self.select_word_at_cursor(primary); self.selection_drag_initial = primary.selection; + self.collapse_cursors(); self.clamp_mouse(); } @@ -2426,6 +2454,7 @@ pub const Editor = struct { 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); self.selection_drag_initial = primary.selection; + self.collapse_cursors(); self.clamp_mouse(); } @@ -2463,6 +2492,7 @@ pub const Editor = struct { } primary.cursor = sel.end; primary.check_selection(root, self.metrics); + self.collapse_cursors(); self.clamp_mouse(); }