Neovim: The IDE That Grows With You

Using Neovim for software development

I love coding, and I love using Neovim to do it. In this article, I hope to inspire and make it

easier for other developers to consider Neovim for software development. Who knows, maybe

you will love it too.

A little background

I've been a professional software developer for over 20 years, but I haven't always used vim for

programming.

 

I got my first taste of vim in college as I was studying computer science. I had a professor there

who was a true vim master. I recall staring up at his screen as he jumped around and edited

code with god-like omnipotence. At the time, I had no idea what combination of keys he was

pressing to make the editor bend to his will with such minimal effort, but I wanted that power.

I used vim for coding throughout college, and I was getting pretty good at it. Then, sadly, I

stopped using it when I started my first programming job. During this phase of my life vim was

relegated to note taking and editing text files from the terminal. After using full-blown editors like

Eclipse for a while, I subconsciously came to the conclusion that vim could not compete in the

world of IDEs, and at the time perhaps that was true.

 

About ten years into my career, we hired a new guy at the place I was working. I was shocked

to see that he used vim exclusively for the Ruby on Rails development we were doing at the

time. For the second time in my life, I was inspired by someone else's display of vim prowess. I

had never stopped enjoying the limited opportunities I had to use vim, so I was super excited at

the prospect of using it full-time for development. So that's what I did, and, for the most part, I

have been using it as my main code editor ever since.

 

Why bother learning vim

Vim is a modal editor which means it has more than one mode of operation. The two primary

modes are "insert" and "normal". Insert mode behaves like regular text editors where the keys

you type are written into the document. Normal mode is used for moving around the file (moving

the cursor within the file) and executing commands against the text within the file. Because

normal mode is distinct from insert mode, every key on the keyboard is available to perform

operations. This is what enables the efficiencies in vim because powerful movements can be

achieved without ever having to move your hands off of the home row on your keyboard. The

following table gives just a few examples of these efficiencies. Try for yourself and see how

much nicer the vim mappings are.

Using Neovi for software development

It may take a little while, but once you get used to vim mappings, having to use arrow keys,

specialized keys like home/end, contorting your fingers to press complex combinations of

modifiers, or even using the mouse feels very tedious.

 

Vim has so many commands to improve editing speed; even though I have been using vim for

over 20 years, I am still learning new things regularly. It's always fun when one vim user is

watching another vim user and says something like: "Wait, why did you do that? You know you

can just do ...". I have learned and taught many vim tricks this way.

 

I know people can get extremely fast with modeless editors using mappings like those in the

second column of the table above. I know many are even much faster than me using vim.

However, my claim is that vim offers the highest upper bound of speed for any given person.

 

Two ways to leverage Vim for coding

There are two levels of adoption when it comes to using Vim for software development.

The first level is turning on vim mode/emulation in your current IDE (e.g. Visual Studio Code).

Most IDEs support this at some level. For Jetbrains products, the Ideavim plugin is excellent. I

think everyone should at least try this first level of adoption. In fact, one could argue that you

get the best of both worlds with this approach: the efficiencies of modal editing and vim

movements/commands as well as all of the bells and whistles of a full blown IDE. I, personally,

would not make this argument, but I certainly understand the position.

 

The next level is actually using Neovim (or Vim) as your IDE. I.e. literally opening up a terminal,

changing directories to your project and running the command, nvim. So fun.

 

Vim has come a long way since I started using it in college and Neovim takes it to the next

level. There are tons of quality plugins, and the available plugin managers make it simple to

start using them. Configuration and customization are also much better now since Neovim

supports using Lua for scripting.

 

The following sections are mainly for those who want to go all the way and use Neovim as their

IDE.

Installation and config

Installation of Neovim is straightforward. Just follow the instructions on the installation page.

 

Neovim is highly configurable with hundreds of options that can be set, limitless mapping

possibilities, and flexibility in creating custom commands and functions. Because of this, it's

easy for your configuration to get a little messy. It is worth taking some time at the beginning

and periodically to keep things organized and trimmed down. A clean configuration is like a

clean room, it's more enjoyable to be in.

 

Describing the options, how to do mappings, and how to create custom

commands/functions is out of scope for this article but I recommend learning about these

things from the Neovim documentation.

 

The entry point for your configuration in Neovim is the init.vim (or init.lua) file. I

recommend going with Lua instead of vim's native script. I prefer using Lua, especially if I plan

to do any complex scripting. The following table lists the standard location to create your

init.vim or init.lua file.

 

Env Location

Using Neovi for software development 2

I like to break up my configuration into multiple files to help me keep things organized. Including

separate files from your init.lua file can be done with statements like the following:

3-1

Note: this loads a file located at <config_root>/lua/core/options.lua then runs the

config() function from the loaded module.

 

Here is what my config structure looks like, but do what makes the most sense to you.

  • .config/nvim: config root
    • lua/: the root folder of any lua files you want to include
      • core/
        • autocommands.lua: where I define custom autocommands
        • mappings.lua: where I define my key mappings
        • options.lua: where I set options to my liking
      • custom/: lua files where I create custom functions/commands
      • plugins/: plugin configuration (I use lazy.nvim as my plugin manager)
    • init.lua: entry point for the config

I also recommend creating a git repo on GitHub or a similar site to house your configuration.

This makes it quick and easy to get your Neovim configuration set up on new computers.

 

Must-have plugins

To this point we've talked about using vim in a general sense, but to really use it effectively as

an IDE for software development, you will likely want to install some plugins.

 

Plugin management, including installing and uninstalling, enabling and disabling, configuring,

and upgrading, is a common activity when using Neovim as your IDE, especially when you are

first starting out. To make this as seamless as possible, use a good plugin manager. There are

multiple options, but I like to use lazy.nvim. It has been working great for me.

 

Staples

Here are some general purpose plugins that are staples for a lot of vim users.

  • surround: provides mappings to easily delete, change and add surroundings (parenthesis,
    brackets, quotes, xml tags, etc) in pairs
  • vim-repeat: enhances functionality of the vim repeat command (.) so that multi-step edits
    provided by plugins can be repeated
  • vim-easymotion: enhances some vim motions to provide super efficient movements
  • snacks: This is actually a collection of quality-of-life plugins for Neovim. Pick and choose
    the ones that bring you joy.

 

Coding assistance

Some of the most important features of an IDE are related to code assistance; these include

things like syntax highlighting, autocompletion, jump to definition, error and warning indicators,

and refactoring support.

 

Here are some must-have plugins to bring these features into your Neovim setup.

  • nvim-treesitter: along with the tree-sitter executable, enables syntax parsing to provide
    syntax highlighting, code folding, and structural navigation for any programming language
    you might want to use
  • nvim-lspconfig: Neovim comes with built-in support to act as an LSP (language server
    protocol) client. The nvim-lspconfig plugin provides default configurations to simplify the
    setup of LSP servers.
  • mason: Although nvim-lspconfig provides default configurations for LSP servers, you still
    need to install and run the external LSP server executables. The mason plugin is a
    package manager for external tools such as LSP servers, DAP servers (for debugging),
    linters, and formatters.
  • nvim-cmp: a completion engine to support autocomplete from various sources such as
    LSPs and snippets
  • trouble: a pretty list for showing diagnostics, references, telescope results, quickfix and
    location lists
  • copilot: for if you want copilot integration (AI completions)
  • nvim-dap & nvim-dap-ui: plugins to support debugging in Neovim

 

File navigation

Another set of features that all IDEs need to support is related to file navigation such as finding

and opening files, finding files containing text, viewing and navigating the file tree, etc. With the

following plugins Neovim can be configured with amazing support for these types of features.

  • neo-tree: file system browser
  • oil: The oil plugin allows editing the file system like a normal Neovim buffer. Neotree
    supports file system edits as well but using the oil plugin for this is so intuitive and fun to
    use.
  • telescope: highly extensible fuzzy finder used for finding files by name, finding files
    containing text, finding files in the current git commit, finding symbols within the current file, finding files based on open buffers, and much more

 

Git

Here are some must-have plugins to enable git integration in Neovim.

  • vim-fugitive: the de facto plugin for git integration
  • git-gutter: adds contextual git info at the line level in the gutter (left margin of the editor)
  • snacks/lazygit: This plugin is part of the snacks collection of plugins mentioned above. It
    provides Neovim integration to a tool called lazygit which is an awesome terminal UI
    program that makes working with git repositories very simple. I usually end up using
    lazygit over vim-fugitive. Note, you will need to install lazygit separately.

 

Tips

This section contains some tips and advice that I have acquired over the years.

 

Mappings

Because vim is a modal editor, as we discussed above, there are a lot of options when it comes

to key mapping; you don't always need to use modifiers like control or alt. A large number of the

mappings you create will likely be of the form <leader> followed by some character. For

example, I use <leader>f to open telescope (see plugins above) for find-in-files. The default

leader key in vim is backslash which is not the easiest key to press. It is pretty common to

change this to something more convenient like comma.

 

If you need to set up a lot of mappings, you can consider setting up a bunch of them in the form

of <space> followed by some character. This is also a common practice.

 

Mappings are, of course, great, but I suggest not being too quick to create them. The more

mappings you create, the harder it is to remember them. Also, you end up using all the good

mappings and run out of options when you need to add more. For a lot of things I like to use the

default binding or run the command directly. For example, I sometimes want to open the current

buffer in a new vertical split but I have never felt the need to create a custom mapping to do it.

Running the command directly with :vs<CR> has not been a problem. However, if opening a

vertical split is something you do all of the time in your normal workflow then make a mapping

for it.

 

Another widely used key by vim users is the ESC key. This is the key to get you back into

normal mode from insert mode, so you can imagine how often you would use it. Many users

also feel that the ESC key is not easy enough to press for as often as you need to. A common

alternative is to map jk and kj to ESC. This essentially allows you to mash j and k at the

same time to trigger the ESC key and return to normal mode. Another option is to alter the key map of your keyboard so 

that the caps lock key is mapped to the ESC key. This is the option I use, but it does require being able to configure your

keyboard to change the key mapping.

 

Macros

Get good at macros. With macros you start a recording which logs all of your key strokes to a

register, then, when you are done performing key strokes, stop the recording. At this point you

now have a macro that you can run over and over again. It is amazing how powerful this can

be. You will definitely impress your pairing partner if you master this technique.

 

Relative line numbers

Turn on relative line numbers (set rnu). When you turn this on, the line numbers in the gutter

are relative to the cursor’s current position. If you also set regular line numbering (set nu), the

cursor's current line will display the actual line number within the file. This looks a little strange,

but it makes it much easier to calculate jump distances. For example if I want to jump

backwards to a line that is 5 lines up I can issue the command 5k. Try it for a while, I'm sure

you will like it.

 

Upgrade often

Stay up to date with the latest Neovim version and your plugin versions. If you do this often, it

makes it easier to isolate any problems that might arise from a new version. Using plugins like

nvim-treesitter and mason as well as a good plugin manager like lazy.nvim make upgrading

plugins and tools simple.

 

Keep learning

Neovim has so many features to offer. Keep reading the docs and experimenting with new

things like using marks, the global command, using tabs and splits effectively, diffing, folds, the

quickfix list, and much much more.

 

Pair Neovim with some additional tools

Since Neovim is a program that runs in the terminal, you will be spending a lot of time there. It's

worth upgrading your experience with a good terminal emulator. I have been using kitty for a

while now and I like it but, there are other good options as well. I am actually going to try out a

newer one called ghostty and see how I like that.

 

Another tool I've grown to love that pairs very well with development in a terminal with Neovim

is tmux. Tmux is a terminal multiplexer. I use it to create and manage terminal sessions,

windows, and panes. For example, within a single terminal instance, I can set up a handcrafted

workspace that contains all the windows and split panes I need for my development needs.

 

Navigating around all of the windows and panes in tmux is done with key mappings, so it lines

up well with the same mentality as in vim which is to increase productivity by allowing the user

to keep their hands on the keyboard as much as possible.

 

Actually, there are a lot of really neat terminal UI style programs out there that can enhance

your terminal experience. For example, as I mentioned before, lazygit is a very good terminal UI

for interacting with git. I encourage you to look for these things and really embrace using the

terminal more.

 

Closing

I sometimes get asked why I use Neovim, tmux, and similar tools in the terminal instead of a

"real" IDE. It's actually a hard question for me to answer because, comparing feature by feature,

my Neovim setup probably comes up short. I think it comes down to an intangible quality, a

feeling that you just can't appreciate until you try it for yourself. I hope you will.

John Quagliata

Other posts you might be interested in