Skip to content

Commit b3db066

Browse files
committed
feat: add vscode-diff.nvim as alternative diff viewer
Add support for vscode-diff.nvim alongside diffview.nvim for viewing diffs. Users can explicitly choose via the new `diff_viewer` config option, or let Neogit auto-detect (diffview first, then vscode-diff). Why: - Provides choice for users who prefer vscode-diff's interface - Maintains backwards compatibility (diffview remains default) - Auto-detection means zero config for most users Implementation: - New `diff_viewer` config option: "diffview", "vscode_diff", or nil - New integration module at integrations/vscode-diff.lua with same interface as diffview (M.open with section_name, item_name, opts) - get_diff_viewer() helper handles explicit choice vs auto-detection - Diff popup and status buffer conflict resolution dispatch to the configured viewer - on_close callback for auto-staging after conflict resolution works with both viewers using the same BufEnter autocmd pattern
1 parent d8bf910 commit b3db066

File tree

7 files changed

+394
-31
lines changed

7 files changed

+394
-31
lines changed

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ Here's an example spec for [Lazy](https://github.com/folke/lazy.nvim), but you'r
3333
lazy = true,
3434
dependencies = {
3535
"nvim-lua/plenary.nvim", -- required
36-
"sindrets/diffview.nvim", -- optional - Diff integration
36+
37+
-- Only one of these is needed.
38+
"sindrets/diffview.nvim", -- optional
39+
"ldelossa/vscode-diff.nvim", -- optional
3740

3841
-- Only one of these is needed.
3942
"nvim-telescope/telescope.nvim", -- optional
@@ -319,6 +322,10 @@ neogit.setup {
319322
-- Requires you to have `sindrets/diffview.nvim` installed.
320323
diffview = nil,
321324

325+
-- Alternative diff viewer integration.
326+
-- Requires you to have `ldelossa/vscode-diff.nvim` installed.
327+
vscode_diff = nil,
328+
322329
-- If enabled, uses fzf-lua for menu selection. If the telescope integration
323330
-- is also selected then telescope is used instead
324331
-- Requires you to have `ibhagwan/fzf-lua` installed.
@@ -334,6 +341,9 @@ neogit.setup {
334341
-- Requires you to have `folke/snacks.nvim` installed.
335342
snacks = nil,
336343
},
344+
-- Which diff viewer to use. nil = auto-detect (tries diffview first, then vscode_diff).
345+
-- Can be "diffview" or "vscode_diff".
346+
diff_viewer = nil,
337347
sections = {
338348
-- Reverting/Cherry Picking
339349
sequencer = {

doc/neogit.txt

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,10 @@ to Neovim users.
285285
-- Requires you to have `sindrets/diffview.nvim` installed.
286286
diffview = nil,
287287

288+
-- Alternative diff viewer integration.
289+
-- Requires you to have `ldelossa/vscode-diff.nvim` installed.
290+
vscode_diff = nil,
291+
288292
-- If enabled, uses fzf-lua for menu selection. If the telescope integration
289293
-- is also selected then telescope is used instead
290294
-- Requires you to have `ibhagwan/fzf-lua` installed.
@@ -300,6 +304,9 @@ to Neovim users.
300304
-- Requires you to have `folke/snacks.nvim` installed.
301305
snacks = nil,
302306
},
307+
-- Which diff viewer to use. nil = auto-detect (tries diffview first, then vscode_diff).
308+
-- Can be "diffview" or "vscode_diff".
309+
diff_viewer = nil,
303310
sections = {
304311
-- Reverting/Cherry Picking
305312
sequencer = {
@@ -1401,9 +1408,13 @@ The diff popup actions allow inspection of changes in the index (staged
14011408
changes), the working tree (unstaged changes and untracked files), any
14021409
ref range.
14031410

1404-
For these actions to become available, Neogit needs to be configured to enable
1405-
`diffview.nvim` integration. See |neogit_setup_plugin| and
1406-
https://github.com/sindrets/diffview.nvim.
1411+
For these actions to become available, Neogit needs to have a diff viewer
1412+
integration enabled. Supported viewers are:
1413+
- `diffview.nvim`: https://github.com/sindrets/diffview.nvim
1414+
- `vscode-diff.nvim`: https://github.com/ldelossa/vscode-diff.nvim
1415+
1416+
By default, Neogit will auto-detect which viewer is available. You can
1417+
explicitly set the viewer with the `diff_viewer` option. See |neogit_setup_plugin|.
14071418

14081419
• Diff this *neogit_diff_this*
14091420
Show the diff for the file referred to by a hunk under the cursor.

lua/neogit/buffers/status/actions.lua

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,8 +1145,12 @@ M.n_stage = function(self)
11451145
end
11461146

11471147
if selection.item and selection.item.mode == "UU" then
1148-
if config.check_integration("diffview") and git.merge.is_conflicted(selection.item.escaped_path) then
1149-
require("neogit.integrations.diffview").open("conflict", selection.item.name, {
1148+
local diff_viewer = config.get_diff_viewer()
1149+
if diff_viewer and git.merge.is_conflicted(selection.item.escaped_path) then
1150+
local integration = diff_viewer == "vscode_diff"
1151+
and require("neogit.integrations.vscode-diff")
1152+
or require("neogit.integrations.diffview")
1153+
integration.open("conflict", selection.item.name, {
11501154
on_close = {
11511155
handle = self.buffer.handle,
11521156
fn = function()
@@ -1186,8 +1190,12 @@ M.n_stage = function(self)
11861190
self:dispatch_refresh({ update_diffs = { "untracked:*" } }, "n_stage")
11871191
elseif section.options.section == "unstaged" then
11881192
if git.status.any_unmerged() then
1189-
if config.check_integration("diffview") then
1190-
require("neogit.integrations.diffview").open("conflict", nil, {
1193+
local diff_viewer = config.get_diff_viewer()
1194+
if diff_viewer then
1195+
local integration = diff_viewer == "vscode_diff"
1196+
and require("neogit.integrations.vscode-diff")
1197+
or require("neogit.integrations.diffview")
1198+
integration.open("conflict", nil, {
11911199
on_close = {
11921200
handle = self.buffer.handle,
11931201
fn = function()

lua/neogit/config.lua

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,8 @@ end
387387
---@field preview_buffer? NeogitConfigPopup Preview options
388388
---@field popup? NeogitConfigPopup Set the default way of opening popups
389389
---@field signs? NeogitConfigSigns Signs used for toggled regions
390-
---@field integrations? { diffview: boolean, telescope: boolean, fzf_lua: boolean, mini_pick: boolean, snacks: boolean } Which integrations to enable
390+
---@field integrations? { diffview: boolean, vscode_diff: boolean, telescope: boolean, fzf_lua: boolean, mini_pick: boolean, snacks: boolean } Which integrations to enable
391+
---@field diff_viewer? "diffview"|"vscode_diff"|nil Which diff viewer to use (nil = auto-detect)
391392
---@field sections? NeogitConfigSections
392393
---@field ignored_settings? string[] Settings to never persist, format: "Filetype--cli-value", i.e. "NeogitCommitPopup--author"
393394
---@field mappings? NeogitConfigMappings
@@ -540,10 +541,12 @@ function M.get_default_values()
540541
integrations = {
541542
telescope = nil,
542543
diffview = nil,
544+
vscode_diff = nil,
543545
fzf_lua = nil,
544546
mini_pick = nil,
545547
snacks = nil,
546548
},
549+
diff_viewer = nil,
547550
sections = {
548551
sequencer = {
549552
folded = false,
@@ -856,8 +859,26 @@ function M.validate_config()
856859
end
857860
end
858861

862+
local function validate_diff_viewer()
863+
if config.diff_viewer == nil then
864+
return
865+
end
866+
867+
local valid_viewers = { "diffview", "vscode_diff" }
868+
if not vim.tbl_contains(valid_viewers, config.diff_viewer) then
869+
err(
870+
"diff_viewer",
871+
string.format(
872+
"Expected diff_viewer to be one of %s or nil, got '%s'",
873+
table.concat(valid_viewers, ", "),
874+
tostring(config.diff_viewer)
875+
)
876+
)
877+
end
878+
end
879+
859880
local function validate_integrations()
860-
local valid_integrations = { "diffview", "telescope", "fzf_lua", "mini_pick", "snacks" }
881+
local valid_integrations = { "diffview", "vscode_diff", "telescope", "fzf_lua", "mini_pick", "snacks" }
861882
if not validate_type(config.integrations, "integrations", "table") or #config.integrations == 0 then
862883
return
863884
end
@@ -1277,6 +1298,7 @@ function M.validate_config()
12771298
end
12781299

12791300
validate_integrations()
1301+
validate_diff_viewer()
12801302
validate_sections()
12811303
validate_ignored_settings()
12821304
validate_mappings()
@@ -1308,6 +1330,32 @@ function M.check_integration(name)
13081330
return enabled
13091331
end
13101332

1333+
---Returns the configured diff viewer, or auto-detects if not set
1334+
---@return string|nil The diff viewer to use ("diffview", "vscode_diff"), or nil if none available
1335+
function M.get_diff_viewer()
1336+
local logger = require("neogit.logger")
1337+
local viewer = M.values.diff_viewer
1338+
1339+
if viewer then
1340+
-- Explicit choice - verify it's available
1341+
if M.check_integration(viewer) then
1342+
return viewer
1343+
else
1344+
logger.warn(("[CONFIG] Configured diff_viewer '%s' is not available"):format(viewer))
1345+
return nil
1346+
end
1347+
end
1348+
1349+
-- Auto-detect: try diffview first (backwards compatible), then vscode_diff
1350+
if M.check_integration("diffview") then
1351+
return "diffview"
1352+
elseif M.check_integration("vscode_diff") then
1353+
return "vscode_diff"
1354+
end
1355+
1356+
return nil
1357+
end
1358+
13111359
function M.setup(opts)
13121360
if opts == nil then
13131361
return

0 commit comments

Comments
 (0)