From 19022d03c902de586009b1d156bc20b01ce48135 Mon Sep 17 00:00:00 2001 From: JJ Liebig Date: Mon, 17 Aug 2026 22:29:47 +0200 Subject: fix: sync powershell process working directory (#2879) --- src/pane.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/pane.rs b/src/pane.rs index a47e62eb..0b3edf7d 100644 --- a/src/pane.rs +++ b/src/pane.rs @@ -1474,8 +1474,8 @@ fn resolve_shell_for_login_mode(shell: &str) -> io::Result { /// wraps whatever `prompt` function the user's profile left behind so each /// prompt render appends the cwd as OSC 9;9 — the sequence Windows Terminal /// and ConEmu standardized for shell integration. PowerShell never updates -/// its Win32 process cwd on `Set-Location`, so prompt-time reporting is the -/// only reliable cwd source on Windows. +/// its Win32 process cwd on `Set-Location`, so the prompt hook updates it when +/// possible before reporting the cwd. /// /// The snippet must not contain double quotes: powershell.exe parses its /// command line with its own rules that disagree with the ArgvQuote escaping @@ -1487,7 +1487,7 @@ fn resolve_shell_for_login_mode(shell: &str) -> io::Result { /// The original prompt must be invoked before any other statement in the /// wrapper: anything that runs first resets `$?`, so a status-aware user /// prompt would show success after a failed command (verified on 5.1). -pub(crate) const WINDOWS_POWERSHELL_SHELL_INTEGRATION_COMMAND: &str = r"if ($null -eq $global:__HerdrOriginalPrompt) { $global:__HerdrOriginalPrompt = $function:prompt; function global:prompt { $out = @(& $global:__HerdrOriginalPrompt) -join ' '; $loc = $ExecutionContext.SessionState.Path.CurrentLocation; if ($loc.Provider.Name -eq 'FileSystem') { $esc = [string][char]27; $out += $esc + ']9;9;' + $loc.ProviderPath + $esc + '\' }; $out } }"; +pub(crate) const WINDOWS_POWERSHELL_SHELL_INTEGRATION_COMMAND: &str = r"if ($null -eq $global:__HerdrOriginalPrompt) { $global:__HerdrOriginalPrompt = $function:prompt; function global:prompt { $out = @(& $global:__HerdrOriginalPrompt) -join ' '; $loc = $ExecutionContext.SessionState.Path.CurrentLocation; if ($loc.Provider.Name -eq 'FileSystem') { try { [Environment]::CurrentDirectory = $loc.ProviderPath } catch {}; $esc = [string][char]27; $out += $esc + ']9;9;' + $loc.ProviderPath + $esc + '\' }; $out } }"; fn pane_shell_command_builder_for_target( shell_config: PaneShellConfig<'_>, @@ -3350,7 +3350,11 @@ mod tests { } let script = WINDOWS_POWERSHELL_SHELL_INTEGRATION_COMMAND; - assert!(script.contains("]9;9;"), "missing OSC 9;9 emit: {script}"); + let cwd_sync = script + .find("[Environment]::CurrentDirectory = $loc.ProviderPath") + .expect("wrapper must synchronize the Win32 process cwd"); + let osc_report = script.find("]9;9;").expect("wrapper must emit OSC 9;9"); + assert!(cwd_sync < osc_report, "cwd sync must precede OSC report"); assert!( script.contains("$global:__HerdrOriginalPrompt = $function:prompt"), "must wrap the profile-defined prompt: {script}" -- cgit v1.2.3