fix: the 7 omitted lines issue (#5141)
Before, the CLI was always showing `... +7 lines` (with the 7 constant) due to a double truncation <img width="263" height="127" alt="Screenshot 2025-10-13 at 10 28 11" src="https://github.com/user-attachments/assets/49a92d2b-c28a-4e2f-96d1-1818955470b8" />
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
source: tui/src/chatwidget/tests.rs
|
source: tui/src/chatwidget/tests.rs
|
||||||
assertion_line: 1152
|
|
||||||
expression: "lines[start_idx..].join(\"\\n\")"
|
expression: "lines[start_idx..].join(\"\\n\")"
|
||||||
---
|
---
|
||||||
• I need to check the codex-rs repository to explain why the project's binaries
|
• I need to check the codex-rs repository to explain why the project's binaries
|
||||||
@@ -33,7 +32,7 @@ expression: "lines[start_idx..].join(\"\\n\")"
|
|||||||
│ … +1 lines
|
│ … +1 lines
|
||||||
└ --- ansi-escape/Cargo.toml
|
└ --- ansi-escape/Cargo.toml
|
||||||
[package]
|
[package]
|
||||||
… +7 lines
|
… +243 lines
|
||||||
] }
|
] }
|
||||||
tracing = { version
|
tracing = { version
|
||||||
|
|
||||||
|
|||||||
@@ -48,10 +48,16 @@ pub(crate) fn new_active_exec_command(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct OutputLines {
|
||||||
|
pub(crate) lines: Vec<Line<'static>>,
|
||||||
|
pub(crate) omitted: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn output_lines(
|
pub(crate) fn output_lines(
|
||||||
output: Option<&CommandOutput>,
|
output: Option<&CommandOutput>,
|
||||||
params: OutputLinesParams,
|
params: OutputLinesParams,
|
||||||
) -> Vec<Line<'static>> {
|
) -> OutputLines {
|
||||||
let OutputLinesParams {
|
let OutputLinesParams {
|
||||||
only_err,
|
only_err,
|
||||||
include_angle_pipe,
|
include_angle_pipe,
|
||||||
@@ -63,9 +69,19 @@ pub(crate) fn output_lines(
|
|||||||
stderr,
|
stderr,
|
||||||
..
|
..
|
||||||
} = match output {
|
} = match output {
|
||||||
Some(output) if only_err && output.exit_code == 0 => return vec![],
|
Some(output) if only_err && output.exit_code == 0 => {
|
||||||
|
return OutputLines {
|
||||||
|
lines: Vec::new(),
|
||||||
|
omitted: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
Some(output) => output,
|
Some(output) => output,
|
||||||
None => return vec![],
|
None => {
|
||||||
|
return OutputLines {
|
||||||
|
lines: Vec::new(),
|
||||||
|
omitted: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let src = if *exit_code == 0 { stdout } else { stderr };
|
let src = if *exit_code == 0 { stdout } else { stderr };
|
||||||
@@ -73,7 +89,7 @@ pub(crate) fn output_lines(
|
|||||||
let total = lines.len();
|
let total = lines.len();
|
||||||
let limit = TOOL_CALL_MAX_LINES;
|
let limit = TOOL_CALL_MAX_LINES;
|
||||||
|
|
||||||
let mut out = Vec::new();
|
let mut out: Vec<Line<'static>> = Vec::new();
|
||||||
|
|
||||||
let head_end = total.min(limit);
|
let head_end = total.min(limit);
|
||||||
for (i, raw) in lines[..head_end].iter().enumerate() {
|
for (i, raw) in lines[..head_end].iter().enumerate() {
|
||||||
@@ -93,6 +109,11 @@ pub(crate) fn output_lines(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let show_ellipsis = total > 2 * limit;
|
let show_ellipsis = total > 2 * limit;
|
||||||
|
let omitted = if show_ellipsis {
|
||||||
|
Some(total - 2 * limit)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
if show_ellipsis {
|
if show_ellipsis {
|
||||||
let omitted = total - 2 * limit;
|
let omitted = total - 2 * limit;
|
||||||
out.push(format!("… +{omitted} lines").into());
|
out.push(format!("… +{omitted} lines").into());
|
||||||
@@ -114,7 +135,10 @@ pub(crate) fn output_lines(
|
|||||||
out.push(line);
|
out.push(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
out
|
OutputLines {
|
||||||
|
lines: out,
|
||||||
|
omitted,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn spinner(start_time: Option<Instant>) -> Span<'static> {
|
pub(crate) fn spinner(start_time: Option<Instant>) -> Span<'static> {
|
||||||
@@ -371,7 +395,7 @@ impl ExecCell {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(output) = call.output.as_ref() {
|
if let Some(output) = call.output.as_ref() {
|
||||||
let raw_output_lines = output_lines(
|
let raw_output = output_lines(
|
||||||
Some(output),
|
Some(output),
|
||||||
OutputLinesParams {
|
OutputLinesParams {
|
||||||
only_err: false,
|
only_err: false,
|
||||||
@@ -380,15 +404,18 @@ impl ExecCell {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if raw_output_lines.is_empty() {
|
if raw_output.lines.is_empty() {
|
||||||
lines.extend(prefix_lines(
|
lines.extend(prefix_lines(
|
||||||
vec![Line::from("(no output)".dim())],
|
vec![Line::from("(no output)".dim())],
|
||||||
Span::from(layout.output_block.initial_prefix).dim(),
|
Span::from(layout.output_block.initial_prefix).dim(),
|
||||||
Span::from(layout.output_block.subsequent_prefix),
|
Span::from(layout.output_block.subsequent_prefix),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
let trimmed_output =
|
let trimmed_output = Self::truncate_lines_middle(
|
||||||
Self::truncate_lines_middle(&raw_output_lines, layout.output_max_lines);
|
&raw_output.lines,
|
||||||
|
layout.output_max_lines,
|
||||||
|
raw_output.omitted,
|
||||||
|
);
|
||||||
|
|
||||||
let mut wrapped_output: Vec<Line<'static>> = Vec::new();
|
let mut wrapped_output: Vec<Line<'static>> = Vec::new();
|
||||||
let output_wrap_width = layout.output_block.wrap_width(width);
|
let output_wrap_width = layout.output_block.wrap_width(width);
|
||||||
@@ -427,7 +454,11 @@ impl ExecCell {
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
fn truncate_lines_middle(lines: &[Line<'static>], max: usize) -> Vec<Line<'static>> {
|
fn truncate_lines_middle(
|
||||||
|
lines: &[Line<'static>],
|
||||||
|
max: usize,
|
||||||
|
omitted_hint: Option<usize>,
|
||||||
|
) -> Vec<Line<'static>> {
|
||||||
if max == 0 {
|
if max == 0 {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
@@ -435,7 +466,17 @@ impl ExecCell {
|
|||||||
return lines.to_vec();
|
return lines.to_vec();
|
||||||
}
|
}
|
||||||
if max == 1 {
|
if max == 1 {
|
||||||
return vec![Self::ellipsis_line(lines.len())];
|
// Carry forward any previously omitted count and add any
|
||||||
|
// additionally hidden content lines from this truncation.
|
||||||
|
let base = omitted_hint.unwrap_or(0);
|
||||||
|
// When an existing ellipsis is present, `lines` already includes
|
||||||
|
// that single representation line; exclude it from the count of
|
||||||
|
// additionally omitted content lines.
|
||||||
|
let extra = lines
|
||||||
|
.len()
|
||||||
|
.saturating_sub(usize::from(omitted_hint.is_some()));
|
||||||
|
let omitted = base + extra;
|
||||||
|
return vec![Self::ellipsis_line(omitted)];
|
||||||
}
|
}
|
||||||
|
|
||||||
let head = (max - 1) / 2;
|
let head = (max - 1) / 2;
|
||||||
@@ -446,8 +487,12 @@ impl ExecCell {
|
|||||||
out.extend(lines[..head].iter().cloned());
|
out.extend(lines[..head].iter().cloned());
|
||||||
}
|
}
|
||||||
|
|
||||||
let omitted = lines.len().saturating_sub(head + tail);
|
let base = omitted_hint.unwrap_or(0);
|
||||||
out.push(Self::ellipsis_line(omitted));
|
let additional = lines
|
||||||
|
.len()
|
||||||
|
.saturating_sub(head + tail)
|
||||||
|
.saturating_sub(usize::from(omitted_hint.is_some()));
|
||||||
|
out.push(Self::ellipsis_line(base + additional));
|
||||||
|
|
||||||
if tail > 0 {
|
if tail > 0 {
|
||||||
out.extend(lines[lines.len() - tail..].iter().cloned());
|
out.extend(lines[lines.len() - tail..].iter().cloned());
|
||||||
|
|||||||
@@ -1148,7 +1148,7 @@ pub(crate) fn new_patch_apply_failure(stderr: String) -> PlainHistoryCell {
|
|||||||
lines.push(Line::from("✘ Failed to apply patch".magenta().bold()));
|
lines.push(Line::from("✘ Failed to apply patch".magenta().bold()));
|
||||||
|
|
||||||
if !stderr.trim().is_empty() {
|
if !stderr.trim().is_empty() {
|
||||||
lines.extend(output_lines(
|
let output = output_lines(
|
||||||
Some(&CommandOutput {
|
Some(&CommandOutput {
|
||||||
exit_code: 1,
|
exit_code: 1,
|
||||||
stdout: String::new(),
|
stdout: String::new(),
|
||||||
@@ -1160,7 +1160,8 @@ pub(crate) fn new_patch_apply_failure(stderr: String) -> PlainHistoryCell {
|
|||||||
include_angle_pipe: true,
|
include_angle_pipe: true,
|
||||||
include_prefix: true,
|
include_prefix: true,
|
||||||
},
|
},
|
||||||
));
|
);
|
||||||
|
lines.extend(output.lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
PlainHistoryCell { lines }
|
PlainHistoryCell { lines }
|
||||||
|
|||||||
Reference in New Issue
Block a user