mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
Improve click-to-move cursor for long commands without semantic prompts
This commit is contained in:
@ -3350,39 +3350,36 @@ fn clickMoveCursor(self: *Surface, to: terminal.Pin) !void {
|
|||||||
// move the cursor so we can fast path out of here.
|
// move the cursor so we can fast path out of here.
|
||||||
if (!t.flags.shell_redraws_prompt) return;
|
if (!t.flags.shell_redraws_prompt) return;
|
||||||
|
|
||||||
// Get our path
|
// Get the current cursor position and target position
|
||||||
const from = t.screen.cursor.page_pin.*;
|
const from = t.screen.cursor.page_pin.*;
|
||||||
const path = t.screen.promptPath(from, to);
|
log.debug("click-to-move-cursor from={} to={}", .{ from, to });
|
||||||
log.debug("click-to-move-cursor from={} to={} path={}", .{ from, to, path });
|
|
||||||
|
|
||||||
// If we aren't moving at all, fast path out of here.
|
// If we aren't moving at all, fast path out of here.
|
||||||
if (path.x == 0 and path.y == 0) return;
|
if (from.x == to.x and from.y == to.y) return;
|
||||||
|
|
||||||
// Convert our path to arrow key inputs. Yes, that is how this works.
|
// First, calculate the total character distance.
|
||||||
// Yes, that is pretty sad. Yes, this could backfire in various ways.
|
// We need to consider the terminal width for proper wrapping.
|
||||||
// But its the best we can do.
|
const cols = t.cols;
|
||||||
|
const from_pos = from.y * cols + from.x;
|
||||||
|
const to_pos = to.y * cols + to.x;
|
||||||
|
const distance = @as(isize, @intCast(to_pos)) - @as(isize, @intCast(from_pos));
|
||||||
|
|
||||||
// We do Y first because it prevents any weird wrap behavior.
|
if (distance == 0) return;
|
||||||
if (path.y != 0) {
|
|
||||||
const arrow = if (path.y < 0) arrow: {
|
// Determine which arrow key to use for movement
|
||||||
break :arrow if (t.modes.get(.cursor_keys)) "\x1bOA" else "\x1b[A";
|
const arrow = if (distance < 0) arrow: {
|
||||||
} else arrow: {
|
// Moving left
|
||||||
break :arrow if (t.modes.get(.cursor_keys)) "\x1bOB" else "\x1b[B";
|
|
||||||
};
|
|
||||||
for (0..@abs(path.y)) |_| {
|
|
||||||
self.io.queueMessage(.{ .write_stable = arrow }, .locked);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (path.x != 0) {
|
|
||||||
const arrow = if (path.x < 0) arrow: {
|
|
||||||
break :arrow if (t.modes.get(.cursor_keys)) "\x1bOD" else "\x1b[D";
|
break :arrow if (t.modes.get(.cursor_keys)) "\x1bOD" else "\x1b[D";
|
||||||
} else arrow: {
|
} else arrow: {
|
||||||
|
// Moving right
|
||||||
break :arrow if (t.modes.get(.cursor_keys)) "\x1bOC" else "\x1b[C";
|
break :arrow if (t.modes.get(.cursor_keys)) "\x1bOC" else "\x1b[C";
|
||||||
};
|
};
|
||||||
for (0..@abs(path.x)) |_| {
|
|
||||||
|
// Move the cursor step by step
|
||||||
|
const steps = @abs(distance);
|
||||||
|
for (0..@intCast(steps)) |_| {
|
||||||
self.io.queueMessage(.{ .write_stable = arrow }, .locked);
|
self.io.queueMessage(.{ .write_stable = arrow }, .locked);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the link at the given cursor position, if any.
|
/// Returns the link at the given cursor position, if any.
|
||||||
|
Reference in New Issue
Block a user