Preserve typeahead from process start

This commit is contained in:
Charlie Marsh
2026-07-05 20:52:37 -04:00
parent 944dcb100d
commit 2e64c1bcf1
3 changed files with 27 additions and 10 deletions
+8 -7
View File
@@ -884,7 +884,7 @@ pub async fn run_main(
Ok(v) => v,
#[allow(clippy::print_stderr)]
Err(e) => {
tui::discard_terminal_input();
tui::abandon_prepared_terminal();
eprintln!("Error parsing -c overrides: {e}");
std::process::exit(1);
}
@@ -895,7 +895,7 @@ pub async fn run_main(
let codex_home = match find_codex_home() {
Ok(codex_home) => codex_home.to_path_buf(),
Err(err) => {
tui::discard_terminal_input();
tui::abandon_prepared_terminal();
eprintln!("Error finding codex home: {err}");
std::process::exit(1);
}
@@ -1018,6 +1018,7 @@ pub async fn run_main(
Some(provider)
} else {
// No provider configured, prompt the user
tui::discard_terminal_input();
let selection = oss_selection::select_oss_provider().await?;
let provider = selection.provider;
if provider == "__CANCELLED__" {
@@ -1148,7 +1149,7 @@ pub async fn run_main(
match check_execpolicy_for_warnings(&config.config_layer_stack).await {
Ok(None) => {}
Ok(Some(err)) | Err(err) => {
tui::discard_terminal_input();
tui::abandon_prepared_terminal();
eprintln!(
"Error loading rules:\n{}",
format_exec_policy_error_with_source(&err)
@@ -1166,7 +1167,7 @@ pub async fn run_main(
) {
#[allow(clippy::print_stderr)]
{
tui::discard_terminal_input();
tui::abandon_prepared_terminal();
eprintln!("Error adding directories: {warning}");
std::process::exit(1);
}
@@ -1186,7 +1187,7 @@ pub async fn run_main(
})
.await
{
tui::discard_terminal_input();
tui::abandon_prepared_terminal();
eprintln!("{err}");
std::process::exit(1);
}
@@ -1946,7 +1947,7 @@ async fn load_config_or_exit_with_fallback_cwd(
{
Ok(config) => config,
Err(err) => {
tui::discard_terminal_input();
tui::abandon_prepared_terminal();
eprintln!("Error loading configuration: {err}");
std::process::exit(1);
}
@@ -1976,7 +1977,7 @@ async fn load_bootstrap_config_or_exit(
{
Ok(config_toml) => config_toml,
Err(err) => {
tui::discard_terminal_input();
tui::abandon_prepared_terminal();
let config_error = err
.get_ref()
.and_then(|err| err.downcast_ref::<ConfigLoadError>())
+1
View File
@@ -77,6 +77,7 @@ pub(crate) struct InitializedTerminal {
pub(crate) use startup::PreparedTerminal;
use startup::StartupInputBuffer;
pub(crate) use startup::abandon_prepared_terminal;
use startup::capture_startup_input;
pub(crate) use startup::discard_terminal_input;
+18 -3
View File
@@ -4,11 +4,14 @@ use std::io::stdin;
use std::io::stdout;
use std::time::Duration;
use crossterm::event::DisableBracketedPaste;
use crossterm::event::EnableBracketedPaste;
use crossterm::event::Event;
use crossterm::event::KeyCode;
use crossterm::event::KeyEvent;
use crossterm::event::KeyEventKind;
use crossterm::event::KeyModifiers;
use crossterm::execute;
use ratatui::backend::CrosstermBackend;
use ratatui::layout::Position;
@@ -30,6 +33,8 @@ impl Drop for PreparedTerminal {
discard_terminal_input();
if self.terminal_modes_active {
let _ = super::restore_after_exit();
} else {
let _ = disable_startup_paste_capture();
}
}
}
@@ -145,6 +150,15 @@ pub(crate) fn discard_terminal_input() {
flush_terminal_input_buffer();
}
pub(crate) fn abandon_prepared_terminal() {
discard_terminal_input();
let _ = disable_startup_paste_capture();
}
fn disable_startup_paste_capture() -> Result<()> {
execute!(stdout(), DisableBracketedPaste)
}
pub(super) fn capture_startup_input(input: &mut StartupInputBuffer) -> Result<()> {
while crossterm::event::poll(Duration::ZERO)? {
input.handle_event(crossterm::event::read()?);
@@ -153,7 +167,7 @@ pub(super) fn capture_startup_input(input: &mut StartupInputBuffer) -> Result<()
}
impl PreparedTerminal {
/// Clear stale shell input before slower startup work begins.
/// Start preserving terminal paste boundaries before slower startup work begins.
pub(crate) fn prepare() -> Result<Self> {
if !stdin().is_terminal() {
return Err(std::io::Error::other("stdin is not a terminal"));
@@ -161,7 +175,9 @@ impl PreparedTerminal {
if !stdout().is_terminal() {
return Err(std::io::Error::other("stdout is not a terminal"));
}
discard_terminal_input();
super::ensure_virtual_terminal_processing()?;
super::set_panic_hook();
execute!(stdout(), EnableBracketedPaste)?;
Ok(Self {
active: true,
terminal_modes_active: false,
@@ -174,7 +190,6 @@ impl PreparedTerminal {
super::set_base_modes()?;
let mut startup_input = StartupInputBuffer::default();
capture_startup_input(&mut startup_input)?;
super::set_panic_hook();
#[cfg(unix)]
let backend = CrosstermBackend::new(stdout());