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
_images/lazy_annotated.gif

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 :e

<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

ColorizerToggle

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

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 " to '

csw}

add { and } surrounding word

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 #tagname across files in directory

<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

Browsher

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.