double-click drag selects word by word

This commit is contained in:
Mitchell Hashimoto
2022-11-22 09:15:39 -08:00
parent a63815c5ba
commit f9fed1f3a8

View File

@ -1644,6 +1644,45 @@ fn cursorPosCallback(
const viewport_point = win.posToViewport(xpos, ypos);
const screen_point = viewport_point.toScreen(&win.io.terminal.screen);
// Handle dragging depending on click count
switch (win.mouse.left_click_count) {
1 => win.dragLeftClickSingle(screen_point, xpos),
2 => win.dragLeftClickDouble(screen_point),
3 => {}, // TODO
else => unreachable,
}
}
/// Double-click dragging moves the selection one "word" at a time.
fn dragLeftClickDouble(
self: *Window,
screen_point: terminal.point.ScreenPoint,
) void {
// Get the word under our current point. If there isn't a word, do nothing.
const word = self.io.terminal.screen.selectWord(screen_point) orelse return;
// Get our selection to grow it. If we don't have a selection, start it now.
// We may not have a selection if we started our dbl-click in an area
// that had no data, then we dragged our mouse into an area with data.
var sel = self.io.terminal.screen.selectWord(self.mouse.left_click_point) orelse {
self.io.terminal.selection = word;
return;
};
// Grow our selection
if (screen_point.before(self.mouse.left_click_point)) {
sel.start = word.start;
} else {
sel.end = word.end;
}
self.io.terminal.selection = sel;
}
fn dragLeftClickSingle(
self: *Window,
screen_point: terminal.point.ScreenPoint,
xpos: f64,
) void {
// NOTE(mitchellh): This logic super sucks. There has to be an easier way
// to calculate this, but this is good for a v1. Selection isn't THAT
// common so its not like this performance heavy code is running that
@ -1653,13 +1692,13 @@ fn cursorPosCallback(
// If we were selecting, and we switched directions, then we restart
// calculations because it forces us to reconsider if the first cell is
// selected.
if (win.io.terminal.selection) |sel| {
if (self.io.terminal.selection) |sel| {
const reset: bool = if (sel.end.before(sel.start))
sel.start.before(screen_point)
else
screen_point.before(sel.start);
if (reset) win.io.terminal.selection = null;
if (reset) self.io.terminal.selection = null;
}
// Our logic for determing if the starting cell is selected:
@ -1675,23 +1714,23 @@ fn cursorPosCallback(
//
// the boundary point at which we consider selection or non-selection
const cell_xboundary = win.cell_size.width * 0.6;
const cell_xboundary = self.cell_size.width * 0.6;
// first xpos of the clicked cell
const cell_xstart = @intToFloat(f32, win.mouse.left_click_point.x) * win.cell_size.width;
const cell_start_xpos = win.mouse.left_click_xpos - cell_xstart;
const cell_xstart = @intToFloat(f32, self.mouse.left_click_point.x) * self.cell_size.width;
const cell_start_xpos = self.mouse.left_click_xpos - cell_xstart;
// If this is the same cell, then we only start the selection if weve
// moved past the boundary point the opposite direction from where we
// started.
if (std.meta.eql(screen_point, win.mouse.left_click_point)) {
if (std.meta.eql(screen_point, self.mouse.left_click_point)) {
const cell_xpos = xpos - cell_xstart;
const selected: bool = if (cell_start_xpos < cell_xboundary)
cell_xpos >= cell_xboundary
else
cell_xpos < cell_xboundary;
win.io.terminal.selection = if (selected) .{
self.io.terminal.selection = if (selected) .{
.start = screen_point,
.end = screen_point,
} else null;
@ -1701,29 +1740,29 @@ fn cursorPosCallback(
// If this is a different cell and we haven't started selection,
// we determine the starting cell first.
if (win.io.terminal.selection == null) {
if (self.io.terminal.selection == null) {
// - If we're moving to a point before the start, then we select
// the starting cell if we started after the boundary, else
// we start selection of the prior cell.
// - Inverse logic for a point after the start.
const click_point = win.mouse.left_click_point;
const click_point = self.mouse.left_click_point;
const start: terminal.point.ScreenPoint = if (screen_point.before(click_point)) start: {
if (win.mouse.left_click_xpos > cell_xboundary) {
if (self.mouse.left_click_xpos > cell_xboundary) {
break :start click_point;
} else {
break :start if (click_point.x > 0) terminal.point.ScreenPoint{
.y = click_point.y,
.x = click_point.x - 1,
} else terminal.point.ScreenPoint{
.x = win.io.terminal.screen.cols - 1,
.x = self.io.terminal.screen.cols - 1,
.y = click_point.y -| 1,
};
}
} else start: {
if (win.mouse.left_click_xpos < cell_xboundary) {
if (self.mouse.left_click_xpos < cell_xboundary) {
break :start click_point;
} else {
break :start if (click_point.x < win.io.terminal.screen.cols - 1) terminal.point.ScreenPoint{
break :start if (click_point.x < self.io.terminal.screen.cols - 1) terminal.point.ScreenPoint{
.y = click_point.y,
.x = click_point.x + 1,
} else terminal.point.ScreenPoint{
@ -1733,7 +1772,7 @@ fn cursorPosCallback(
}
};
win.io.terminal.selection = .{ .start = start, .end = screen_point };
self.io.terminal.selection = .{ .start = start, .end = screen_point };
return;
}
@ -1742,8 +1781,8 @@ fn cursorPosCallback(
// We moved! Set the selection end point. The start point should be
// set earlier.
assert(win.io.terminal.selection != null);
win.io.terminal.selection.?.end = screen_point;
assert(self.io.terminal.selection != null);
self.io.terminal.selection.?.end = screen_point;
}
fn posToViewport(self: Window, xpos: f64, ypos: f64) terminal.point.Viewport {