From 3ae971f941d8c7a7e012e995d2afc392078aa252 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 8 Oct 2025 23:28:11 +0200 Subject: [PATCH] terminal: Clear shell after activating (#39798) Two tweaks were required to ensure we correctly clear the shell after running an activate script(s): 1. PowerShell upon receiving `\r\n` input, will enter the continuation mode (>>). To avoid this, we send an "enter" key press instead `\x0d`. 2. In order to clear the terminal _after_ issuing all activation commands, we need to take into account the asynchronous nature of the activation process: - We write the command to run the script to PTY - We send "enter" (It is now being processed by the shell) At this point we need to wait for the shell to finish executing before we clear the terminal. Otherwise we will create a race where we might clear the terminal _before_ the shell finished executing the activation script(s). - Write `clear`/`cls` command to PTY - Send "enter" This way we guarantee that we clear the terminal _after_ all scripts were executed. Closes #38474 Release Notes: - N/A --- crates/terminal/src/terminal.rs | 31 +++++++++++++++++++++---------- crates/util/src/shell.rs | 7 +++++++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index eca98a5eec3189349693af31d146f8e88d9e49ab..0d1073b41bc19e01ac03de24b40e93a13488baca 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -495,6 +495,8 @@ impl TerminalBuilder { .unwrap_or(params.program.clone()) }); + let shell_kind = shell.shell_kind(); + let pty_options = { let alac_shell = shell_params.as_ref().map(|params| { alacritty_terminal::tty::Shell::new( @@ -511,7 +513,7 @@ impl TerminalBuilder { // We do not want to escape arguments if we are using CMD as our shell. // If we do we end up with too many quotes/escaped quotes for CMD to handle. #[cfg(windows)] - escape_args: shell.shell_kind() != util::shell::ShellKind::Cmd, + escape_args: shell_kind != util::shell::ShellKind::Cmd, } }; @@ -581,7 +583,7 @@ impl TerminalBuilder { let no_task = task.is_none(); - let mut terminal = Terminal { + let terminal = Terminal { task, terminal_type: TerminalType::Pty { pty_tx: Notifier(pty_tx), @@ -621,14 +623,23 @@ impl TerminalBuilder { if !activation_script.is_empty() && no_task { for activation_script in activation_script { - terminal.input(activation_script.into_bytes()); - terminal.write_to_pty(if cfg!(windows) { - b"\r\n" as &[_] - } else { - b"\n" - }); - } - terminal.clear(); + terminal.write_to_pty(activation_script.into_bytes()); + // Simulate enter key press + // NOTE(PowerShell): using `\r\n` will put PowerShell in a continuation mode (infamous >> character) + // and generally mess up the rendering. + terminal.write_to_pty(b"\x0d"); + } + // In order to clear the screen at this point, we have two options: + // 1. We can send a shell-specific command such as "clear" or "cls" + // 2. We can "echo" a marker message that we will then catch when handling a Wakeup event + // and clear the screen using `terminal.clear()` method + // We cannot issue a `terminal.clear()` command at this point as alacritty is evented + // and while we have sent the activation script to the pty, it will be executed asynchronously. + // Therefore, we somehow need to wait for the activation script to finish executing before we + // can proceed with clearing the screen. + terminal.write_to_pty(shell_kind.clear_screen_command().as_bytes()); + // Simulate enter key press + terminal.write_to_pty(b"\x0d"); } Ok(TerminalBuilder { diff --git a/crates/util/src/shell.rs b/crates/util/src/shell.rs index cde7c73b7ef6d36c47c383f8c38cd0f2a5fd642b..c54fa6edea894dbd418b8ddc811e3a3c3a6f9d3e 100644 --- a/crates/util/src/shell.rs +++ b/crates/util/src/shell.rs @@ -389,4 +389,11 @@ impl ShellKind { ShellKind::Posix | ShellKind::Rc => "source", } } + + pub const fn clear_screen_command(&self) -> &'static str { + match self { + ShellKind::Cmd => "cls", + _ => "clear", + } + } }