Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 53 additions & 100 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,125 +1,78 @@
# diffs.nvim

**Treesitter-powered Diff Syntax highlighting for Neovim**
Language syntax highlighting for unified diffs in Neovim.

Enhance Neovim's built-in diff mode (and much more!) with language-aware syntax
highlighting driven by treesitter.
Diffs uses Treesitter or Vim syntax to highlight the code inside diff hunks.
It adds line backgrounds and intra-line highlights, and adjusts colors in native
diff windows.

<img width="1719" height="1040" alt="image" src="https://github.com/user-attachments/assets/c26cd9d4-b8f7-4386-aa47-6e7cf2fef9cb" />

## Features

- Treesitter syntax highlighting in
[vim-fugitive](https://github.com/tpope/vim-fugitive),
[Neogit](https://github.com/NeogitOrg/neogit), builtin `diff` filetype, and
more!
- Word- and character-level diff highlighting, driven by `'diffopt'` `inline:`
- `:Diff` for [pierre-style](https://diffs.com) unified, stacked, or split diffs against any revision
- `:Diff review` full-repo review diff with qflist/loclist navigation
- `:Diff files` to diff two arbitrary files, or the buffer against its last save
- Inline and 3-way merge conflict detection, highlighting, and resolution
- Email quoting/patch syntax support (`> diff ...`)
- Vim syntax fallback
- [Difftastic](https://difftastic.wilfred.me.uk/) highlight support
- Configurable highlighting

## Requirements

- Neovim 0.12.0+
- Optional: the Treesitter `diff` parser for the best experience
- Optional: Treesitter parsers for the languages in your diffs and the `diff` parser

## Installation

With `vim.pack` (Neovim 0.12+):
```lua
vim.pack.add({ 'https://github.com/barrettruth/diffs.nvim' })
```

Diffs attaches to `git` and `gitcommit` buffers by default. Enable integrations
before the plugin loads:

```lua
vim.g.diffs = {
integrations = { 'fugitive', 'neogit', 'neojj', 'gitsigns', 'committia', 'telescope' },
}
```

To highlight patch files with the `diff` filetype:

```lua
vim.pack.add({
'https://github.com/barrettruth/diffs.nvim',
vim.api.nvim_create_autocmd('FileType', {
pattern = 'diff',
callback = function(event)
require('diffs').attach(event.buf)
end,
})
```

## Documentation
Use `'diffopt'` to select intra-line highlighting:

```vim
:help diffs.nvim
set diffopt+=inline:word
```

## FAQ
See `:help diffs.nvim` for configuration and the Lua API. Run `:checkhealth diffs`
for dependency information.

**Q: Does diffs.nvim support
[vim-fugitive](https://github.com/tpope/vim-fugitive)/[Neogit](https://github.com/NeogitOrg/neogit)/[neojj](https://github.com/NicholasZolton/neojj)/[gitsigns](https://github.com/lewis6991/gitsigns.nvim)/[fzf-lua](https://github.com/ibhagwan/fzf-lua)?**
## Diff commands and conflicts

Yes. Enable integrations in your config:
[diffs-collection.nvim](https://github.com/barrettruth/diffs-collection.nvim)
contains file comparison, repository review, split views, quickfix navigation,
and conflict resolution. Install it alongside diffs.nvim for these workflows.

```lua
vim.g.diffs = {
integrations = { 'fugitive', 'neogit', 'neojj', 'gitsigns' },
}
```
## Limitations

Treesitter parses each hunk separately. Hunks that start or end inside an
expression can have incomplete syntax highlighting.

Vim syntax fallback runs after redraw. A new hunk can appear without syntax
colors for one frame. Language parsers and queries also load on first use.

Other plugins that change diff highlights can produce conflicting colors.

## Acknowledgements

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

See the documentation for more information.

**Q: Can I use diffs.nvim as a Git mergetool?**

Yes. Configure Git to open `$MERGED` with Neovim; diffs.nvim will detect
conflict markers automatically. See `:help diffs.nvim-git-mergetool`.

**Q: Can I exclude untracked files from `:Diff review`?**

Yes. Run `:Diff review ++nountracked`. To make it the default, wrap it in your
own command, e.g. `:command! Review Diff review ++nountracked`.

## Known Limitations

- **Incomplete syntax context**: Treesitter parses each diff hunk in isolation.
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. The plugin reparses hunks after buffer edits and redraws visible
highlights.

- **Conflicting diff plugins**: `diffs.nvim` may not interact well with other
plugins that modify diff highlighting. Known plugins that may conflict:
- [`diffview.nvim`](https://github.com/sindrets/diffview.nvim) - provides its
own diff highlighting and conflict resolution UI
- [`mini.diff`](https://github.com/echasnovski/mini.diff) - visualizes buffer
differences with its own highlighting system
- [`gitsigns.nvim`](https://github.com/lewis6991/gitsigns.nvim) - generally
compatible, but both plugins modifying line highlights may produce
unexpected results
- [`git-conflict.nvim`](https://github.com/akinsho/git-conflict.nvim) -
`diffs.nvim` now includes built-in conflict resolution; disable one or the
other to avoid overlap

# Acknowledgements

- [`vim-fugitive`](https://github.com/tpope/vim-fugitive)
- [`diffview.nvim`](https://github.com/sindrets/diffview.nvim)
- [`difftastic`](https://github.com/Wilfred/difftastic)
- [`mini.diff`](https://github.com/echasnovski/mini.diff)
- [`gitsigns.nvim`](https://github.com/lewis6991/gitsigns.nvim)
- [`git-conflict.nvim`](https://github.com/akinsho/git-conflict.nvim)
- [@phanen](https://github.com/phanen) - diff header highlighting, unknown
filetype fix, shebang/modeline detection, treesitter injection support,
decoration provider highlighting architecture, gitsigns blame popup
highlighting, intra-line bg visibility fix
- [@tris203](https://github.com/tris203) - support for transparent backgrounds
- [@letientai299](https://github.com/letientai299) - `diff.mnemonicPrefix`
support
- [vim-fugitive](https://github.com/tpope/vim-fugitive)
- [diffview.nvim](https://github.com/sindrets/diffview.nvim)
- [difftastic](https://github.com/Wilfred/difftastic)
- [mini.diff](https://github.com/echasnovski/mini.diff)
- [gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim)
- [git-conflict.nvim](https://github.com/akinsho/git-conflict.nvim)
- [@phanen](https://github.com/phanen) — header highlighting, filetype detection,
Treesitter injections, decoration providers, Gitsigns popups, and intra-line colors
- [@tris203](https://github.com/tris203) — transparent backgrounds
- [@letientai299](https://github.com/letientai299) — `diff.mnemonicPrefix` support
Loading
Loading