*diffs.nvim.txt* Syntax highlighting for diffs in Neovim Author: Barrett Ruth License: MIT ============================================================================== INTRODUCTION *diffs.nvim* diffs.nvim adds syntax highlighting to diff views. It overlays language-aware highlights on top of default diff highlighting in vim-fugitive and Neovim's built-in diff mode. Features: ~ - Syntax highlighting in |:Git| summary diffs and commit detail views - Syntax highlighting in |:Gdiffsplit| / |:Gvdiffsplit| side-by-side diffs - Background-only diff colors for any `&diff` buffer (vimdiff, diffthis, etc.) - Vim syntax fallback for languages without a treesitter parser - Blended diff background colors that preserve syntax visibility - Optional diff prefix (`+`/`-`/` `) concealment - Gutter (line number) highlighting ============================================================================== REQUIREMENTS *diffs-requirements* - Neovim 0.9.0+ - vim-fugitive (https://github.com/tpope/vim-fugitive) (optional, for unified diff syntax highlighting in |:Git| and commit views) - Treesitter parsers for languages you want highlighted Note: The diff mode feature (background-only colors for |:diffthis|, vimdiff, etc.) works without vim-fugitive. ============================================================================== SETUP *diffs-setup* Using lazy.nvim: >lua { 'barrettruth/diffs.nvim', dependencies = { 'tpope/vim-fugitive' }, opts = {}, } < The plugin works automatically with no configuration required. For customization, see |diffs-config|. ============================================================================== CONFIGURATION *diffs-config* *diffs.Config* Fields: ~ {enabled} (boolean, default: true) Enable or disable highlighting globally. {debug} (boolean, default: false) Enable debug logging to |:messages| with `[diffs]` prefix. {debounce_ms} (integer, default: 0) Debounce delay in milliseconds for re-highlighting after buffer changes. Lower values feel snappier but use more CPU. {hide_prefix} (boolean, default: false) Hide diff prefixes (`+`/`-`/` `) using virtual text overlay. Makes code appear without the leading diff character. When `highlights.background` is also enabled, the overlay inherits the line's background color. {treesitter} (table, default: see below) Treesitter highlighting options. See |diffs.TreesitterConfig| for fields. {vim} (table, default: see below) Vim syntax highlighting options (experimental). See |diffs.VimConfig| for fields. {highlights} (table, default: see below) Controls which highlight features are enabled. See |diffs.Highlights| for fields. *diffs.TreesitterConfig* Treesitter config fields: ~ {enabled} (boolean, default: true) Apply treesitter syntax highlighting to code. {max_lines} (integer, default: 500) Skip treesitter highlighting for hunks larger than this many lines. Prevents lag on massive diffs. *diffs.VimConfig* Vim config fields: ~ {enabled} (boolean, default: false) Use vim syntax highlighting as fallback when no treesitter parser is available for a language. Creates a scratch buffer, sets the filetype, and queries |synID()| per character to extract highlight groups. Slower than treesitter but covers languages without a TS parser installed. {max_lines} (integer, default: 200) Skip vim syntax highlighting for hunks larger than this many lines. Lower than the treesitter default due to the per-character cost of |synID()|. *diffs.Highlights* Highlights table fields: ~ {background} (boolean, default: true) Apply background highlighting to `+`/`-` lines using `DiffsAdd`/`DiffsDelete` groups (derived from `DiffAdd`/`DiffDelete` backgrounds). {gutter} (boolean, default: true) Highlight line numbers with matching colors. Only visible if line numbers are enabled. Note: Header context (e.g., `@@ -10,3 +10,4 @@ func()`) is always highlighted with treesitter when a parser is available. Language detection uses Neovim's built-in |vim.filetype.match()| and |vim.treesitter.language.get_lang()|. To customize filetype detection or register treesitter parsers for custom filetypes, use |vim.filetype.add()| and |vim.treesitter.language.register()|. ============================================================================== API *diffs-api* setup({opts}) *diffs.setup()* Configure the plugin with `opts`. Parameters: ~ {opts} (|diffs.Config|, optional) Configuration table. attach({bufnr}) *diffs.attach()* Manually attach highlighting to a buffer. Called automatically for fugitive buffers via the `FileType fugitive` autocmd. Parameters: ~ {bufnr} (integer, optional) Buffer number. Defaults to current buffer. refresh({bufnr}) *diffs.refresh()* Manually refresh highlighting for a buffer. Useful after external changes or for debugging. Parameters: ~ {bufnr} (integer, optional) Buffer number. Defaults to current buffer. ============================================================================== IMPLEMENTATION *diffs-implementation* Summary / commit detail views: ~ 1. `FileType fugitive` or `FileType git` (for `fugitive://` buffers) triggers |diffs.attach()| 2. The buffer is parsed to detect file headers (`M path/to/file`, `diff --git a/... b/...`) and hunk headers (`@@ -10,3 +10,4 @@`) 3. For each hunk: - Language is detected from the filename using |vim.filetype.match()| - Diff prefixes (`+`/`-`/` `) are stripped from code lines - Code is parsed with |vim.treesitter.get_string_parser()| - If no treesitter parser and `vim.enabled`: vim syntax fallback via scratch buffer and |synID()| - Background extmarks (`DiffsAdd`/`DiffsDelete`) at priority 198 - `Normal` extmarks at priority 199 clear underlying diff foreground - Syntax highlights are applied as extmarks at priority 200 - Conceal extmarks hide diff prefixes when `hide_prefix` is enabled 4. Re-highlighting occurs on `TextChanged` (debounced) and `Syntax` events Diff mode views: ~ 1. `OptionSet diff` detects when any window enters diff mode 2. All `&diff` windows in the tabpage receive a window-local 'winhighlight' override that remaps `DiffAdd`/`DiffDelete`/`DiffChange`/`DiffText` to background-only variants, allowing existing treesitter highlighting to show through the diff colors ============================================================================== KNOWN LIMITATIONS *diffs-limitations* Syntax Highlighting Flash ~ *diffs-flash* When opening a fugitive buffer, there is an unavoidable visual "flash" where the buffer briefly shows fugitive's default diff highlighting before diffs.nvim applies treesitter highlights. This occurs because diffs.nvim hooks into the `FileType fugitive` event, which fires after vim-fugitive has already painted the buffer. Even with `debounce_ms = 0`, the re-painting goes through Neovim's event loop. To minimize the flash, use a low debounce value: >lua require('diffs').setup({ debounce_ms = 0, }) < ============================================================================== HIGHLIGHT GROUPS *diffs-highlights* diffs.nvim defines custom highlight groups. All are set with `default = true`, so colorschemes can override them by defining them first. Fugitive unified diff highlights: ~ *DiffsAdd* DiffsAdd Background for `+` lines. Derived by blending `DiffAdd` background with `Normal` at 40% alpha. *DiffsDelete* DiffsDelete Background for `-` lines. Derived by blending `DiffDelete` background with `Normal` at 40% alpha. *DiffsAddNr* DiffsAddNr Line number for `+` lines. Foreground from `diffAdded`, background from `DiffsAdd`. *DiffsDeleteNr* DiffsDeleteNr Line number for `-` lines. Foreground from `diffRemoved`, background from `DiffsDelete`. Diff mode window highlights: ~ These are background-only variants used for |winhighlight| remapping in `&diff` windows, allowing treesitter syntax to show through. *DiffsDiffAdd* DiffsDiffAdd Background-only version of `DiffAdd`. *DiffsDiffDelete* DiffsDiffDelete Background-only version of `DiffDelete`. *DiffsDiffChange* DiffsDiffChange Background-only version of `DiffChange`. *DiffsDiffText* DiffsDiffText Background-only version of `DiffText`. To customize these in your colorscheme: >lua vim.api.nvim_set_hl(0, 'DiffsAdd', { bg = '#2e4a3a' }) vim.api.nvim_set_hl(0, 'DiffsDiffDelete', { link = 'DiffDelete' }) < ============================================================================== HEALTH CHECK *diffs-health* Run |:checkhealth| diffs to verify your setup. Checks performed: - Neovim version >= 0.9.0 - vim-fugitive is installed (optional) ============================================================================== vim:tw=78:ts=8:ft=help:norl: