From fed3c4a8a282392e81c2245774d078f43736390d Mon Sep 17 00:00:00 2001 From: "Dr. Alex Mitre" Date: Fri, 1 May 2026 18:14:54 -0600 Subject: [PATCH] fix(terminal): skip Ctrl-U/Ctrl-K for pexpect-based subshells (poetry/pipenv) When clicking 'Warpify subshell' in a poetry or pipenv subshell, the terminal input would stop working. This was caused by Warp sending Ctrl-U and Ctrl-K control characters to clear the line before sending the InitShell DCS hook, which interfered with pexpect's PTY management. pexpect (used by poetry and pipenv to spawn subshells) expects to manage the PTY itself and is sensitive to control characters. Sending Ctrl-U/Ctrl-K caused pexpect to enter a state where user input was blocked. This fix: - Adds is_pexpect_subshell() helper to detect poetry/pipenv subshells - Adds write_init_subshell_bytes_to_pty_without_clearing() for pexpect - Modifies trigger_subshell_bootstrap to use the non-clearing variant for pexpect-based subshells Fixes #3105 --- app/src/terminal/view.rs | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/app/src/terminal/view.rs b/app/src/terminal/view.rs index c69adaa46..c5e710f46 100644 --- a/app/src/terminal/view.rs +++ b/app/src/terminal/view.rs @@ -314,7 +314,9 @@ use crate::terminal::shared_session::{ use crate::terminal::ssh::ssh_detection::SshInteractiveSessionDetected; use crate::terminal::view::block_onboarding::onboarding_prompt_block::OnboardingPromptBlock; use crate::terminal::warpify::{ - render::render_subshell_separator, settings::WarpifySettings, SubshellSource, + render::render_subshell_separator, + settings::{WarpifySettings, PIPENV_SUBSHELL_COMMAND_REGEX, POETRY_SUBSHELL_COMMAND_REGEX}, + SubshellSource, }; use crate::terminal::ShellLaunchData; use crate::terminal::{element_size_at_last_frame, HistoryEntry}; @@ -8036,7 +8038,12 @@ impl TerminalView { } } - self.write_init_subshell_bytes_to_pty(shell_type, ctx); + let is_pexpect_subshell = self.is_pexpect_subshell(ctx); + if is_pexpect_subshell { + self.write_init_subshell_bytes_to_pty_without_clearing(shell_type, ctx); + } else { + self.write_init_subshell_bytes_to_pty(shell_type, ctx); + } if !self.env_vars.is_empty() { self.start_bootstrap_timer(ENV_VAR_BOOTSTRAP_FAILED_DURATION, ctx); @@ -13539,6 +13546,35 @@ impl TerminalView { self.write_to_pty(vec![escape_sequences::C0::CR], ctx); } + /// Writes the InitShell DCS hook to the PTY for pexpect-based subshells (poetry, pipenv). + /// Unlike `write_init_subshell_bytes_to_pty`, this method does not send Ctrl-U/Ctrl-K to clear + /// the line first, as these control characters interfere with pexpect's PTY management. + fn write_init_subshell_bytes_to_pty_without_clearing( + &mut self, + shell_type: Option, + ctx: &mut ViewContext, + ) { + self.write_to_pty( + init_subshell_command(shell_type, &self.env_vars, ctx).into_bytes(), + ctx, + ); + self.write_to_pty(vec![escape_sequences::C0::CR], ctx); + } + + /// Returns true if the current subshell is a pexpect-based subshell (poetry or pipenv). + /// These subshells use pexpect's PTY management which is sensitive to control characters + /// like Ctrl-U and Ctrl-K. + fn is_pexpect_subshell(&self, ctx: &mut ViewContext) -> bool { + let Some(session) = self.active_session.session(ctx) else { + return false; + }; + let Some(subshell_info) = session.subshell_info() else { + return false; + }; + POETRY_SUBSHELL_COMMAND_REGEX.is_match(subshell_info.spawning_command.as_str()) + || PIPENV_SUBSHELL_COMMAND_REGEX.is_match(subshell_info.spawning_command.as_str()) + } + /// If a command correction exists, generate the command correction banner. fn after_command_correction_generation( &mut self,