core-agent-ide/codex-rs/tui/src/exec_command.rs
Dylan Hurd 28ebe1c97a
fix(windows) shell_command on windows, minor parsing (#6811)
## Summary
Enables shell_command for windows users, and starts adding some basic
command parsing here, to at least remove powershell prefixes. We'll
follow this up with command parsing but I wanted to land this change
separately with some basic UX.

**NOTE**: This implementation parses bash and powershell on both
platforms. In theory this is possible, since you can use git bash on
windows or powershell on linux. In practice, this may not be worth the
complexity of supporting, so I don't feel strongly about the current
approach vs. platform-specific branching.

## Testing
- [x] Added a bunch of tests 
- [x] Ran on both windows and os x
2025-11-17 22:23:53 -08:00

70 lines
2.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::path::Path;
use std::path::PathBuf;
use codex_core::parse_command::extract_shell_command;
use dirs::home_dir;
use shlex::try_join;
pub(crate) fn escape_command(command: &[String]) -> String {
try_join(command.iter().map(String::as_str)).unwrap_or_else(|_| command.join(" "))
}
pub(crate) fn strip_bash_lc_and_escape(command: &[String]) -> String {
if let Some((_, script)) = extract_shell_command(command) {
return script.to_string();
}
escape_command(command)
}
/// If `path` is absolute and inside $HOME, return the part *after* the home
/// directory; otherwise, return the path as-is. Note if `path` is the homedir,
/// this will return and empty path.
pub(crate) fn relativize_to_home<P>(path: P) -> Option<PathBuf>
where
P: AsRef<Path>,
{
let path = path.as_ref();
if !path.is_absolute() {
// If the path is not absolute, we cant do anything with it.
return None;
}
let home_dir = home_dir()?;
let rel = path.strip_prefix(&home_dir).ok()?;
Some(rel.to_path_buf())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_escape_command() {
let args = vec!["foo".into(), "bar baz".into(), "weird&stuff".into()];
let cmdline = escape_command(&args);
assert_eq!(cmdline, "foo 'bar baz' 'weird&stuff'");
}
#[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");
}
}