T59: a click goes to a shell that takes clicks only past its prompt's last cell before the cursor, never on a prompt cell, so a click on fish's $ leaves its cursor where it stood
This commit is contained in:
4 files changed
+47
-8
No files matched your search
+20
-6
@@ -92,16 +92,30 @@ pub fn arrows<T>(term: &Term<T>, click: Point) -> Option<i32> {
|
||||
})
|
||||
}
|
||||
|
||||
/// The left press, SGR, a shell that takes clicks hears for `click`, its row the screen's or counted from its prompt's first, as kitty and Ghostty send it; none before that prompt.
|
||||
/// The left press, SGR, a shell that takes clicks hears for `click`, its row the screen's or counted from its prompt's first, as kitty and Ghostty send it; none on the prompt or before its end.
|
||||
pub fn press<T>(term: &Term<T>, click: Point, relative: bool) -> Option<Vec<u8>> {
|
||||
if term.mode().contains(TermMode::ALT_SCREEN) {
|
||||
return None;
|
||||
}
|
||||
let first = start(term, term.grid().cursor.point.line.0)?;
|
||||
let opens = (0..term.columns())
|
||||
.position(|column| prompted(&term.grid()[Line(first)][Column(column)]))
|
||||
let grid = term.grid();
|
||||
let cursor = grid.cursor.point;
|
||||
let first = start(term, cursor.line.0)?;
|
||||
let cell = |line: i32, column: usize| &grid[Line(line)][Column(column)];
|
||||
// The prompt ends at its last cell before the cursor.
|
||||
let end = (first..=cursor.line.0)
|
||||
.flat_map(|line| {
|
||||
let width = if line == cursor.line.0 {
|
||||
cursor.column.0
|
||||
} else {
|
||||
term.columns()
|
||||
};
|
||||
(0..width).map(move |column| (line, column))
|
||||
})
|
||||
.filter(|&(line, column)| prompted(cell(line, column)))
|
||||
.last()
|
||||
.expect("a prompt's first row holds its cells");
|
||||
if (click.line.0, click.column.0) < (first, opens) {
|
||||
let at = (click.line.0, click.column.0);
|
||||
if at <= end || prompted(cell(at.0, at.1)) {
|
||||
return None;
|
||||
}
|
||||
let row = if relative {
|
||||
@@ -129,7 +143,7 @@ impl TerminalView {
|
||||
}
|
||||
if takes != Click::Arrows {
|
||||
let Some(bytes) = press(&self.pty.term.lock(), click, takes == Click::Relative) else {
|
||||
log::debug!("terminal {pid}: a click at {click:?}, before the prompt");
|
||||
log::debug!("terminal {pid}: a click at {click:?}, off the input");
|
||||
return;
|
||||
};
|
||||
log::debug!("terminal {pid}: a click at {click:?} goes to the shell as {bytes:?}");
|
||||
|
||||
@@ -114,6 +114,31 @@ fn a_shell_that_takes_clicks_hears_the_press_where_it_landed() {
|
||||
"a row below goes too"
|
||||
);
|
||||
assert_eq!(sent(&typed, click(0, 1), false), None, "before the prompt");
|
||||
assert_eq!(sent(&typed, click(1, 0), false), None, "on the prompt");
|
||||
assert_eq!(
|
||||
sent(&typed, click(1, 1), false),
|
||||
None,
|
||||
"on the prompt's space"
|
||||
);
|
||||
let past = sent(&typed, click(1, 15), false);
|
||||
assert_eq!(
|
||||
past.as_deref(),
|
||||
Some("\x1b[<0;16;2M"),
|
||||
"past the end, the shell decides"
|
||||
);
|
||||
let right = term(
|
||||
20,
|
||||
&format!("{marked}ls\x1b7\x1b[1;17H\x1b]133;A\x07~/a\x1b]133;B\x07\x1b8"),
|
||||
);
|
||||
assert_eq!(
|
||||
sent(&right, click(0, 18), false),
|
||||
None,
|
||||
"a right prompt after the cursor"
|
||||
);
|
||||
assert_eq!(
|
||||
sent(&right, click(0, 3), false).as_deref(),
|
||||
Some("\x1b[<0;4;1M")
|
||||
);
|
||||
let two = term(
|
||||
20,
|
||||
"\x1b]133;A;click_events=2\x07~/src\r\n> \x1b]133;B\x07ls",
|
||||
|
||||
Reference in new issue
Block a user