Run command UI (#1897)

Edit how commands show:

<img width="243" height="119" alt="image"
src="https://github.com/user-attachments/assets/13d5608e-3b66-4b8d-8fe7-ce464310d85d"
/>
This commit is contained in:
aibrahim-oai
2025-08-06 17:10:59 -07:00
committed by GitHub
parent 8a980399c5
commit a5e17cda6b
2 changed files with 27 additions and 24 deletions

View File

@@ -485,7 +485,7 @@ impl ChatWidget<'_> {
EventMsg::ExecCommandEnd(ExecCommandEndEvent { EventMsg::ExecCommandEnd(ExecCommandEndEvent {
call_id, call_id,
exit_code, exit_code,
duration, duration: _,
stdout, stdout,
stderr, stderr,
}) => { }) => {
@@ -498,7 +498,6 @@ impl ChatWidget<'_> {
exit_code, exit_code,
stdout, stdout,
stderr, stderr,
duration,
}, },
)); ));
} }

View File

@@ -38,7 +38,6 @@ pub(crate) struct CommandOutput {
pub(crate) exit_code: i32, pub(crate) exit_code: i32,
pub(crate) stdout: String, pub(crate) stdout: String,
pub(crate) stderr: String, pub(crate) stderr: String,
pub(crate) duration: Duration,
} }
pub(crate) enum PatchEventType { pub(crate) enum PatchEventType {
@@ -122,7 +121,7 @@ pub(crate) enum HistoryCell {
PatchApplyResult { view: TextBlock }, PatchApplyResult { view: TextBlock },
} }
const TOOL_CALL_MAX_LINES: usize = 5; const TOOL_CALL_MAX_LINES: usize = 3;
impl HistoryCell { impl HistoryCell {
/// Return a cloned, plain representation of the cell's lines suitable for /// Return a cloned, plain representation of the cell's lines suitable for
@@ -232,8 +231,11 @@ impl HistoryCell {
let command_escaped = strip_bash_lc_and_escape(&command); let command_escaped = strip_bash_lc_and_escape(&command);
let lines: Vec<Line<'static>> = vec![ let lines: Vec<Line<'static>> = vec![
Line::from(vec!["command".magenta(), " running...".dim()]), Line::from(vec![
Line::from(format!("$ {command_escaped}")), "".cyan(),
"Running command ".magenta(),
command_escaped.into(),
]),
Line::from(""), Line::from(""),
]; ];
@@ -247,34 +249,36 @@ impl HistoryCell {
exit_code, exit_code,
stdout, stdout,
stderr, stderr,
duration,
} = output; } = output;
let mut lines: Vec<Line<'static>> = Vec::new(); let mut lines: Vec<Line<'static>> = Vec::new();
let command_escaped = strip_bash_lc_and_escape(&command);
// Title depends on whether we have output yet. lines.push(Line::from(vec![
let title_line = Line::from(vec![ "⚡Ran command ".magenta(),
"command".magenta(), command_escaped.into(),
format!( ]));
" (code: {}, duration: {})",
exit_code,
format_duration(duration)
)
.dim(),
]);
lines.push(title_line);
let src = if exit_code == 0 { stdout } else { stderr }; let src = if exit_code == 0 { stdout } else { stderr };
let cmdline = strip_bash_lc_and_escape(&command);
lines.push(Line::from(format!("$ {cmdline}")));
let mut lines_iter = src.lines(); let mut lines_iter = src.lines();
for raw in lines_iter.by_ref().take(TOOL_CALL_MAX_LINES) { for (idx, raw) in lines_iter.by_ref().take(TOOL_CALL_MAX_LINES).enumerate() {
lines.push(ansi_escape_line(raw).dim()); let mut line = ansi_escape_line(raw);
let prefix = if idx == 0 { "" } else { " " };
line.spans.insert(0, prefix.into());
line.spans.iter_mut().for_each(|span| {
span.style = span.style.add_modifier(Modifier::DIM);
});
lines.push(line);
} }
let remaining = lines_iter.count(); let remaining = lines_iter.count();
if remaining > 0 { if remaining > 0 {
lines.push(Line::from(format!("... {remaining} additional lines")).dim()); let mut more = Line::from(format!("... +{remaining} lines"));
// Continuation/ellipsis is treated as a subsequent line for prefixing
more.spans.insert(0, " ".into());
more.spans.iter_mut().for_each(|span| {
span.style = span.style.add_modifier(Modifier::DIM);
});
lines.push(more);
} }
lines.push(Line::from("")); lines.push(Line::from(""));