feat: add neogit support (#117)

## TODO

1. docs (vimdoc + readme) - this is a non-trivial feature
2. push luarocks version

## Problem

diffs.nvim only activates on `fugitive`, `git`, and `gitcommit`
filetypes.
Neogit uses its own custom filetypes (`NeogitStatus`,
`NeogitCommitView`,
`NeogitDiffView`) and doesn't set `b:git_dir`, so the plugin never
attaches
and repo root resolution fails for filetype detection within diff hunks.

## Solution

Two changes:

1. **`lua/diffs/init.lua`** — Add the three Neogit filetypes to the
default
`filetypes` list. The `FileType` autocmd in `plugin/diffs.lua` already
handles them correctly since the `is_fugitive_buffer` guard only applies
   to the `git` filetype.

2. **`lua/diffs/parser.lua`** — Add a CWD-based fallback in
`get_repo_root()`.
After the existing `b:diffs_repo_root` and `b:git_dir` checks, fall back
to
`vim.fn.getcwd()` via `git.get_repo_root()` (already cached). Without
this,
   the parser can't resolve filetypes for files in Neogit buffers.

Neogit's expanded diffs use standard unified diff format, so the parser
handles
them without modification.

Closes #110.
This commit is contained in:
Barrett Ruth 2026-02-14 17:12:01 -05:00 committed by GitHub
parent 5d3bbc3631
commit 3d640c207b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 314 additions and 56 deletions

View file

@ -33,9 +33,13 @@
---@field priorities diffs.PrioritiesConfig
---@class diffs.FugitiveConfig
---@field enabled boolean
---@field horizontal string|false
---@field vertical string|false
---@class diffs.NeogitConfig
---@field enabled boolean
---@class diffs.ConflictKeymaps
---@field ours string|false
---@field theirs string|false
@ -56,9 +60,11 @@
---@class diffs.Config
---@field debug boolean|string
---@field hide_prefix boolean
---@field filetypes string[]
---@field filetypes? string[] @deprecated use fugitive, neogit, extra_filetypes
---@field extra_filetypes string[]
---@field highlights diffs.Highlights
---@field fugitive diffs.FugitiveConfig
---@field neogit diffs.NeogitConfig
---@field conflict diffs.ConflictConfig
---@class diffs
@ -108,7 +114,7 @@ end
local default_config = {
debug = false,
hide_prefix = false,
filetypes = { 'fugitive', 'git', 'gitcommit' },
extra_filetypes = {},
highlights = {
background = true,
gutter = true,
@ -137,9 +143,13 @@ local default_config = {
},
},
fugitive = {
enabled = false,
horizontal = 'du',
vertical = 'dU',
},
neogit = {
enabled = false,
},
conflict = {
enabled = true,
disable_diagnostics = true,
@ -188,6 +198,31 @@ function M.is_fugitive_buffer(bufnr)
return vim.api.nvim_buf_get_name(bufnr):match('^fugitive://') ~= nil
end
---@param opts table
---@return string[]
function M.compute_filetypes(opts)
if opts.filetypes then
return opts.filetypes
end
local fts = { 'git', 'gitcommit' }
local fug = opts.fugitive
if fug == true or (type(fug) == 'table' and fug.enabled ~= false) then
table.insert(fts, 'fugitive')
end
local neo = opts.neogit
if neo == true or (type(neo) == 'table' and neo.enabled ~= false) then
table.insert(fts, 'NeogitStatus')
table.insert(fts, 'NeogitCommitView')
table.insert(fts, 'NeogitDiffView')
end
if type(opts.extra_filetypes) == 'table' then
for _, ft in ipairs(opts.extra_filetypes) do
table.insert(fts, ft)
end
end
return fts
end
local dbg = log.dbg
---@param bufnr integer
@ -387,6 +422,34 @@ local function compute_highlight_groups()
end
end
local neogit_attached = false
local neogit_hl_groups = {
'NeogitDiffAdd',
'NeogitDiffAddCursor',
'NeogitDiffAddHighlight',
'NeogitDiffDelete',
'NeogitDiffDeleteCursor',
'NeogitDiffDeleteHighlight',
'NeogitDiffContext',
'NeogitDiffContextCursor',
'NeogitDiffContextHighlight',
'NeogitDiffHeader',
'NeogitDiffHeaderHighlight',
'NeogitHunkHeader',
'NeogitHunkHeaderCursor',
'NeogitHunkHeaderHighlight',
'NeogitHunkMergeHeader',
'NeogitHunkMergeHeaderCursor',
'NeogitHunkMergeHeaderHighlight',
}
local function override_neogit_highlights()
for _, name in ipairs(neogit_hl_groups) do
vim.api.nvim_set_hl(0, name, {})
end
end
local function init()
if initialized then
return
@ -395,6 +458,35 @@ local function init()
local opts = vim.g.diffs or {}
if opts.filetypes then
vim.deprecate(
'vim.g.diffs.filetypes',
'fugitive, neogit, and extra_filetypes',
'0.3.0',
'diffs.nvim'
)
end
if opts.fugitive == true then
opts.fugitive = { enabled = true }
elseif opts.fugitive == false then
opts.fugitive = { enabled = false }
elseif opts.fugitive == nil then
opts.fugitive = nil
elseif type(opts.fugitive) == 'table' and opts.fugitive.enabled == nil then
opts.fugitive.enabled = true
end
if opts.neogit == true then
opts.neogit = { enabled = true }
elseif opts.neogit == false then
opts.neogit = { enabled = false }
elseif opts.neogit == nil then
opts.neogit = nil
elseif type(opts.neogit) == 'table' and opts.neogit.enabled == nil then
opts.neogit.enabled = true
end
vim.validate({
debug = {
opts.debug,
@ -404,7 +496,9 @@ local function init()
'boolean or string (file path)',
},
hide_prefix = { opts.hide_prefix, 'boolean', true },
filetypes = { opts.filetypes, 'table', true },
fugitive = { opts.fugitive, 'table', true },
neogit = { opts.neogit, 'table', true },
extra_filetypes = { opts.extra_filetypes, 'table', true },
highlights = { opts.highlights, 'table', true },
})
@ -472,23 +566,30 @@ local function init()
if opts.fugitive then
vim.validate({
['fugitive.enabled'] = { opts.fugitive.enabled, 'boolean', true },
['fugitive.horizontal'] = {
opts.fugitive.horizontal,
function(v)
return v == false or type(v) == 'string'
return v == nil or v == false or type(v) == 'string'
end,
'string or false',
},
['fugitive.vertical'] = {
opts.fugitive.vertical,
function(v)
return v == false or type(v) == 'string'
return v == nil or v == false or type(v) == 'string'
end,
'string or false',
},
})
end
if opts.neogit then
vim.validate({
['neogit.enabled'] = { opts.neogit.enabled, 'boolean', true },
})
end
if opts.conflict then
vim.validate({
['conflict.enabled'] = { opts.conflict.enabled, 'boolean', true },
@ -583,6 +684,9 @@ local function init()
vim.api.nvim_create_autocmd('ColorScheme', {
callback = function()
compute_highlight_groups()
if neogit_attached then
vim.schedule(override_neogit_highlights)
end
for bufnr, _ in pairs(attached_buffers) do
invalidate_cache(bufnr)
end
@ -701,6 +805,11 @@ function M.attach(bufnr)
end
attached_buffers[bufnr] = true
if not neogit_attached and config.neogit.enabled and vim.bo[bufnr].filetype:match('^Neogit') then
neogit_attached = true
vim.schedule(override_neogit_highlights)
end
dbg('attaching to buffer %d', bufnr)
ensure_cache(bufnr)