mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
double-click drag selects word by word
This commit is contained in:
@ -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 {
|
||||
|
Reference in New Issue
Block a user