core: double-click drag

This commit is contained in:
Mitchell Hashimoto
2024-03-10 21:03:16 -07:00
parent 361fdd2179
commit 4d0f210025
2 changed files with 49 additions and 21 deletions

View File

@ -2640,7 +2640,7 @@ pub fn cursorPosCallback(
// Handle dragging depending on click count // Handle dragging depending on click count
switch (self.mouse.left_click_count) { switch (self.mouse.left_click_count) {
1 => try self.dragLeftClickSingle(pin, pos.x), 1 => try self.dragLeftClickSingle(pin, pos.x),
// 2 => self.dragLeftClickDouble(screen_point), 2 => try self.dragLeftClickDouble(pin),
// 3 => self.dragLeftClickTriple(screen_point), // 3 => self.dragLeftClickTriple(screen_point),
// 0 => unreachable, // handled above // 0 => unreachable, // handled above
else => unreachable, else => unreachable,
@ -2680,38 +2680,40 @@ pub fn cursorPosCallback(
/// Double-click dragging moves the selection one "word" at a time. /// Double-click dragging moves the selection one "word" at a time.
fn dragLeftClickDouble( fn dragLeftClickDouble(
self: *Surface, self: *Surface,
screen_point: terminal.point.ScreenPoint, drag_pin: terminal.Pin,
) void { ) !void {
const screen = &self.io.terminal.screen;
const click_pin = self.mouse.left_click_pin.?.*;
// Get the word closest to our starting click. // Get the word closest to our starting click.
const word_start = self.io.terminal.screen.selectWordBetween( const word_start = screen.selectWordBetween(click_pin, drag_pin) orelse {
self.mouse.left_click_point, try self.setSelection(null);
screen_point,
) orelse {
self.setSelection(null);
return; return;
}; };
// Get the word closest to our current point. // Get the word closest to our current point.
const word_current = self.io.terminal.screen.selectWordBetween( const word_current = screen.selectWordBetween(
screen_point, drag_pin,
self.mouse.left_click_point, click_pin,
) orelse { ) orelse {
self.setSelection(null); try self.setSelection(null);
return; return;
}; };
// If our current mouse position is before the starting position, // If our current mouse position is before the starting position,
// then the seletion start is the word nearest our current position. // then the seletion start is the word nearest our current position.
if (screen_point.before(self.mouse.left_click_point)) { if (drag_pin.before(click_pin)) {
self.setSelection(.{ try self.setSelection(terminal.Selection.init(
.start = word_current.start, word_current.start(),
.end = word_start.end, word_start.end(),
}); false,
));
} else { } else {
self.setSelection(.{ try self.setSelection(terminal.Selection.init(
.start = word_start.start, word_start.start(),
.end = word_current.end, word_current.end(),
}); false,
));
} }
} }

View File

@ -1295,6 +1295,32 @@ pub fn selectAll(self: *Screen) ?Selection {
return Selection.init(start, end, false); 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 /// Select the word under the given point. A word is any consecutive series
/// of characters that are exclusively whitespace or exclusively non-whitespace. /// of characters that are exclusively whitespace or exclusively non-whitespace.
/// A selection can span multiple physical lines if they are soft-wrapped. /// A selection can span multiple physical lines if they are soft-wrapped.