Skip to content

feat: add configurable diff command with $width and interactive support#453

Closed
pablospe wants to merge 5 commits intoidursun:mainfrom
pablospe:feature/configurable-diff-command
Closed

feat: add configurable diff command with $width and interactive support#453
pablospe wants to merge 5 commits intoidursun:mainfrom
pablospe:feature/configurable-diff-command

Conversation

@pablospe
Copy link
Copy Markdown
Contributor

@pablospe pablospe commented Jan 3, 2026

Summary

  • Add a new [diff] config section with customizable command for the built-in diff view (d key on files)
  • Support show = "interactive" to open diff in a real terminal (like custom commands)
  • Pass screen width via $width placeholder for proper side-by-side diff rendering

Motivation

When using delta with --side-by-side in the built-in diff view, there was no way to:

  1. Pass the correct terminal width (delta would default to half screen)
  2. Open an interactive terminal (required for proper pager behavior)

This complements the $width variable added for preview commands (#452).

Example configuration

[diff]
# Use delta with side-by-side for the built-in diff view (d key on files in details view).
# +g: start at top of file (not bottom for small files)
command = ["util", "exec", "--", "bash", "-c", """jj diff --color always --git -r $change_id $file | delta --side-by-side --width $width --pager 'less -R +g'"""]
show = "interactive"

[custom_commands."deltadiff"]
# Custom command for viewing full revision diff with delta.
# This is needed because [diff] only applies to individual files (d key in file list),
# while this custom command applies to entire revisions (d key on revision list).
key = ["d"]
args = ["util", "exec", "--", "bash", "-c", """jj show --summary --git --color always -r $change_id | delta --pager 'less -R +g'"""]
show = "interactive"

Available placeholders

  • $change_id - revision change ID
  • $commit_id - revision commit ID
  • $file - selected file path
  • $width - screen width in columns

Add a new placeholder variable $width that exposes the actual
view width (in columns) to preview commands. This enables tools
like delta to use --side-by-side with the correct width.

Similar to how fzf exposes $FZF_PREVIEW_COLUMNS, this allows users to
configure preview commands that adapt to the view size:

```toml
[preview]
revision_command = ["util", "exec", "--", "bash", "-c",
  """jj show --color always --git -r $change_id | delta --side-by-side --width $width"""]
```

The width updates dynamically when the preview pane is resized.
@pablospe pablospe requested a review from idursun as a code owner January 3, 2026 22:28
@pablospe
Copy link
Copy Markdown
Contributor Author

pablospe commented Jan 3, 2026

Note: This PR is stacked on top of #452 (adds $width variable for preview commands). Please merge #452 first.

@baggiiiie
Copy link
Copy Markdown
Collaborator

baggiiiie commented Jan 4, 2026

fyi the issue with delta side-by-side has a workaround as discussed in #314 (comment)

linting is failing, please run go fmt

Add a new [diff] config section with a customizable command for the
built-in diff view (d key on files). This allows users to use tools
like delta with proper width support.

The screen width is passed via $width placeholder, enabling side-by-side
diff viewers to use the correct terminal width.

Example configuration:
```toml
[diff]
command = ["util", "exec", "--", "bash", "-c",
  """jj diff --color always --git -r $change_id $file | delta --side-by-side --width $width"""]
```

Available placeholders: $change_id, $commit_id, $file, $width
@pablospe pablospe force-pushed the feature/configurable-diff-command branch from 887391f to 472d522 Compare January 4, 2026 19:31
@pablospe
Copy link
Copy Markdown
Contributor Author

pablospe commented Jan 4, 2026

Thank! Let me explain a bit better what is the problem. When pressing d on a file in jjui, the built-in diff view runs the diff command inside the TUI. With delta's --side-by-side, two issues occur:

  1. Width detection fails - Delta can't detect the terminal width when running inside jjui's TUI, so side-by-side columns render incorrectly
  2. Pager doesn't work - Delta's pager (less) needs an interactive terminal, which isn't available in the embedded view

The workaround in #314 avoids the problem by disabling side-by-side mode entirely (side-by-side = false). That works, but you lose the side-by-side feature.

This PR solves it properly by:

  • Adding $width so delta knows the exact terminal width
  • Adding show = "interactive" to open the diff in a real terminal where the pager works

This lets you use delta with --side-by-side as intended, without compromises.

@idursun
Copy link
Copy Markdown
Owner

idursun commented Jan 5, 2026

Hey thanks,

This side by side diff issue when using delta is coming up regularly and at this point I am just ignoring it. I don't feel comfortable adding a configuration block just to enable integration one of the tools out there.

My take on this is that;

If you want to use a custom pager for diffs, you can unbind the d from the internal diff view and define a custom command that binds to d and invokes the external diff viewer in an interactive session. You already have the command for that. I understand delta doesn't read the width of the terminal and defaults to 50 and it is the root cause here. I would instead have a look at why that's the case, because it should be able to query the terminal dimensions itself. Maybe our interactive session is missing some env variables for it to be able to do that or maybe that feature doesn't exists at all. In either case, I don't think the solution is to customise jjui to patch that gap.

@baggiiiie
Copy link
Copy Markdown
Collaborator

baggiiiie commented Jan 5, 2026

avoids the problem by disabling side-by-side mode entirely (side-by-side = false). That works, but you lose the side-by-side feature.

hey @pablospe , i'm using delta side-by-side with no issue at all, using the config suggested in #314 ,

.gitconfig

[delta "split-view"]
    side-by-side = true

[delta "non-split-view"]
    side-by-side = false

[delta]
    features = split-view
    navigate = true
    line-numbers = true

jj/config.toml:

[ui]
diff-formatter = [
    "bash",
    "-c",
    "delta --width $width $left $right --features=split-view || true",
]
pager = "delta"
image

@pablospe
Copy link
Copy Markdown
Contributor Author

pablospe commented Jan 5, 2026

@baggiiiie Thanks! One question. Is this working for you when you enter to delta from jjui (when opened from the file list l shortcut)?
navigate = true # use n and N to move between diff sections

@baggiiiie
Copy link
Copy Markdown
Collaborator

Is this working for you when you enter to delta from jjui (when opened from the file list l shortcut)?

display works fine when showing diff from file list, tho it's only display, losing pager's other functionalities (regarding pager, related discussion see #366 )

asciicast

@pablospe
Copy link
Copy Markdown
Contributor Author

pablospe commented Jan 5, 2026

losing pager's other functionalities

Yes, exactly, thanks for the video and the confirmation. I thought I was missing something. This is exactly what I noticed and wanted to solve with this PR, which allow me to have the full delta experience with n/N navigation (pager functionalities).

@pablospe
Copy link
Copy Markdown
Contributor Author

pablospe commented Jan 5, 2026

you can unbind the d from the internal diff view and define a custom command that binds to d and invokes the external diff viewer in an interactive session

@idursun
Before we abandon this PR. How would you do that? I mean, unbind and bind again? I tried with this configuration:

  [keys]
  diff = []

  [keys.details]
  diff = []

  [custom_commands.deltadiff]
  key = ["d"]
  args = ["util", "exec", "--", "bash", "-c", "jj diff --git --color always -r $change_id $file | delta --pager 'less -R +g'"]
  show = "interactive"

but it doesn't seem to be working:

  • d is only working in the revision list
  • d is not working In the details view (after pressing l) → how do I re-bind d to shows diff for a specific file with a custom command?

@pablospe
Copy link
Copy Markdown
Contributor Author

pablospe commented Jan 5, 2026

@idursun ignore my previous message. I found a solution for what I wanted to achieve with this PR, I think the inline format made the difference (somehow).

In jjui config file:

# Unbind built-in diff key to allow custom command to handle it
[keys]
diff = []

# Interactive diff with delta (works in both revision list and details view)
# - $change_id: replaced with selected revision
# - $file: replaced with selected file (in details view) or empty (in revision view)
# - show = "interactive": opens real terminal so delta's pager/navigation works
[custom_commands]
"deltadiff" = { key = ["d"], args = ["util", "exec", "--", "bash", "-c", "jj diff --git --color always -r $change_id $file | delta --pager 'less -R +g'"], show = "interactive" }

@baggiiiie Could you give a try to this? It will give you the pager's functionalities. And you don't need to touch .gitconfig and jj/config anymore, only jjui/config.

@baggiiiie
Copy link
Copy Markdown
Collaborator

@pablospe nice thanks, your custom command works!

@pablospe
Copy link
Copy Markdown
Contributor Author

pablospe commented Jan 6, 2026

Ok, we can close this PR. Thanks for the help both and the very useful tool, @idursun and @baggiiiie.

@pablospe pablospe closed this Jan 6, 2026
@pablospe pablospe deleted the feature/configurable-diff-command branch March 15, 2026 01:17
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.

3 participants