fix(tui): render the /diff pager at the width it paints (#7053)

open_diff_pager rendered the diff at the transcript width minus two and
handed the pager finished lines. The pager body is narrower than that
(its margin, padding and scroll rail take five columns), so it wrapped
those lines a second time: a wrapped diff row lost its hanging indent
and left its last word alone at the left edge. At 60 columns:

          3 + A longer description line that is long
  enough
              to wrap when the terminal is narrow, with a

Keep the diff as the pager's source and render it in the pager's layout
at the body width, the way a text page is wrapped there. The rows fit,
so nothing wraps twice, and a resize renders the diff again instead of
re-wrapping the old rows. Copy still gives the sanitized diff, now from
the source.

Signed-off-by: Lstarsky0 <[email protected]>
This commit is contained in:
WissssleyL authored and GitHub committed 2026-10-23 05:35:25 +08:00
1 parent 0237e2983c
commit 3a113e7e4a
2 files changed
+19 -4

No files matched your search

+14 -1
View File
@@ -72,6 +72,7 @@ enum PagerSource {
Text(String),
/// Pre-styled lines, wrapped with their styles intact.
Lines(Vec<Line<'static>>),
Diff(String),
}
/// The display rows of one page and the column width they were wrapped to.
@@ -175,6 +176,13 @@ impl PagerPage {
*self.rows.borrow_mut() = match &self.source {
PagerSource::Text(source) => PagerRows::wrap_text(source, width),
PagerSource::Lines(lines) => PagerRows::wrap_lines(lines, width),
PagerSource::Diff(diff) => PagerRows::wrap_lines(
&crate::tui::diff_render::render_diff(
diff,
u16::try_from(width).unwrap_or(u16::MAX),
),
width,
),
};
true
}
@@ -196,7 +204,7 @@ impl PagerPage {
/// display wrapping.
fn source_text(&self) -> String {
match &self.source {
PagerSource::Text(source) => source.clone(),
PagerSource::Text(source) | PagerSource::Diff(source) => source.clone(),
PagerSource::Lines(lines) => lines
.iter()
.map(line_to_string)
@@ -359,6 +367,11 @@ impl PagerView {
Self::from_pages(vec![PagerPage::from_text(title, text, width)], 0)
}
pub(crate) fn from_diff(title: impl Into<String>, diff: String, width: u16) -> Self {
let page = PagerPage::new(title, PagerSource::Diff(diff), usize::from(width));
Self::from_pages(vec![page], 0)
}
/// Reuse the inspector confirmation control for token-bound commands.
/// Copy exposes the exact command; confirmation dispatches it unchanged.
pub(crate) fn command_review(
+5 -3
View File
@@ -328,9 +328,11 @@ pub(crate) fn open_diff_pager(app: &mut App, title: String, diff: &str) {
// `PagerView::from_text` applies to every other pager body.
let mut sanitized = String::with_capacity(diff.len());
crate::tui::osc8::strip_ansi_into(diff, &mut sanitized);
let lines = crate::tui::diff_render::render_diff(&sanitized, width.saturating_sub(2));
app.view_stack
.push(PagerView::new(title, lines).with_copy_text(sanitized));
app.view_stack.push(PagerView::from_diff(
title,
sanitized,
width.saturating_sub(2),
));
}
pub(crate) fn open_context_inspector(app: &mut App) {