fix bash commands being incorrectly quoted in display (#2313)

The "display format" of commands was sometimes producing incorrect
quoting like `echo foo '>' bar`, which is importantly different from the
actual command that was being run. This refactors ParsedCommand to have
a string in `cmd` instead of a vec, as a `vec` can't accurately capture
a full command.
This commit is contained in:
Jeremy Rose
2025-08-14 17:08:29 -04:00
committed by GitHub
parent 20cd61e2a4
commit 7038827bf4
3 changed files with 289 additions and 290 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -206,7 +206,7 @@ fn exec_history_cell_shows_working_then_completed() {
command: vec!["bash".into(), "-lc".into(), "echo done".into()], command: vec!["bash".into(), "-lc".into(), "echo done".into()],
cwd: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")), cwd: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
parsed_cmd: vec![codex_core::parse_command::ParsedCommand::Unknown { parsed_cmd: vec![codex_core::parse_command::ParsedCommand::Unknown {
cmd: vec!["echo".into(), "done".into()], cmd: "echo done".into(),
}], }],
}), }),
}); });
@@ -248,7 +248,7 @@ fn exec_history_cell_shows_working_then_failed() {
command: vec!["bash".into(), "-lc".into(), "false".into()], command: vec!["bash".into(), "-lc".into(), "false".into()],
cwd: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")), cwd: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
parsed_cmd: vec![codex_core::parse_command::ParsedCommand::Unknown { parsed_cmd: vec![codex_core::parse_command::ParsedCommand::Unknown {
cmd: vec!["false".into()], cmd: "false".into(),
}], }],
}), }),
}); });

View File

@@ -248,18 +248,19 @@ fn new_parsed_command(
ParsedCommand::Read { name, .. } => format!("📖 {name}"), ParsedCommand::Read { name, .. } => format!("📖 {name}"),
ParsedCommand::ListFiles { cmd, path } => match path { ParsedCommand::ListFiles { cmd, path } => match path {
Some(p) => format!("📂 {p}"), Some(p) => format!("📂 {p}"),
None => format!("📂 {}", shlex_join_safe(cmd)), None => format!("📂 {cmd}"),
}, },
ParsedCommand::Search { query, path, cmd } => match (query, path) { ParsedCommand::Search { query, path, cmd } => match (query, path) {
(Some(q), Some(p)) => format!("🔎 {q} in {p}"), (Some(q), Some(p)) => format!("🔎 {q} in {p}"),
(Some(q), None) => format!("🔎 {q}"), (Some(q), None) => format!("🔎 {q}"),
(None, Some(p)) => format!("🔎 {p}"), (None, Some(p)) => format!("🔎 {p}"),
(None, None) => format!("🔎 {}", shlex_join_safe(cmd)), (None, None) => format!("🔎 {cmd}"),
}, },
ParsedCommand::Format { .. } => "✨ Formatting".to_string(), ParsedCommand::Format { .. } => "✨ Formatting".to_string(),
ParsedCommand::Test { cmd } => format!("🧪 {}", shlex_join_safe(cmd)), ParsedCommand::Test { cmd } => format!("🧪 {cmd}"),
ParsedCommand::Lint { cmd, .. } => format!("🧹 {}", shlex_join_safe(cmd)), ParsedCommand::Lint { cmd, .. } => format!("🧹 {cmd}"),
ParsedCommand::Unknown { cmd } => format!("⌨️ {}", shlex_join_safe(cmd)), ParsedCommand::Unknown { cmd } => format!("⌨️ {cmd}"),
ParsedCommand::Noop { cmd } => format!("🔄 {cmd}"),
}; };
let first_prefix = if i == 0 { "" } else { " " }; let first_prefix = if i == 0 { "" } else { " " };
@@ -856,13 +857,6 @@ fn format_mcp_invocation<'a>(invocation: McpInvocation) -> Line<'a> {
Line::from(invocation_spans) Line::from(invocation_spans)
} }
fn shlex_join_safe(command: &[String]) -> String {
match shlex::try_join(command.iter().map(|s| s.as_str())) {
Ok(cmd) => cmd,
Err(_) => command.join(" "),
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -870,7 +864,7 @@ mod tests {
#[test] #[test]
fn parsed_command_with_newlines_starts_each_line_at_origin() { fn parsed_command_with_newlines_starts_each_line_at_origin() {
let parsed = vec![ParsedCommand::Unknown { let parsed = vec![ParsedCommand::Unknown {
cmd: vec!["printf".into(), "foo\nbar".into()], cmd: "printf 'foo\nbar'".to_string(),
}]; }];
let lines = exec_command_lines(&[], &parsed, None); let lines = exec_command_lines(&[], &parsed, None);
assert!(lines.len() >= 3); assert!(lines.len() >= 3);