From fa8f7cee31756baf787a35da2f40e7fcca5fd33a Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Sun, 9 Aug 2026 10:07:09 +0700 Subject: [PATCH] fix(terminal): bring the view back to the prompt when you start typing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scroll up into the scrollback and type: the characters went to the shell, the prompt line grew, and the viewport did not move. Nothing on screen changed, so the pane read as having stopped listening — while it was in fact accepting every keystroke somewhere the user could not see. `commit_text` has three branches and only the last one jumped to the prompt: the one taken when tty7 is *not* driving the line. At a shell prompt with OSC 133 reporting — the normal case, and the one the editor features exist for — the text goes into `cmd` and returned early. Same for a reverse-search query. `handle_editor_key` has always jumped, so the two halves of the same editor disagreed: Left and Backspace came back to the prompt and the letters between them did not. Hoisted the jump above all three branches, where it describes the whole function: text typed goes to the prompt, so the view has to be looking at the prompt. Held by a test that fails on the old order. Verified in a dev window: 200 lines printed, scrolled 15 notches back, typed — the grid snaps to the prompt with the characters on it. --- src/terminal/view.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/terminal/view.rs b/src/terminal/view.rs index 6556969e..390909ee 100644 --- a/src/terminal/view.rs +++ b/src/terminal/view.rs @@ -3964,6 +3964,14 @@ impl TerminalView { if self.terminal.exited || text.is_empty() || !self.accepts_input(cx) { return; } + // Typing goes to the prompt, so the view has to be looking at it. + // Only the last branch below used to do this, which is the branch + // taken when tty7 is *not* driving the line — so scrolling up and + // typing did the one thing it must never do at a shell prompt: + // accepted the characters somewhere the user could not see them. + // `handle_editor_key` has always jumped, so Left and Backspace came + // back to the prompt and the letters between them did not. + self.jump_to_prompt(); if let Some(rs) = self.reverse_search.as_mut() { rs.push_query(text, &self.history, &self.history_frecency); self.cursor_visible = true; @@ -3982,7 +3990,6 @@ impl TerminalView { } self.write_gap_text(text, text.as_bytes().to_vec(), cx); self.cursor_visible = true; - self.jump_to_prompt(); cx.notify(); } @@ -8590,6 +8597,30 @@ mod gpui_tests { .unwrap(); } + /// The one thing typing at a prompt must never do is land where the + /// person typing cannot see it. + #[gpui::test] + fn typing_brings_the_view_back_to_the_prompt(cx: &mut TestAppContext) { + let (window, mut daemon) = harness(cx); + prompt_ready(&window, cx, &mut daemon); + window + .update(cx, |view, _w, cx| { + assert!( + view.input_active(), + "this is the branch that was leaving the view parked" + ); + scroll_into_history(view, 10); + view.commit_text("l", cx); + assert_eq!( + display_offset(view), + 0, + "the character went in while the viewport stayed in the scrollback" + ); + assert_eq!(view.cmd.text(), "l", "and it did reach the line"); + }) + .unwrap(); + } + /// A trackpad is already a continuous stream — animating it would only put /// lag between the fingers and the grid. It is told apart by its phase, not /// by its delta type or size: a flick moves further in one event than a