mirror of
https://github.com/openai/codex.git
synced 2026-05-02 02:17:22 +00:00
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.
108 lines
3.4 KiB
Rust
108 lines
3.4 KiB
Rust
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 can’t 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()]);
|
||
}
|
||
}
|