aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pane.rs6
-rw-r--r--src/platform/mod.rs9
-rw-r--r--src/platform/windows.rs63
3 files changed, 70 insertions, 8 deletions
diff --git a/src/pane.rs b/src/pane.rs
index 4ac86c23..ec1b8646 100644
--- a/src/pane.rs
+++ b/src/pane.rs
@@ -2009,7 +2009,7 @@ impl PaneRuntime {
let windows_powershell_prompt_cwd_reporting =
uses_windows_powershell_pane_shell(shell_config);
let mut cmd = pane_shell_command_builder(shell_config)?;
- cmd.cwd(cwd);
+ cmd.cwd(crate::platform::normalize_cwd_for_launch(&cwd));
apply_pane_terminal_env(&mut cmd);
apply_pane_launch_env(&mut cmd, launch_env);
Self::spawn_command_builder(
@@ -2051,7 +2051,7 @@ impl PaneRuntime {
render_dirty: Arc<RenderSignal>,
) -> std::io::Result<Self> {
let mut cmd = crate::platform::pane_custom_command_pty_builder(command);
- cmd.cwd(cwd);
+ cmd.cwd(crate::platform::normalize_cwd_for_launch(&cwd));
apply_pane_terminal_env(&mut cmd);
apply_pane_launch_env(&mut cmd, launch_env);
Self::spawn_command_builder(
@@ -2098,7 +2098,7 @@ impl PaneRuntime {
for arg in args {
cmd.arg(arg);
}
- cmd.cwd(cwd);
+ cmd.cwd(crate::platform::normalize_cwd_for_launch(&cwd));
apply_pane_terminal_env(&mut cmd);
apply_pane_launch_env(&mut cmd, launch_env);
Self::spawn_command_builder(
diff --git a/src/platform/mod.rs b/src/platform/mod.rs
index a578b42d..70047fef 100644
--- a/src/platform/mod.rs
+++ b/src/platform/mod.rs
@@ -82,6 +82,15 @@ pub(crate) fn plugin_runtime_path(path: &std::path::Path) -> std::path::PathBuf
plugin_runtime_path_platform(path)
}
+pub(crate) fn normalize_cwd_for_launch(path: &std::path::Path) -> std::path::PathBuf {
+ normalize_cwd_for_launch_platform(path)
+}
+
+#[cfg(not(windows))]
+fn normalize_cwd_for_launch_platform(path: &std::path::Path) -> std::path::PathBuf {
+ path.to_path_buf()
+}
+
#[cfg(not(windows))]
fn plugin_runtime_path_platform(path: &std::path::Path) -> std::path::PathBuf {
path.to_path_buf()
diff --git a/src/platform/windows.rs b/src/platform/windows.rs
index 080bbf34..9742b52c 100644
--- a/src/platform/windows.rs
+++ b/src/platform/windows.rs
@@ -380,6 +380,54 @@ pub(crate) fn prepare_paste_text_for_pty_platform(text: String) -> String {
text.replace("\r\n", "\n").replace('\n', "\r\n")
}
+pub(crate) fn normalize_cwd_for_launch_platform(path: &std::path::Path) -> PathBuf {
+ use std::os::windows::ffi::{OsStrExt, OsStringExt};
+ use std::path::{Component, Prefix};
+ use windows_sys::Win32::{
+ Foundation::INVALID_HANDLE_VALUE,
+ Storage::FileSystem::{FindClose, FindFirstFileW, WIN32_FIND_DATAW},
+ };
+
+ fn stored_name(path: &std::path::Path) -> Option<std::ffi::OsString> {
+ let input = path
+ .as_os_str()
+ .encode_wide()
+ .chain(std::iter::once(0))
+ .collect::<Vec<_>>();
+ let mut data = std::mem::MaybeUninit::<WIN32_FIND_DATAW>::uninit();
+ let handle = unsafe { FindFirstFileW(input.as_ptr(), data.as_mut_ptr()) };
+ if handle == INVALID_HANDLE_VALUE {
+ return None;
+ }
+ let data = unsafe { data.assume_init() };
+ unsafe { FindClose(handle) };
+ let len = data
+ .cFileName
+ .iter()
+ .position(|&ch| ch == 0)
+ .unwrap_or(data.cFileName.len());
+ Some(std::ffi::OsString::from_wide(&data.cFileName[..len]))
+ }
+
+ let mut normalized = PathBuf::new();
+ for component in path.components() {
+ match component {
+ Component::Prefix(prefix) => match prefix.kind() {
+ Prefix::Disk(drive) => {
+ normalized.push(format!("{}:", char::from(drive).to_ascii_uppercase()))
+ }
+ _ => normalized.push(prefix.as_os_str()),
+ },
+ Component::Normal(name) => {
+ let candidate = normalized.join(name);
+ normalized.push(stored_name(&candidate).unwrap_or_else(|| name.to_os_string()));
+ }
+ _ => normalized.push(component.as_os_str()),
+ }
+ }
+ normalized
+}
+
pub(crate) fn plugin_runtime_path_platform(path: &std::path::Path) -> PathBuf {
use std::os::windows::ffi::OsStrExt;
@@ -3399,15 +3447,17 @@ mod tests {
}
#[test]
- fn windows_process_cwd_reads_child_launch_directory() {
- let cwd = std::env::temp_dir().join(format!("herdr-cwd-test-{}", std::process::id()));
+ fn windows_process_cwd_reads_normalized_child_launch_directory() {
+ let name = format!("Herdr-Cwd-Case-{}", std::process::id());
+ let cwd = std::env::temp_dir().join(&name);
fs::create_dir_all(&cwd).expect("create cwd fixture");
+ let launch_cwd = cwd.with_file_name(name.to_ascii_lowercase());
let shell =
std::env::var_os("ComSpec").unwrap_or_else(|| r"C:\Windows\System32\cmd.exe".into());
let mut child = Command::new(shell)
.args(["/D", "/Q", "/C", "ping -n 11 127.0.0.1 > NUL"])
- .current_dir(&cwd)
+ .current_dir(super::normalize_cwd_for_launch_platform(&launch_cwd))
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
@@ -3418,7 +3468,7 @@ mod tests {
let mut observed = None;
while Instant::now() < deadline {
observed = super::process_cwd(child.id());
- if observed.as_deref() == Some(cwd.as_path()) {
+ if observed.as_ref().and_then(|path| path.file_name()) == Some(name.as_ref()) {
break;
}
thread::sleep(Duration::from_millis(100));
@@ -3428,7 +3478,10 @@ mod tests {
let _ = child.wait();
let _ = fs::remove_dir_all(&cwd);
- assert_eq!(observed.as_deref(), Some(cwd.as_path()));
+ assert_eq!(
+ observed.as_ref().and_then(|path| path.file_name()),
+ Some(name.as_ref())
+ );
}
#[test]