Nvim plugins¶
Plugins are configured in lua/plugins/*.lua
.
Plugins are configured using lazy.nvim. This supports lazy-loading of plugins to keep a snappy startup time, and only load plugins when they’re needed. See Migrating to Neovim Lua config for my rationale on that.
Quick-reference on lazy.nvim
Each plugin spec in lua/plugins/*.lua
is a table. The first property is
the name of the plugin. Other properties:
lazy
: only load when requested by something else. Saves on initial load time, but use this with care since it can get confusing.ft
: only load the plugin when editing this filetype. Implies lazy=true.cmd
: only load the plugin when first running this command. Implies lazy=true.keys
: only load the plugin when using these keymappings. Implies lazy=true.config
: run this stuff after the plugin loads. If config = true, just run the default setup for the plugin.init
: similar to config, but used for pure-vim plugins
If keys are specified, this is the only place they need to be mapped, and they
will make their way into the which-key menu even if they trigger a lazy-loaded
plugin. Use the desc
argument to give which-key a description to use.
Note
Don’t like a plugin? Find it in lua/plugins/*.lua
and add enabled
= false
next to where the plugin is named. For example:
{ "user/plugin-name", enabled = false },
Or delete the file completely.
screencast of lazy.nvim setting up plugins

Because of how frequently nvim changes, each plugin section below has
a changelog. Since I have reorganized files over the years, the changelogs show
the mention of a plugin in a commit message, in a filename, or as part of the
changeset of a commit in an attempt to catch all of the changes. This may be
a little overzealous (for example the trouble
plugin picks up commits
related to troubleshooting) but I’ve opted to err on the side of completeness.
Plugin list¶
I’ve organized the plugins into broad categories:
Interfaces¶
These plugins add different interfaces unrelated to git (interfaces related to git are described above).
telescope
¶
Telescope provides a floating window with fuzzy-search selection.
Searching and selecting what, you ask? Pretty much anything you hook it up to.
Type in the text box to filter the list. Hit enter to select (and open the selected file in a new buffer). Hit Esc twice to exit.
command |
description |
---|---|
<leader>ff |
Find files under this directory. Handy alternative to |
<leader>fg |
Search directory for string. This is like using ripgrep, but in vim. Selecting entry takes you right to the line. |
<leader>/ |
Fuzzy find within buffer |
<leader>fc |
Find code object |
Other useful things you can do with Telescope:
:Telescope highlights
to see the currently set highlights for the colorscheme.:Telescope builtin
to see a picker of all the built-in pickers. Selecting one opens that picker. Very meta. But also very interesting for poking around to see what’s configured.:Telescope planets
to use a telescope:Telescope autocommands
,:Telescope commands
,:Telescope vim_options
,:Telescope man_pages
are some other built-in pickers that are interesting to browse through.
nvim-tree
¶
nvim-tree provides a filesystem tree for browsing.
command |
description |
---|---|
<leader>fb |
Toggle file browser |
- (within browser) |
Go up a directory. |
Enter (within browser) |
Open file or directory, or close directory |
The window-switching shortcuts <leader>w and <leader>q (move to windows left and right respectively; see toggleterm) also work.
which-key
¶
which-key displays a popup with possible key bindings of the command you started typing. This is wonderful for discovering commands you didn’t know about, or have forgotten.
The window will appear 1 second after pressing a key. For example, try pressing the leader key (,) and waiting a second to see all the keys you can press after the leader and what the behavior will be.
The length of this delay is configured with vim.o.timeoutlen
, e.g.
vim.o.timeoutlen=500
for half a sectond). There is no timeout though for
registers ("
) or marks ('
) or spelling (z=
over a word).
You can hit a displayed key to execute the command, or if it’s a multi-key
command (typically indicated with a +prefix
to show there’s more), then
that will take you to the next menu.
Use <Backspace> to back out a menu. In fact, pressing any key, waiting for the menu, and then hitting backspace will give a list of all the default mapped keys in vim.
There is currently no extra configuration. Instead, when a key is mapped
(either in lua/mappings.lua
or lua/plugins/*.lua
), an
additional parameter desc = "description of mapping"
is included. This
allows which-key to show a description. Mappings with no descriptions will
still be shown.
-- example mapping using vim.keymap.set, with description
vim.keymap.set('n', '<leader>1', ':bfirst<CR>',
{ desc = "First buffer" })
-- example mapping when inside a plugin spec
{ "plugin/plugin-name",
keys = {
{ "<leader>1", ":bfirst<CR>", desc = "First buffer" },
}
}
command |
description |
---|---|
any |
after 1 second, shows a popup menu |
<Backspace> |
Goes back a menu |
z= (over a word) |
Show popup with spelling suggestions, use indicated character to select |
' |
Show popup with list of marks |
" |
Show popup with list of registers |
aerial
¶
aerial provides a navigation sidebar for quickly moving around code (for example, jumping to functions or classes or methods). For markdown or ReStructured Text, it acts like a table of contents.
command |
description |
---|---|
<leader>a |
Toggle aerial sidebar |
{ and } |
Jump to prev or next item (function, snakemake rule, markdown section) |
For navigating complex codebases, there are other keys that are automatically mapped, which you can read about in the README for aerial.
Visuals¶
These plugins add various visual enhancements to nvim.
bufferline
¶
bufferline.nvim provides the tabs along the top.
command |
description |
---|---|
<leader>b, then type highlighted letter in tab |
Switch to buffer |
beacon
¶
Beacon provides an animated marker to show where the cursor is.
command |
description |
---|---|
n or N after search |
Flash beacon at search hit |
lualine
¶
lualine provides the status line along the bottom.
No additional commands configured, but see the homepage for all the things you can add to it.
indent-blankline
¶
indent-blankline shows vertical lines where there is indentation, and highlights one of these vertical lines to indicate the current scope.
No additional commands configured. However, depending on the font you use, you may want to play around with the symbol used.
render-markdown
¶
render-markdown provides a nicer reading experience for markdown files. This includes bulleted list and checkbox icons, fancy table rendering, colored background for code blocks, and more.
In my testing I found it to be more configurable and performant than the
obsidian.nvim
equivalent functionality, and in daler/zenburn.nvim
I’ve
added highlight groups for this plugin.
Some notes about its behavior:
It uses “conceal” functionality to replace things like
-
(for bulleted lists) with the unicode•
. It hides URLs and only shows the link text (like a website does)It’s configured to differentiate between a web link (http) and an internal link (no http) and show an icon for an internal link.
It has functionality for parsing headlines and making them stand out more in a document. The actual styling of headlines is configured in the colorscheme.
Code blocks have an icon indicating their language, and the background of code blocks is different from surrounding text.
Tables are rendered nicely
This plugin is specifically disabled for RMarkdown files, which are typically heavy on the source code, and the background of code chunks can get distracting when entering and exiting insert mode. However, this plugin can be useful when reviewing a long RMarkdown file to focus on the narrative text.
command |
description |
---|---|
<leader>rm |
Toggle [r]ender[m]arkdown on an [r][m]arkdown file |
nvim-colorizer
¶
nvim-colorizer is a high-performance color highlighter. It converts hex codes to their actual colors.
command |
description |
---|---|
|
Toggle colorizing of hex codes |
lush
¶
lush is a helper for adjusting colors in a colorscheme.
Open up a color scheme file, run :Lushify
, and you can use <C-a> and
<C-x> to increase/decrease values. This gives you live feedback as
you’re working. See the homepage linked above for a demo, and zenfade for a colorscheme that used lush (and
so supports it well).
Everything else¶
These plugins don’t have a clear categorization. That doesn’t mean they’re not super helpful though!
vim-commentary
¶
vim-commentary lets you easily toggle comments on lines or blocks of code.
command |
description |
---|---|
gc on a visual selection |
toggle comment |
gcc on a single line |
toggle comment |
accelerated-jk
¶
accelerated-jk speeds up j and k movements: longer presses will jump more and more lines.
In particular, you might want to tune the acceleration curve depending on your system’s keyboard repeat rate settings – see the config file for an explanation of how to tweak.
command |
description |
---|---|
j, k |
Keep holding for increasing vertical scroll speed |
blink
¶
blink offers autocomplete.
In this config, I’ve chosen to mimic the bash style of completion, the commands documented here reflect that. I’ve also disabled the menu popping up all the time. There are a lot of ways you can customize this yourself though – see the blink docs.
command |
description |
---|---|
<C-space> |
Open completion menu |
<Tab> (when typing and the cursor is in a word) |
Open completion menu |
<Tab>, <Shift-Tab> (in menu) |
Next, previous entry |
Enter (when menu visible) |
Select entry |
up/down arrow (in menu) |
Next, previous entry |
treesitter
¶
treesitter is a parsing library that underpins many other plugins.
You install a parser for a language, and it figures out which tokens are functions, classes, variables, modules, etc. Then it’s up to other plugins to do something with that. For example, colorschemes can use that information, or you can select text based on its semantic meaning within the programming language (like easily select an entire function, or the body of a for-loop).
Treesitter is configured to ensure the parsers listed in the config are installed. These will be attempted to be installed automatically, but they do require a C compiler to be available.
On a Mac, this may need XCode Command Line Tools to be installed.
A fresh Ubuntu installation will need
sudo apt install build-essential
RHEL/Fedora will need
sudo dnf install 'Development Tools'
(and may need the EPEL repo enabled).Alternatively, if you don’t have root access, you can install compiler packages via conda,
Alternatively, comment out the entire ensure_installed
block in
~/.config/nvim/lua/plugins/treesitter.lua
; this means you will not have
treesitter-enabled syntax highlighting though.
command |
description |
---|---|
<leader>cs |
Start incremental selection |
<Tab> (in incremental selection) |
Increase selection by node |
<S-Tab> (in incremental selection) |
Decrease selection by node |
toggleterm
¶
ToggleTerm lets you easily interact with a terminal within vim.
The greatest benefit of this is that you can send text from a text buffer
(Python script, RMarkdown file, etc) over to a terminal. This lets you
reproduce an IDE-like environment purely from the terminal. The following
commands are custom mappings set in .config/nvim/init.vim
that affect
the terminal use.
Note
The terminal will jump to insert mode when you switch to it (either using keyboard shortcuts or mouse), but clicking the mouse a second time will enter visual mode, just like in a text buffer. This can get confusing if you’re not expecting it.
You can either click to the text buffer and immediately back in the terminal, or use a or i in the terminal to get back to insert mode.
command |
description |
---|---|
<leader>t |
Open terminal to the right. |
<leader>w |
Move to the right window (assumes it’s terminal), and enter insert mode |
<leader>q |
Move to the text buffer to the left, and enter normal mode |
<leader>cd |
Send the current RMarkdown code chunk to the terminal, and jump to the next chunk |
gxx |
Send the current line to the terminal buffer |
gx |
Send the current selection to the terminal buffer |
<leader>k |
Render the current RMarkdown file to HTML using knitr::render(). Assumes you have knitr installed and you’re running R in the terminal buffer. |
<leader>k |
Run the current Python script in IPython. Assumes you’re running IPython in the terminal buffer. |
vim-diff-enhanced
¶
vim-diff-enhanced provides additional diff algorithms that work better on certain kinds of files. If your diffs are not looking right, try changing the algorithm with this plugin:
command |
description |
---|---|
:EnhancedDiff <algorithm> |
Configure the diff algorithm to use, see below table |
The following algorithms are available:
algorithm |
description |
---|---|
myers |
Default diff algorithm |
default |
alias for myers |
minimal |
Like myers, but tries harder to minimize the resulting diff |
patience |
Patience diff algorithm |
histogram |
Histogram is similar to patience but slightly faster |
vim-table-mode
¶
vim-table-mode provides easy formatting of tables in Markdown and Restructured Text
Nice Markdown and ReStructured Text tables are a pain to format. This plugin makes it easy, by auto-padding table cells and adding the header lines as needed.
With table mode enabled, || on a new line to start the header.
Type the header, with column names separated by |.
On a new line, use || to fill in the header underline.
On subsequent rows, delimit fields by | (including a leading and trailing |)
Complete the table with || on a new line.
command |
description |
---|---|
:TableModeEnable |
Enables table mode, which makes on-the-fly adjustments to table cells as they’re edited |
:TableModeDisable |
Disables table mode |
:Tableize |
Creates a markdown or restructured text table based on TSV or CSV text |
TableModeRealign |
Realigns an existing table, adding padding as necessary |
flash
¶
flash lets you jump around in a buffer with low mental effort.
The trick is to keep your eyes on the destination. Hit s, and type the first 2 letters of where you’re trying to go. This plugin will dim the rest of the buffer, only highlighting instances where those 2 letters occur. It will also add a third letter after it. If you type that third letter, the cursor will jump to that location.
Alternatively, if a treesitter parser is installed for this filetype, you can use S and suffix letters will be shown at different levels of the syntax tree. For example inside a for-loop (i.e. don’t include the for); outside a for-loop (including the for), an entire function, entire Rmd code chunk, etc. In this mode, which is just for selection, you don’t type the two characters you’re looking for. Instead you just type the letter coresponding to level of code that you want to select.
command |
description |
---|---|
s in normal mode |
jump to match (see details) |
S in normal mode |
select this treesitter node (see details) |
Ctrl-s when searching |
Toggle flash during search |
vim-surround
¶
vim-surround lets you easily change surrounding characters.
command |
description |
---|---|
cs"' |
change surrounding |
csw} |
add |
csw{ |
same, but include a space |
vis
¶
vis provides better behavior on visual blocks.
By default in vim and neovim, when selecting things in visual block mode, operations (substitutions, sorting) operate on the entire line – not just the block, as you might expect. However sometimes you want to edit just the visual block selection, for example when editing TSV files.
command |
description |
---|---|
<C-v>, then use :B instead of : |
Operates on visual block selection only |
stickybuf.nvim
¶
stickybuf.nvim prevents text buffers from opening up inside a terminal buffer.
Otherwise, you run nvim inside of nvim, and it gets hard to control which instance of nvim is supposed to be interpreting your keystrokes.
No additional commands configured.
obsidian.nvim
¶
obsidian.nvim is a plugin originally written for working with Obsidian which is a GUI notetaking app (that uses markdown and has vim keybindings). If you’re an Obsidian user, this plugin makes the experience with nvim quite nice.
However, after using it for a bit I really like it for markdown files in general, in combination with the render-markdown plugin.
I’ve been using it to take daily notes.
The mapped commands below use o ([o]bsidian) as a a prefix.
command |
description |
---|---|
Enter on any link |
Open the link in a browser (if http) or open the file in a new buffer |
<leader>od |
[o]bsidian [d]ailies: choose or create a daily note |
<leader>os |
[o]bsidian [s]search for notes with ripgrep |
<leader>ot |
[o]bsidian [t]ags finds occurrences of |
<leader>on |
[o]bsidian [n]ew link with a word selected will make a link to that new file |
browsher.nvim
¶
browsher.nvim constructs a URL for GitHub or GitLab that includes line highlighting, based on your visual selection.
Run :Browsher
on a line of code, and a URL to that line of code in the
upstream repo (GitHub, GitLab) will be copied to your clipboard.
It is currently configured to store the URL on your OS clipboard, which makes
it useful for working on remote systems. However, you can comment out the
open_cmd
config option if you want it to automatically open a browser tab
for working on a local machine.
It is also currently configured to optionally read from a file stored outside
of a dotfiles repo. This is to support the construction of URLs for private
GitHub/GitLab instances. See the config file
.config/nvim/lua/plugins/browsher.lua
for details.
-- Add the following to ~/.browsher.lua, using your own instance URL
return {
["gitlab.private.com"] = {
url_template = "%s/-/blob/%s/%s",
single_line_format = "#L%d",
multi_line_format = "#L%d-%d",
},
}
command |
description |
---|---|
|
Store URL on OS clipboard |
indent-o-matic
¶
indent-o-matic is “dumb automatic fast indentation detection”.
To quote more from the home page, “Instead of trying to be smart about detecting an indentation using statistics, it will find the first thing that looks like a standard indentation (tab or 8/4/2 spaces) and assume that’s what the file’s indentation is. This has the advantage of being fast and very often correct while being simple enough that most people will understand what it will do predictably”
When starting a blank file, if it’s not doing what you want when you hit
<Tab> then give it a hint: manually use the tab spacing you want and then
run :IndentOMatic
to re-check.
No additional commands configured.
TreeSJ
¶
TreeSJ uses treesitter to split and join nodes. This is one of those things that is a lot easier to show than explain. It converts back and forth between this:
def f(a, b=True, c='default'):
pass
and this:
def f(
a,
b=True,
c='default',
):
pass
command |
description |
---|---|
<leader>j |
Toggle split/join |
Colorschemes¶
If colors look broken then you may be using a terminal like the default Terminal.app on macOS that does not support true color. See nvim has light gray text, colorscheme looks broken for how to fix.
For years I’ve been using the venerable zenburn colorscheme. However, now with additional plugins and highlighting mechansims (especially treesitter), it became important to be able to configure more than what that colorscheme supported.
zenburn.nvim is a reboot of this colorscheme, but there were some parts of it that I wanted to change, or at least have more control over.
My fork of the repo is used here. If you’re interested in tweaking your own colorschemes, I’ve hopefully documented that fork enough to give you an idea of how to modify on your own.
zenfade is what I’ve been working on recently. It’s a warmer and more faded version of zenburn and I like it quite a bit. However, since zenburn has been the default for a while and other people are using it (and are probably used to it), I’m not setting zenfade to be the default, at least not yet.
Changelog for zenburn
:
Changelog for zenfade
:
Changelog for colorscheme
:
Deprecations¶
Sometimes there are better plugins for a particular functionality. I’ve kept the documentation here in case you’re using an old version.
Deprecated plugins¶
vim-rmarkdown
¶
vim-pandoc
¶
vim-pandoc-syntax
¶
vim-tmux-clipboard
¶
leap.nvim
¶
nvim-cmp
¶
vim-sleuth
¶
Notes on tried plugins¶
nvim-aider, when paired with neo-tree, was nice to use for adding files to the context. But now:
nvim-aider supports nvim-tree too now
aider has gotten better at tab-completion, making it easy to add even deeply-nested files
nvim-tree’s - to go up a directory was confusing with neo-tree’s “remove from aider context”
It’s a better experience to just keep aider running in a different tmux pane/window … no need to consume nnvim screen real estate.
vim-matchup was nice to have (esp for Python) but it caused errors when trying to edit a buffer where a treesitter parser wasn’t installed.
jakewvincent/mkdnflow.nvim
was nice for hitting <CR> to open a linked file and then <BS> to go back. But I realized I needed to keep the context in my head of where I came from. I prefer having separate buffers open so I can keep track of that (and buffer navigation helps move between them). This plugin is also pretty nice for collapsing sections into fancy headers. But I didn’t consider it sufficiently useful to warrant including and configuring it.lukas-reineke/headlines.nvim
had nice section headers, and it had backgrounds for code blocks. However that ended up having too much visual noise for my taste.nvim-telekasten/telekasten.nvim
has nice pickers for tags and files and making links, but it was too opinionated for forcing the “telekasten” style of note-taking.