Skip to content

Commit db61122

Browse files
fix(forge_select): enter alternate screen to keep prompt visible (#3492)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent d26a266 commit db61122

2 files changed

Lines changed: 32 additions & 4 deletions

File tree

crates/forge_main/src/ui.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3251,9 +3251,10 @@ impl<A: API + ConsoleWriter + 'static, F: Fn(ForgeConfig) -> A + Send + Sync> UI
32513251
server.wait_for_code().await?
32523252
} else {
32533253
// Prompt user to paste authorization code
3254-
let code = ForgeWidget::input("Paste the authorization code")
3255-
.prompt()?
3256-
.ok_or_else(|| anyhow::anyhow!("Authorization code input cancelled"))?;
3254+
let code =
3255+
ForgeWidget::input(format!("Paste the authorization code for {provider_id}"))
3256+
.prompt()?
3257+
.ok_or_else(|| anyhow::anyhow!("Authorization code input cancelled"))?;
32573258

32583259
if code.trim().is_empty() {
32593260
anyhow::bail!("Authorization code cannot be empty");

crates/forge_select/src/input.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
use std::io::IsTerminal;
1+
use std::io::{self, IsTerminal};
22

33
use anyhow::Result;
44
use colored::Colorize;
5+
use crossterm::execute;
6+
use crossterm::terminal::{EnterAlternateScreen, LeaveAlternateScreen};
57
use rustyline::DefaultEditor;
68
use tracing::debug;
79

@@ -63,6 +65,13 @@ impl InputBuilder {
6365
return Ok(None);
6466
}
6567

68+
// Enter the alternate screen so that the prompt is always visible and
69+
// cannot be scrolled out of the viewport. This fixes an issue in
70+
// terminals like VS Code (xterm.js) where rustyline's per-keystroke
71+
// redraw causes the viewport to jump back to the cursor position,
72+
// scrolling the prompt out of view.
73+
let _guard = AlternateScreenGuard::enter();
74+
6675
let mut rl = DefaultEditor::new()?;
6776

6877
// On Windows, rustyline miscounts ANSI escape bytes as visible characters,
@@ -103,6 +112,24 @@ impl InputBuilder {
103112
}
104113
}
105114

115+
/// Guard that enters the terminal alternate screen on creation and exits it on
116+
/// drop. Failures are silently ignored — the alternate screen is a cosmetic
117+
/// best-effort fix for terminal viewport issues.
118+
struct AlternateScreenGuard;
119+
120+
impl AlternateScreenGuard {
121+
fn enter() -> Option<Self> {
122+
execute!(io::stdout(), EnterAlternateScreen).ok()?;
123+
Some(Self)
124+
}
125+
}
126+
127+
impl Drop for AlternateScreenGuard {
128+
fn drop(&mut self) {
129+
let _ = execute!(io::stdout(), LeaveAlternateScreen);
130+
}
131+
}
132+
106133
#[cfg(test)]
107134
mod tests {
108135
use pretty_assertions::assert_eq;

0 commit comments

Comments
 (0)