From dd3882e1bf14584482006d20d72ffcb00e94f645 Mon Sep 17 00:00:00 2001 From: Hunter Bown Date: Sun, 3 May 2026 02:17:50 -0500 Subject: [PATCH] fix(utils): display_path normalizes home-relative suffix to platform separator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `display_path_with_home` joined the `~` prefix with `MAIN_SEPARATOR_STR` but called `rest.display()` for the suffix, which preserves whatever separators the input carried. On Windows that produced mixed-separator output like `~\projects/foo` for any path that came in with forward slashes — visible in the tests that #506 added to lock down the contract (the tests passed locally on Unix but failed on the windows-latest CI runner). Walk `rest.components()` and join each `Normal` component with `MAIN_SEPARATOR_STR`. Pure-Rust, no extra deps, behavior is byte-identical on Unix because the input separator was already `/`. Verified locally: - `cargo test -p deepseek-tui --locked display_path` ✓ (5 passed) Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/tui/src/utils.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/crates/tui/src/utils.rs b/crates/tui/src/utils.rs index d2b98030..63ef5002 100644 --- a/crates/tui/src/utils.rs +++ b/crates/tui/src/utils.rs @@ -344,6 +344,10 @@ pub fn display_path(path: &Path) -> String { /// Like [`display_path`] but takes an explicit home directory instead of /// reading `$HOME` / `dirs::home_dir()`. Used in tests and anywhere the /// caller already has the home path available. +/// +/// The home-relative suffix is rejoined with the platform separator +/// (`\` on Windows, `/` elsewhere) by walking the path's components, so +/// inputs that carried foreign separators don't leak through. #[must_use] pub fn display_path_with_home(path: &Path, home: Option<&Path>) -> String { let Some(home) = home else { @@ -353,8 +357,13 @@ pub fn display_path_with_home(path: &Path, home: Option<&Path>) -> String { if rest.as_os_str().is_empty() { return "~".to_string(); } - let sep = std::path::MAIN_SEPARATOR; - return format!("~{sep}{}", rest.display()); + let sep = std::path::MAIN_SEPARATOR_STR; + let mut out = String::from("~"); + for component in rest.components() { + out.push_str(sep); + out.push_str(&component.as_os_str().to_string_lossy()); + } + return out; } path.display().to_string() }