Improve click-to-move cursor for long commands without semantic prompts

This commit is contained in:
Bryan Lee
2025-06-23 00:07:23 +08:00
parent 373fc6bcbf
commit df68e5f219

View File

@ -3350,38 +3350,35 @@ 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"; break :arrow if (t.modes.get(.cursor_keys)) "\x1bOD" else "\x1b[D";
}; } else arrow: {
for (0..@abs(path.y)) |_| { // Moving right
self.io.queueMessage(.{ .write_stable = arrow }, .locked); break :arrow if (t.modes.get(.cursor_keys)) "\x1bOC" else "\x1b[C";
} };
}
if (path.x != 0) { // Move the cursor step by step
const arrow = if (path.x < 0) arrow: { const steps = @abs(distance);
break :arrow if (t.modes.get(.cursor_keys)) "\x1bOD" else "\x1b[D"; for (0..@intCast(steps)) |_| {
} else arrow: { self.io.queueMessage(.{ .write_stable = arrow }, .locked);
break :arrow if (t.modes.get(.cursor_keys)) "\x1bOC" else "\x1b[C";
};
for (0..@abs(path.x)) |_| {
self.io.queueMessage(.{ .write_stable = arrow }, .locked);
}
} }
} }