# RRethy/vim-illuminate: three highlight groups, two config systems, one tree

> vim-illuminate highlights other uses of the word under the cursor through LSP, Tree-sitter or regex. Its documentation is thorough about functions and commands, and quietly inconsistent about keymaps, group names and the delay default.

**RRethy/vim-illuminate** — illuminate.vim - (Neo)Vim plugin for automatically highlighting other uses of the word under the cursor using either LSP, Tree-sitter, or regex matching.

- Repository: https://github.com/RRethy/vim-illuminate
- Stars: 2,470 · Forks: 75
- Language: Lua
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/rrethy-vim-illuminate

## Three highlight groups that all default to the same underline

The plugin documents three highlight groups, one for references with no kind information, one for reads and one for writes. All three ship the same definition.

```vim
hi def IlluminatedWordText gui=underline cterm=underline
hi def IlluminatedWordRead gui=underline cterm=underline
hi def IlluminatedWordWrite gui=underline cterm=underline
```

gui and cterm are set to underline in every case, so out of the box a write reference, a read reference and a reference the provider could not classify look identical. The split only becomes visible once you override one of them, which means the kind information the providers return is available to your colourscheme but unused until you ask for it. There is a second naming problem further down the same file. The Vim section shows two autocmd blocks that link a group called illuminatedWord to CursorLine or set it to underline, all lowercase, while the groups documented above are IlluminatedWordText, IlluminatedWordRead and IlluminatedWordWrite. Those are different strings, and a link to a name nothing defines is a link that does nothing.

## The quickstart says a-n and a-p, the function list says c-n and c-p

The Quickstart promises two keymaps for moving between references, written as a-n and a-p, plus a-i as a textobject for the reference under the cursor. Later, the entry for invisible_buf says that turning off the highlighting will not stop the engine from running, so you can still use c-n and c-p. The two lists use different modifier keys for the same two motions, and the file does not say whether both are bound, whether one is a leftover, or whether the textobject moved too. Nothing in the Functions section names a keymap at all, so the two spellings never meet. For a plugin whose whole value is moving quickly between references, that is the first thing a user checks, and the documentation gives two answers. The textobj_select function is the Lua side of a-i and is documented properly, so at least the mechanism is clear: the keymaps are conveniences over functions you can call yourself.

## freeze, invisible and pause are three ways to turn the same thing off

The Functions section offers nine buffer-level switches, and reading them in order shows why a user might pause the plugin and find that it still does something. pause_buf stops the buffer and resumes it, with a toggle for both. freeze_buf freezes the illumination on the buffer and explicitly will not clear the highlights, and there is a matching unfreeze and a toggle for the frozen state. invisible_buf turns off the highlighting without stopping the engine, which is the one that explains why the keymaps keep working, and visible_buf turns it back on, with a toggle for visibility. So there are three distinct states a buffer can be in: running and highlighting, running without highlighting, and stopped with the old highlights still painted on screen. Freeze is the only one that leaves the previous state visible, which makes it the useful one for stepping through code, and invisible is the one that keeps the reference engine warm. The three global pause commands sit above all of it and apply everywhere rather than per buffer.

## The Lua configuration stops partway through the fourth key

The Configuration section shows the default table, and it is the only place the option names appear.

```lua
require('illuminate').configure({
    providers = {
        'lsp',
        'treesitter',
        'regex',
    },
    delay = 100,
    filetype_overrides = {},
```

Three of those keys are explained in the comments around them: providers is a list ordered by priority, so lsp is consulted first and regex last; delay is in milliseconds and defaults to 100; filetype_overrides takes filetype keys whose values are tables supporting the same keys passed to configure. Then the block ends inside the comment introducing the fourth key, filetypes_denylist, after the words filetypes to. The comment on filetype_overrides also mentions a fifth name, filetypes_allowlist, which never appears as a key of its own. So the visible configuration gives you three usable options, one half-explained, and one that exists only as a word in a sentence about another key. Reading that table tells you the defaults are conservative, since regex is the last resort and a hundred milliseconds is a deliberate pause rather than no delay at all.

## Two configuration vocabularies whose delay defaults disagree

The Lua table is one configuration system. The Vim section documents a completely separate one built from global variables: g:Illuminate_delay, g:Illuminate_highlightUnderCursor, g:Illuminate_ftHighlightGroups, g:Illuminate_ftblacklist and g:Illuminate_ftwhitelist. The names do not overlap with the Lua keys, and neither do the semantics. The Lua side speaks of filetypes_denylist and filetypes_allowlist while the Vim globals speak of a blacklist and a whitelist. The Lua side has filetype_overrides, where each filetype maps to a nested table, while the Vim globals have ftHighlightGroups, where each filetype maps to a list of syntax highlight groups. And the delay defaults are not the same value: the Lua configuration sets 100 milliseconds, while g:Illuminate_delay is documented as defaulting to 0. Whichever build you run, one of those two numbers is not what you get, and the file does not reconcile them. The ftHighlightGroups entry also carries a wording slip, saying that if the whitelist for that filetype already exists it will override the blacklist, in a section that had been calling the positive list a list of highlight groups.

## autoload/ and lua/ in one tree, which is how the old build stays loadable

The top level listing holds both lua/ and autoload/, plus plugin/ and doc/. That is two implementations in one repository: lua/ is the Neovim version this README leads with, and autoload/ with plugin/ is the Vimscript path that the deprecated section describes. Keeping both is what makes the escape hatch work, since the Vim Users section tells Neovim users they can force the old version by setting g:Illuminate_useDeprecated to 1 in their init.vim. The cost is that the documentation has to describe two command sets, two configuration systems and two delay defaults, which is exactly the split described above. The deprecated section is at least explicit about its status, calling itself deprecated for Neovim users and noting that delay only works for Vim8 and Neovim. Two smaller things sit in the same listing: doc/ for the editor's own help files, and a file called foo.txt at the root, which nothing in the documentation refers to.

## The quickstart gives no install command and the last line stops mid-sentence

The Quickstart says to install the plugin and states that things will work with no configuration needed, repeating the word work with emphasis markers still visible around the second one. It never says how. No plugin manager is named, no command is given, and there is no install section anywhere in the file. The repository publishes no GitHub releases and records no homepage, so there is no release page and no site to fall back on either. The Overview has the same problem in a smaller form: its only content is a bare attachment URL with no caption saying what the asset shows. And the file ends where the last sentence is cut off, introducing a way to highlight the word under the cursor differently from the other matches, and stopping at the word follow. Between the missing install path, the missing release history and the two unfinished edges, this is a document that is strongest in the middle, where the commands and functions are listed exhaustively, and thinnest exactly where a new user starts.

## Conclusion

vim-illuminate is worth installing if you want reference highlighting without wiring anything up, and it is worth reading the source of the docs rather than the prose, because the file disagrees with itself in three places a first-time user hits. Check the keymap names before you build muscle memory, since the quickstart and the function documentation use different ones for moving between references. Check the group names too, because the documented capitalised groups and the lowercase group used in the autocmd examples are not the same string. And decide which configuration vocabulary you are in: the Lua configure call and the deprecated g:Illuminate_* globals do not share names and do not share a delay default, so mixing them gives you a delay you did not ask for. Installation is not covered anywhere in the repository, and it publishes no releases.

## FAQ

### What does RRethy/vim-illuminate actually highlight?

Other uses of the word under the cursor, using LSP, Tree-sitter or regex matching. The default provider list is ordered by priority as lsp, treesitter, regex, and the default delay before highlighting is 100 milliseconds.

### How do I install RRethy/vim-illuminate?

The quickstart says only to install the plugin, with no command and no plugin manager named, and there is no install section in the README. The repository publishes no GitHub releases and records no homepage, so the install path is left to the reader.

### How do I pause vim-illuminate?

Globally with :IlluminatePause, :IlluminateResume and :IlluminateToggle. Per buffer, use :IlluminatePauseBuf, :IlluminateResumeBuf and :IlluminateToggleBuf, or the Lua functions pause_buf, resume_buf and toggle_buf.

### What is the difference between freeze_buf, invisible_buf and pause in vim-illuminate?

freeze_buf leaves the current highlights on screen, invisible_buf turns the highlighting off while leaving the engine running so reference motion still works, and the pause functions stop the plugin. Each of the three states has a toggle and a matching on function.

### Can I use vim-illuminate in Vim rather than Neovim?

Yes, through a deprecated Vimscript implementation kept in the same repository. Neovim users can force it with let g:Illuminate_useDeprecated = 1, and that build is configured through g:Illuminate_ variables such as g:Illuminate_delay, g:Illuminate_ftblacklist and g:Illuminate_ftwhitelist.

### Which highlight groups does vim-illuminate define?

IlluminatedWordText for references with no kind information, IlluminatedWordRead for reads and IlluminatedWordWrite for writes. All three default to gui=underline cterm=underline, so they look identical until a colourscheme overrides them.

## Sources

- [Issues](https://github.com/RRethy/vim-illuminate/issues)
- [License: MIT](https://github.com/RRethy/vim-illuminate/blob/master/LICENSE)
- [README](https://github.com/RRethy/vim-illuminate/blob/master/README.md)
- [RRethy/vim-illuminate on GitHub](https://github.com/RRethy/vim-illuminate)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/rrethy-vim-illuminate
