Skip to content

[Diff] Thread the [diff] config through the viewer and zoom with z - #49

Merged
KCaverly merged 2 commits into
mainfrom
ct/diff_view/f8a397f5
Jul 28, 2026
Merged

[Diff] Thread the [diff] config through the viewer and zoom with z#49
KCaverly merged 2 commits into
mainfrom
ct/diff_view/f8a397f5

Conversation

@KCaverly

@KCaverly KCaverly commented Jul 26, 2026

Copy link
Copy Markdown
Owner

The preview splits the width between the commit list and the diff, which is
fine for a unified patch but cramped for a side-by-side pager: two code
columns need room the list is taking. z now hides the list so the diff spans
the whole terminal, and toggles back.

Zoomed, the diff owns the keyboard whether or not it held focus — j/k scroll,
] / [ jump files, n / p step commits — so reading a full-width diff needs no
tab dance. tab has nothing to flip to and is inert; z or d bring the list
back. The header reads [zoom] diff, and the footer names z as "show list".

Because the zoomed layout is a single column, it is allowed below the
two-column minimum width: a resize down after zooming keeps showing the diff
rather than snapping back to the plain list. splitShown and stackDiffFocused
are the two predicates the renderer, key routing and wheel all share, so none
of them can disagree about whether the diff is on screen or who owns a key.

Zoom clears when the preview closes, so the next open starts in the standard
two-column layout and the open-time width guard stays coherent; it survives a
status refresh, since that leaves you reading the same view.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com


Stack (bottom → top):

  1. [Diff] Add the external diff pager package #51
  2. [Diff] Thread the [diff] config through the viewer and zoom with z #49 ← this PR
  3. [Docs] Document the diff viewer settings #53

@KCaverly
KCaverly force-pushed the ct/diff_view/995b1b40 branch from eb62af7 to 2e9386d Compare July 26, 2026 19:24
@KCaverly
KCaverly force-pushed the ct/diff_view/f8a397f5 branch from 7cb84fd to 554a575 Compare July 26, 2026 19:24
@KCaverly
KCaverly force-pushed the ct/diff_view/995b1b40 branch from 2e9386d to 14f9032 Compare July 26, 2026 19:30
@KCaverly
KCaverly force-pushed the ct/diff_view/f8a397f5 branch from 554a575 to efe9450 Compare July 26, 2026 19:30
@KCaverly
KCaverly force-pushed the ct/diff_view/995b1b40 branch from 14f9032 to 4317268 Compare July 26, 2026 19:34
@KCaverly
KCaverly force-pushed the ct/diff_view/f8a397f5 branch from efe9450 to d86f6ca Compare July 26, 2026 19:34
@KCaverly
KCaverly force-pushed the ct/diff_view/995b1b40 branch from 4317268 to 19702e6 Compare July 26, 2026 19:39
@KCaverly
KCaverly force-pushed the ct/diff_view/f8a397f5 branch from d86f6ca to 46c1c4c Compare July 26, 2026 19:40
@KCaverly
KCaverly force-pushed the ct/diff_view/995b1b40 branch from 19702e6 to f157ff7 Compare July 26, 2026 19:41
@KCaverly
KCaverly force-pushed the ct/diff_view/f8a397f5 branch from 46c1c4c to 90adf42 Compare July 26, 2026 19:41
Base automatically changed from ct/diff_view/995b1b40 to main July 26, 2026 19:43
@KCaverly
KCaverly force-pushed the ct/diff_view/f8a397f5 branch from 90adf42 to 25916e9 Compare July 26, 2026 20:27
diffpager pipes each file's patch through an external formatter (delta,
diff-so-fancy, bat) while ct keeps ownership of scrolling and keybindings.
A zero-value Pager is inert, so the default stays ct's built-in styling.

The body is split on `diff --git` boundaries and each file rendered as its
own Chunk, which is what preserves the viewer's file-jump index. Headers
are matched against ANSI-stripped text so a user running --color=always
does not collapse the whole patch into one chunk and lose that index.

Rendering is all-or-nothing: the caller's fallback is to re-render with
ct's built-in styling, and a half-formatted patch would be worse than
either. Chunks render concurrently under a worker cap, since a 40-file
diff spawning processes serially would cost 40x a single process's
latency on the fetch path. A 30s timeout bounds the whole call so a
formatter that hangs cannot strand the fetch goroutine, and the first
failure cancels the rest rather than waiting out the budget.

cmd.Dir is set to the repo so a formatter reading .gitattributes or git
config sees the right repo, and COLUMNS is set because several formatters
size their output from it when stdout is not a terminal — which, piped
into a Builder, it never is.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ct-stack-id: ecdcdaf3
Three changes that cannot build apart, so they land as one: repo.DiffOptions
changes the signature of every diff call, the viewer supplies those options and
reads cfg.Diff.Pager, and the config that defines them is exercised by tests
calling the viewer's own m.diffOptions() and m.diffPager(). Any split leaves an
intermediate commit that does not compile.

repo: adds repo.DiffOptions, threading the user's extra git diff flags and
exclude pathspecs in from config rather than reading config here - repo stays
the layer that only talks to git, and these functions stay testable without a
settings file. Args land after ct's pinned diffBodyFlags and before the
revisions, so a user flag wins over a pinned one. This is what makes
`--color=always` a supported override of the pinned --no-color, for feeding a
formatter that wants coloured input. --no-ext-diff stays non-negotiable:
nothing downstream can recover a patch from an external tool's output. Both
Args and Exclude apply to the --numstat calls and the untracked-file listing as
well as the patch calls, since the numstat feeds the file index and the +/-
totals in the viewer header. The zero value produces argv identical to what ct
sent before these knobs existed.

config: a [diff] section supplying args and exclude, plus a [diff.pager]
subtable naming an external formatter each file's patch is piped through.
Omitting the subtable keeps ct's built-in styling, which stays the default. A
literal {width} in the pager args is replaced with the viewer's current column
count, so a formatter can be sized to the pane.

zoom: the preview splits the width between the commit list and the diff, which
is fine for a unified patch but cramped for a side-by-side pager: two code
columns need room the list is taking. z now hides the list so the diff spans
the whole terminal, and toggles back.

Zoomed, the diff owns the keyboard whether or not it held focus - j/k scroll,
] / [ jump files, n / p step commits - so reading a full-width diff needs no
tab dance. tab has nothing to flip to and is inert; z or d bring the list back.
The header reads [zoom] diff, and the footer names z as "show list".

Because the zoomed layout is a single column, it is allowed below the
two-column minimum width: a resize down after zooming keeps showing the diff
rather than snapping back to the plain list. splitShown and stackDiffFocused
are the two predicates the renderer, key routing and wheel all share, so none
of them can disagree about whether the diff is on screen or who owns a key.

Zoom clears when the preview closes, so the next open starts in the standard
two-column layout and the open-time width guard stays coherent; it survives a
status refresh, since that leaves you reading the same view.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ct-stack-id: f8a397f5
@KCaverly
KCaverly force-pushed the ct/diff_view/f8a397f5 branch from 25916e9 to dad446e Compare July 26, 2026 20:32
@KCaverly
KCaverly changed the base branch from main to ct/diff_view/ecdcdaf3 July 26, 2026 20:33
@KCaverly KCaverly changed the title [UI] Zoom the stack preview to full width with z [Diff] Thread the [diff] config through the viewer and zoom with z Jul 26, 2026
Base automatically changed from ct/diff_view/ecdcdaf3 to main July 28, 2026 04:08
@KCaverly
KCaverly merged commit e873f90 into main Jul 28, 2026
2 checks passed
@KCaverly
KCaverly deleted the ct/diff_view/f8a397f5 branch July 28, 2026 04:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant