Files
codex/codex-rs/tui/src/exec_command.rs
Eric Traut 61429a6c10 Rename tui_app_server to tui (#16104)
This is a follow-up to https://github.com/openai/codex/pull/15922. That
previous PR deleted the old `tui` directory and left the new
`tui_app_server` directory in place. This PR renames `tui_app_server` to
`tui` and fixes up all references.
2026-03-28 11:23:07 -06:00

108 lines
3.4 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_shell_command::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)
}
pub(crate) fn split_command_string(command: &str) -> Vec<String> {
let Some(parts) = shlex::split(command) else {
return vec![command.to_string()];
};
match shlex::try_join(parts.iter().map(String::as_str)) {
Ok(round_trip)
if round_trip == command
|| (!command.contains(":\\")
&& shlex::split(&round_trip).as_ref() == Some(&parts)) =>
{
parts
}
_ => vec![command.to_string()],
}
}
/// 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");
}
#[test]
fn split_command_string_round_trips_shell_wrappers() {
let command =
shlex::try_join(["/bin/zsh", "-lc", r#"python3 -c 'print("Hello, world!")'"#])
.expect("round-trippable command");
assert_eq!(
split_command_string(&command),
vec![
"/bin/zsh".to_string(),
"-lc".to_string(),
r#"python3 -c 'print("Hello, world!")'"#.to_string(),
]
);
}
#[test]
fn split_command_string_preserves_non_roundtrippable_windows_commands() {
let command = r#"C:\Program Files\Git\bin\bash.exe -lc "echo hi""#;
assert_eq!(split_command_string(command), vec![command.to_string()]);
}
}