Skip to content

feat: add ui.useDeltaTheme to render diffs with the user's own delta config - #160

Open
pablospe wants to merge 10 commits into
dlvhdr:mainfrom
pablospe:theme-none
Open

pablospe wants to merge 10 commits into
dlvhdr:mainfrom
pablospe:theme-none

Conversation

@pablospe

@pablospe pablospe commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Since the theme picker (#152), diffnav passes delta a full set of style flags derived from the active theme (--syntax-theme, --plus-style, --minus-style, line-number and hunk-header styles, etc.). Command-line flags take precedence over [delta] in gitconfig, so users who had delta configured to their liking lost that styling, and there is no way to opt out. Fixes #158.

This adds an opt-in option, ui.useUserDeltaTheme: true (or DIFFNAV_USE_USER_DELTA_THEME=1, which overrides the config). With it, the diff is rendered with the user's own delta config, and the rest of the UI keeps ui.theme. diffnav then only passes delta --paging=never, -w=N and --wrap-max-lines=unlimited. Unlimited wrapping is kept because the diff pane is narrower than the terminal and can't scroll sideways, so delta's default (wrap twice, then cut) would lose text on long side-by-side lines. Without the option, delta gets exactly the same args and env as today.

Side-by-side needs special handling in this mode. The --side-by-side CLI flag enables delta's built-in side-by-side feature, which takes precedence over the user's own features and replaces their line-number formats and styles with delta's defaults. It also can't turn side-by-side off when the user's config enables it. So with the option on, diffnav sets delta.side-by-side=true/false through GIT_CONFIG_PARAMETERS (appending to any existing value) instead. Delta treats it like gitconfig, so the user's styling is kept and s toggles both ways.

One change applies to everyone: delta runs asynchronously, and a slow result could overwrite the current view. Examples: a file you already moved away from, a cancelled theme preview, or an older run of the same file after a resize or watch reload. Each result now carries the cache node it was started for and is dropped unless that node is still current. Delta args/env are also built before the command runs, not inside it.

How Did You Test this Change?

  • Unit tests: delta args and env in both modes, config/env handling, and dropping a stale delta result.
  • go test -race ./... and golangci-lint pass.
  • Ran it with ui.theme: catppuccin_frappe + ui.useUserDeltaTheme: true against my own delta config: the diff uses my line-number format, colors and hunk headers in both unified and side-by-side, s toggles between them, and the tree/borders keep the Catppuccin theme. With the option off, rendering is unchanged.

Images/Videos

Before:
diffnav-before

After:
diffnav-after

AI disclosure

Claude Code was used to write the code and tests. I reviewed the changes and tested them manually.

With theme none, side-by-side was enabled with delta's --side-by-side flag. Delta gathers features from command-line flags before the [delta] features list and gives earlier ones higher priority, so the builtin side-by-side feature (and the line-numbers feature it pulls in) overrode the line-number formats and styles from the user's own features. The flag also could not turn side-by-side off when the user's config enables it.

Set delta.side-by-side through GIT_CONFIG_PARAMETERS instead, as `git -c delta.side-by-side=...` does. Delta reads it as a main [delta] section value, so the builtin feature ranks below the user's features, and false turns side-by-side off. Existing GIT_CONFIG_PARAMETERS entries are kept.

Also drop --max-line-length=0 and --wrap-max-lines=unlimited on this path so the user's own truncation and wrapping settings apply. Themed rendering is unchanged.
@dlvhdr

dlvhdr commented Oct 24, 2026

Copy link
Copy Markdown
Owner

Hmm, how about we only disable delta theming but keep the rest of the ui themed?

@pablospe

Copy link
Copy Markdown
Contributor Author

Yes, that's actually what I'm after: I have my delta config heavily tuned (syntax theme, line-number formats, plus/minus colors), and the theme flags override all of it. I'll rework this into a separate opt-in option, ui.useDeltaTheme: true (or DIFFNAV_USE_DELTA_THEME=1), so the UI keeps whatever ui.theme is set and only delta's styling flags are dropped. Users who don't set it get the same delta args as today.

One thing that applies to everyone: a small fix so that late delta results for a file you've already moved away from (or from a cancelled theme preview) don't overwrite the current view.

@pablospe pablospe changed the title feat: add theme "none" to keep the user's own delta config feat: add ui.useDeltaTheme to render diffs with the user's own delta config Oct 25, 2026
@pablospe

pablospe commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor Author

@dlvhdr updated as suggested: theme: none is gone, and there's a new opt-in ui.useDeltaTheme: true (or DIFFNAV_USE_DELTA_THEME=1). With it, the diff uses the user's own delta config and the rest of the UI keeps ui.theme. Without it, delta gets the same args as before. I updated the description and added before/after GIFs.

In the "after" GIF, the diff uses my delta config: line numbers like 70┊, the @ hunk label, my OneHalfDark syntax colors and my plus/minus backgrounds.

@dlvhdr

dlvhdr commented Oct 27, 2026

Copy link
Copy Markdown
Owner

@pablospe I think ui.useDeltaTheme is a bit confusing. Which theme it should use?
I think a better name is ui.useUserDeltaTheme. WDYT?

Comment on lines +216 to +223
node, ok := m.cache[msg.cacheKey]
if !ok || node != msg.node {
// Stale result: a theme change, resize or reload has replaced this node since.
break
}
node.diff = msg.lines
if node == m.file || node == m.dir {
m.fvp.SetObjects(msg.lines)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this related to the PR?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not strictly. It fixes a race that exists on main: delta runs async, so a slow result (e.g. after a resize, a theme preview, or switching files quickly) can overwrite the current view. I hit it while testing this PR. I'll move it to a separate PR, if you prefer. Let me know.

return env
}
param := fmt.Sprintf("'delta.side-by-side'='%t'", sideBySide)
if prev := os.Getenv("GIT_CONFIG_PARAMETERS"); prev != "" {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is GIT_CONFIG_PARAMETERS, I couldn't find info about it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's how git passes git -c key=value to the pager. It isn't really documented, but delta reads it (src/env.rs) and treats it as if it were in the gitconfig. So setting GIT_CONFIG_PARAMETERS="'delta.side-by-side'='true'" is the same as having side-by-side = true in your [delta] config.

Why not just --side-by-side? Two problems with the flag:

  • it also turns on delta's built-in side-by-side feature, which replaces the user's line-number format with delta's default
  • there's no flag to turn side-by-side off, so if your config has it on, s can't switch back to unified

With the env var, s works both ways and the user's styling stays as it is. It's only used with ui.useUserDeltaTheme; the themed path still uses --side-by-side. I'll shorten the code comment too.

@dlvhdr

dlvhdr commented Oct 27, 2026 •

Copy link
Copy Markdown
Owner

Also, the PR has many tests, are they all necessary or we're just being verbose here?
Asking because these would need to be maintained.
Please also clean up verbose comments or make them shorter and to the point.

@pablospe

pablospe commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor Author

@pablospe I think ui.useDeltaTheme is a bit confusing. Which theme it should use? I think a better name is ui.useUserDeltaTheme. WDYT?

Agreed, useDeltaTheme is ambiguous. I'll rename it to ui.useUserDeltaTheme (and the env var to DIFFNAV_USE_USER_DELTA_THEME).

@pablospe

Copy link
Copy Markdown
Contributor Author

ok, I'll trim the tests to the ones that guard real behavior: the delta args in each mode, the side-by-side env override, and one config/env test, and drop the rest (also shorten the comments).

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.

[feature request] external themes support

2 participants