Feat: Rewrite diff module to allow for external dependencies as jj.nvim's diff tool (#74)

- Refactor diff into modular architecture (native, diffview, codediff)
- Add the possibility for users to define their own diff backend
- Support external diff tools like diffview.nvim codediff.nvim
- Enable visual mode selection to diff two changes in log buffer
- Add summary tooltip integration with terminal
- Update documentation with new diff workflows
This commit is contained in:
Nicolas GB
2026-01-25 09:39:31 -08:00
committed by GitHub
parent 8ed2aa52aa
commit 335663c3ee
14 changed files with 590 additions and 162 deletions
+23 -41
View File
@@ -6,6 +6,7 @@ local runner = require("jj.core.runner")
local parser = require("jj.core.parser")
local terminal = require("jj.ui.terminal")
local buffer = require("jj.core.buffer")
local diff = require("jj.diff")
local log_selected_hl_group = "JJLogSelectedHlGroup"
local log_selected_ns_id = vim.api.nvim_create_namespace(log_selected_hl_group)
@@ -332,13 +333,23 @@ end
--- Handle diffing a log line
function M.handle_log_diff()
local revset = get_revset()
if revset then
local cmd = string.format("jj show --no-pager %s", revset)
terminal.run_floating(cmd, require("jj.cmd").floating_keymaps())
else
local revsets = extract_revsets_from_terminal_buffer()
if not revsets then
utils.notify("No valid revision found in the log line", vim.log.levels.ERROR)
return
end
-- Delete the pipes from the revsets string since jj new expects space separated revsets
revsets = revsets:gsub("| ", "")
local is_multiple = revsets:find(" ") ~= nil
if not is_multiple then
diff.show_revision({ rev = revsets })
else
-- Get the first and the last revset to diff
local list = vim.split(revsets, "%s+", { trimempty = true })
diff.diff_revisions({ left = list[1], right = list[#list] })
end
end
@@ -731,40 +742,11 @@ function M.handle_summary_diff(revset)
terminal.keep_tooltip_open(true)
end
-- Add custom close behavior that returns to tooltip
local function close_and_return()
-- Close the floating diff
terminal.close_floating_buffer()
-- Return focus to tooltip if still valid
if terminal.state.tooltip_win and vim.api.nvim_win_is_valid(terminal.state.tooltip_win) then
vim.api.nvim_set_current_win(terminal.state.tooltip_win)
end
-- Clear suppress flag
if terminal.state.tooltip_buf and vim.api.nvim_buf_is_valid(terminal.state.tooltip_buf) then
terminal.keep_tooltip_open(false)
end
end
local cmd = require("jj.cmd")
local cfg = cmd.config.keymaps.floating or {}
-- In this specific case we override the behaviour of the default terminal close and return to the old buffer
local specs = {
close = {
modes = { "n", "v" },
handler = close_and_return,
desc = "Close diff and return to tooltip",
},
hide = {
modes = { "n", "v" },
handler = close_and_return,
desc = "Close diff and return to tooltip",
},
}
terminal.run_floating(
string.format("jj diff -r %s %s", revset, filepath.new_path),
cmd.resolve_keymaps_from_specs(cfg, specs)
)
-- Use the diff module to show what changed in this revision for this file
diff.show_revision({
rev = revset,
path = filepath.new_path,
})
end
--- Handle edit action in summary tooltip (opens file after jj edit)
@@ -936,7 +918,7 @@ function M.log_keymaps()
diff = {
desc = "Diff revision under cursor",
handler = M.handle_log_diff,
modes = { "n" },
modes = { "n", "v" },
},
new = {
desc = "Create new change branching off revision under cursor",