## Problem `highlight_hunk` applied DiffsClear extmarks across 5 scattered sites with ad-hoc column arithmetic. This fragmentation produced the 1-column DiffsClear gap on email-quoted body context lines (#142 issue 1). A redundant `highlight_hunk_vim_syntax` function duplicated the inline vim syntax path, and the deferred pass in init.lua double-called it, creating duplicate scratch buffers and extmarks. ## Solution Reorganize `highlight_hunk` into two clean phases: - **Phase 1** — multi-line syntax computation (treesitter, vim syntax, diff grammar, header context text). Sets syntax extmarks only, no DiffsClear. - **Phase 2** — per-line chrome (DiffsClear, backgrounds, gutter, overlays, intra-line). All non-syntax extmarks consolidated in one pass. Hoist `new_code` to function scope (needed by `highlight_text` outside the `use_ts` block). Hoist `at_raw_line` so Phase 1d and Phase 2b share one `nvim_buf_get_lines` call. Delete `highlight_hunk_vim_syntax` (redundant with inline path). Remove the double-call from the deferred pass in init.lua. Extend body prefix DiffsClear `end_col` from `qw` to `pw + qw`, fixing the 1-column gap where native treesitter background bled through on context lines in email-quoted diffs (#142 issue 1). ### Email-quoted diff support The parser now strips `> ` (and `>> `, etc.) email quote prefixes before pattern matching, enabling syntax highlighting for diffs embedded in email replies and `git-send-email` / sourcehut-style patch review threads. Each hunk stores `quote_width` so the highlight pipeline can apply `DiffsClear` at the correct column offsets to suppress native treesitter on quoted regions. Closes #141 ### #142 status after this PR | Sub-issue | Status | |-----------|--------| | 1. Col gap on context lines | Fixed | | 2. Bare `>` context lines | Improved, edge case remains | | 3. Diff prefix marker fg | Not addressed (follow-up) |
122 lines
4.2 KiB
Markdown
122 lines
4.2 KiB
Markdown
# diffs.nvim
|
|
|
|
**Syntax highlighting for diffs in Neovim**
|
|
|
|
Enhance [vim-fugitive](https://github.com/tpope/vim-fugitive),
|
|
[Neogit](https://github.com/NeogitOrg/neogit), and Neovim's built-in diff mode
|
|
with language-aware syntax highlighting.
|
|
|
|
<video src="https://github.com/user-attachments/assets/24574916-ecb2-478e-a0ea-e4cdc971e310" width="100%" controls></video>
|
|
|
|
## Features
|
|
|
|
- Treesitter syntax highlighting in vim-fugitive, Neogit, and `diff` filetype
|
|
- Character-level intra-line diff highlighting (with optional
|
|
[vscode-diff](https://github.com/esmuellert/codediff.nvim) FFI backend for
|
|
word-level accuracy)
|
|
- `:Gdiff` unified diff against any revision
|
|
- Background-only diff colors for `&diff` buffers
|
|
- Inline merge conflict detection, highlighting, and resolution
|
|
- Email-quoted diff highlighting (`> diff ...` prefixes, arbitrary nesting
|
|
depth)
|
|
- Vim syntax fallback, configurable blend/priorities
|
|
|
|
## Requirements
|
|
|
|
- Neovim 0.9.0+
|
|
|
|
## Installation
|
|
|
|
Install with your package manager of choice or via
|
|
[luarocks](https://luarocks.org/modules/barrettruth/diffs.nvim):
|
|
|
|
```
|
|
luarocks install diffs.nvim
|
|
```
|
|
|
|
## Documentation
|
|
|
|
```vim
|
|
:help diffs.nvim
|
|
```
|
|
|
|
## FAQ
|
|
|
|
**Q: How do I install with lazy.nvim?**
|
|
|
|
```lua
|
|
{
|
|
'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?**
|
|
|
|
Yes. Enable it in your config:
|
|
|
|
```lua
|
|
vim.g.diffs = {
|
|
fugitive = true,
|
|
neogit = true,
|
|
}
|
|
```
|
|
|
|
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,
|
|
causing a brief visual "flash".
|
|
|
|
- **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 these hunks appear slightly delayed.
|
|
|
|
- **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)
|
|
- [@esmuellert](https://github.com/esmuellert) /
|
|
[`codediff.nvim`](https://github.com/esmuellert/codediff.nvim) - vscode-diff
|
|
algorithm FFI backend for word-level intra-line accuracy
|
|
- [`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
|