treesitter syntax highlighting for diffs
  • Lua 99.5%
  • Nix 0.4%
Find a file
Barrett Ruth 6310b4f728
All checks were successful
quality / Format (push) Successful in 13s
quality / Lint (push) Successful in 10s
quality / Test (push) Successful in 8s
fix(ci): put LuaRocks publishing under deploy workflow (#228)
Problem
The LuaRocks publish workflow currently uses the workflow prefix `luarocks`, so tag-publish status contexts render as `luarocks / Publish to LuaRocks`. Publish/deploy jobs should live under the deploy namespace, matching the newer deploy/nightly naming strategy.

Solution
Rename the LuaRocks workflow and job display names so future tag-publish contexts render as:

- deploy / LuaRocks

The tag trigger, job id, runner, secret usage, and publish command are unchanged.

Verification
- Parsed `.forgejo/workflows/luarocks.yaml` with PyYAML.
- Ran `git diff --check`.

Reviewed-on: #228
2026-05-03 16:49:26 +00:00
.forgejo fix(ci): put LuaRocks publishing under deploy workflow (#228) 2026-05-03 16:49:26 +00:00
doc fix: make conflict keymaps opt-in (#224) 2026-04-30 14:49:49 -04:00
lua/diffs fix: make conflict keymaps opt-in (#224) 2026-04-30 14:49:49 -04:00
plugin fix: always attach for configured filetypes (#217) 2026-04-22 14:02:01 -04:00
spec fix: make conflict keymaps opt-in (#224) 2026-04-30 14:49:49 -04:00
.busted feat(test): testing infrastructure 2026-02-01 23:09:05 -05:00
.editorconfig feat: initial setup files 2026-02-01 16:30:24 -05:00
.gitignore ci: migrate to nix 2026-02-23 18:14:05 -05:00
.luarc.json feat(commands): model Greview as review specs (#214) 2026-04-19 20:21:39 -04:00
.styluaignore refactor(highlight): unified per-line extmark builder (#144) 2026-03-05 09:01:22 -05:00
biome.json chore: replace prettier with biome (#219) 2026-04-25 16:16:01 -04:00
diffs.nvim-scm-1.rockspec feat: rename everything 2026-02-02 22:09:13 -05:00
flake.lock build(nix): use nixpkgs vimdoc-language-server (#216) 2026-04-20 17:34:56 -04:00
flake.nix chore: replace prettier with biome (#219) 2026-04-25 16:16:01 -04:00
justfile chore: replace prettier with biome (#219) 2026-04-25 16:16:01 -04:00
LICENSE chore: switch license to GPL 2026-04-30 23:20:10 +00:00
minimal_init.lua fix: preserve host treesitter assets in repros (#225) 2026-04-30 16:02:32 -04:00
README.md docs: normalize README media embeds (#226) 2026-05-02 02:04:00 +00:00
selene.toml ci: migrate to nix 2026-02-23 18:14:05 -05:00
stylua.toml feat: initial setup files 2026-02-01 16:30:24 -05:00
vim.yaml ci: add bit luajit global 2026-02-23 18:18:30 -05:00

diffs.nvim

Treesitter-powered Diff Syntax highlighting for Neovim

Enhance Neovim's built-in diff mode (and much more!) with language-aware syntax highlighting driven by treesitter.

Features

  • Treesitter syntax highlighting in vim-fugitive, Neogit, builtin diff filetype, and more!
  • Character-level intra-line diff highlighting (with optional vscode-diff FFI backend for word-level accuracy)
  • :Gdiff unified diff against any revision
  • :Greview full-repo review diff with qflist/loclist navigation
  • Inline merge conflict detection, highlighting, and resolution
  • gitsigns.nvim blame popup highlighting
  • Email quoting/patch syntax support (> diff ...)
  • Vim syntax fallback
  • Configurable highlighiting blend & priorities
  • Context-inclusive, high-accuracy highlights

Requirements

  • Neovim 0.9.0+

Installation

Install with your package manager of choice or via luarocks:

luarocks install diffs.nvim

Documentation

:help diffs.nvim

FAQ

Q: How do I install with lazy.nvim?

{
  'barrettruth/diffs.nvim',
  init = function()
    vim.g.diffs = {
      ...
    }
  end,
}

Do not lazy load diffs.nvim with event, lazy, ft, config, or keys to control loading - diffs.nvim lazy-loads itself.

Q: Does diffs.nvim support vim-fugitive/Neogit/neojj/gitsigns/fzf-lua?

Yes. Enable integrations in your config:

vim.g.diffs = {
  integrations = {
    fugitive = true,
    neogit = true,
    neojj = true,
    gitsigns = true,
  }
}

fzf-lua is supported out-of-the-box.

See the documentation for more information.

Known Limitations

  • Incomplete syntax context: Treesitter parses each diff hunk in isolation. Context lines within the hunk provide syntactic context for the parser. In rare cases, hunks that start or end mid-expression may produce imperfect highlights due to treesitter error recovery.

  • Syntax "flashing": diffs.nvim hooks into the FileType fugitive event triggered by vim-fugitive, at which point the buffer is preliminarily painted. The decoration provider applies highlights on the next redraw cycle, so a brief first-paint flash may still occur.

  • Cold Start: Treesitter grammar loading (~10ms) and query compilation (~4ms) are one-time costs per language per Neovim session. Each language pays this cost on first encounter, which may cause a brief stutter when a diff containing a new language first enters the viewport.

  • Vim syntax fallback is deferred: The vim syntax fallback (for languages without a treesitter parser) cannot run inside the decoration provider's redraw cycle due to Neovim's restriction on buffer mutations. Vim syntax highlights for cold hunks may appear one frame later. Warm hunks can reuse cached vim syntax spans, and stale deferred renders are ignored after buffer changes.

  • Conflicting diff plugins: diffs.nvim may not interact well with other plugins that modify diff highlighting. Known plugins that may conflict:

    • diffview.nvim - provides its own diff highlighting and conflict resolution UI
    • mini.diff - visualizes buffer differences with its own highlighting system
    • gitsigns.nvim - generally compatible, but both plugins modifying line highlights may produce unexpected results
    • git-conflict.nvim - diffs.nvim now includes built-in conflict resolution; disable one or the other to avoid overlap

Acknowledgements