Strip zsh -lc wrapper from TUI command headers (#5374)

Extends shell wrapper stripping in TUI to handle `zsh -lc` in addition
to `bash -lc`.

Currently, Linux users (and macOS users with zsh profiles) see cluttered
command headers like `• Ran zsh -lc "echo hello"` instead of `• Ran echo
hello`. This happens because `codex-rs/tui/src/exec_command.rs` only
checks for literal `"bash"`, ignoring `zsh` and absolute paths like
`/usr/bin/zsh`.

**Changes:**
- Added `is_login_shell_with_lc` helper that extracts shell basename and
matches against `bash` or `zsh`
- Updated pattern matching to use the helper instead of hardcoded check
- Added test coverage for zsh and absolute paths (`/usr/bin/zsh`,
`/bin/bash`)

**Testing:**
```bash
cd codex-rs
cargo test strip_bash_lc_and_escape -p codex-tui
```

All 4 test cases pass (bash, zsh, and absolute paths for both).

Closes #4201
This commit is contained in:
hxreborn
2025-10-20 19:24:39 +02:00
committed by GitHub
parent 3282e86a60
commit 0e8d937a3f
2 changed files with 29 additions and 6 deletions

View File

@@ -485,11 +485,10 @@ mod tests {
})
.collect();
let expected = vec![
"✔ You approved codex to".to_string(),
" run /bin/zsh -lc 'git add".to_string(),
" tui/src/render/mod.rs tui/".to_string(),
" src/render/renderable.rs'".to_string(),
" this time".to_string(),
"✔ You approved codex to run".to_string(),
" git add tui/src/render/".to_string(),
" mod.rs tui/src/render/".to_string(),
" renderable.rs this time".to_string(),
];
assert_eq!(rendered, expected);
}

View File

@@ -8,9 +8,17 @@ pub(crate) fn escape_command(command: &[String]) -> String {
try_join(command.iter().map(String::as_str)).unwrap_or_else(|_| command.join(" "))
}
fn is_login_shell_with_lc(shell: &str) -> bool {
let shell_name = std::path::Path::new(shell)
.file_name()
.and_then(|s| s.to_str())
.unwrap_or(shell);
matches!(shell_name, "bash" | "zsh")
}
pub(crate) fn strip_bash_lc_and_escape(command: &[String]) -> String {
match command {
[first, second, third] if first == "bash" && second == "-lc" => third.clone(),
[first, second, third] if is_login_shell_with_lc(first) && second == "-lc" => third.clone(),
_ => escape_command(command),
}
}
@@ -46,8 +54,24 @@ mod tests {
#[test]
fn test_strip_bash_lc_and_escape() {
// Test bash
let args = vec!["bash".into(), "-lc".into(), "echo hello".into()];
let cmdline = strip_bash_lc_and_escape(&args);
assert_eq!(cmdline, "echo hello");
// Test zsh
let args = vec!["zsh".into(), "-lc".into(), "echo hello".into()];
let cmdline = strip_bash_lc_and_escape(&args);
assert_eq!(cmdline, "echo hello");
// Test absolute path to zsh
let args = vec!["/usr/bin/zsh".into(), "-lc".into(), "echo hello".into()];
let cmdline = strip_bash_lc_and_escape(&args);
assert_eq!(cmdline, "echo hello");
// Test absolute path to bash
let args = vec!["/bin/bash".into(), "-lc".into(), "echo hello".into()];
let cmdline = strip_bash_lc_and_escape(&args);
assert_eq!(cmdline, "echo hello");
}
}