From 4d0f21002565ebf4149eb5c0c1ccb9464cb0f419 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 10 Mar 2024 21:03:16 -0700 Subject: [PATCH] core: double-click drag --- src/Surface.zig | 44 +++++++++++++++++++++-------------------- src/terminal/Screen.zig | 26 ++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index 6dbb27e61..37172b51c 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -2640,7 +2640,7 @@ pub fn cursorPosCallback( // Handle dragging depending on click count switch (self.mouse.left_click_count) { 1 => try self.dragLeftClickSingle(pin, pos.x), - // 2 => self.dragLeftClickDouble(screen_point), + 2 => try self.dragLeftClickDouble(pin), // 3 => self.dragLeftClickTriple(screen_point), // 0 => unreachable, // handled above else => unreachable, @@ -2680,38 +2680,40 @@ pub fn cursorPosCallback( /// Double-click dragging moves the selection one "word" at a time. fn dragLeftClickDouble( self: *Surface, - screen_point: terminal.point.ScreenPoint, -) void { + drag_pin: terminal.Pin, +) !void { + const screen = &self.io.terminal.screen; + const click_pin = self.mouse.left_click_pin.?.*; + // Get the word closest to our starting click. - const word_start = self.io.terminal.screen.selectWordBetween( - self.mouse.left_click_point, - screen_point, - ) orelse { - self.setSelection(null); + const word_start = screen.selectWordBetween(click_pin, drag_pin) orelse { + try self.setSelection(null); return; }; // Get the word closest to our current point. - const word_current = self.io.terminal.screen.selectWordBetween( - screen_point, - self.mouse.left_click_point, + const word_current = screen.selectWordBetween( + drag_pin, + click_pin, ) orelse { - self.setSelection(null); + try self.setSelection(null); return; }; // If our current mouse position is before the starting position, // then the seletion start is the word nearest our current position. - if (screen_point.before(self.mouse.left_click_point)) { - self.setSelection(.{ - .start = word_current.start, - .end = word_start.end, - }); + if (drag_pin.before(click_pin)) { + try self.setSelection(terminal.Selection.init( + word_current.start(), + word_start.end(), + false, + )); } else { - self.setSelection(.{ - .start = word_start.start, - .end = word_current.end, - }); + try self.setSelection(terminal.Selection.init( + word_start.start(), + word_current.end(), + false, + )); } } diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index c5e7cfefb..9cfc97401 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -1295,6 +1295,32 @@ pub fn selectAll(self: *Screen) ?Selection { return Selection.init(start, end, false); } +/// Select the nearest word to start point that is between start_pt and +/// end_pt (inclusive). Because it selects "nearest" to start point, start +/// point can be before or after end point. +/// +/// TODO: test this +pub fn selectWordBetween( + self: *Screen, + start: Pin, + end: Pin, +) ?Selection { + const dir: PageList.Direction = if (start.before(end)) .right_down else .left_up; + var it = start.cellIterator(dir, end); + while (it.next()) |pin| { + // Boundary conditions + switch (dir) { + .right_down => if (end.before(pin)) return null, + .left_up => if (pin.before(end)) return null, + } + + // If we found a word, then return it + if (self.selectWord(pin)) |sel| return sel; + } + + return null; +} + /// Select the word under the given point. A word is any consecutive series /// of characters that are exclusively whitespace or exclusively non-whitespace. /// A selection can span multiple physical lines if they are soft-wrapped.