Your first Neovim config
I want to show you how to build a simple configuration file for Vim and Neovim. So here I will teach you the basic commands and functions that you can use to customize Neovim.
I will explain enough so you understand what is happening, but I will not go in depth on every single detail and possibility. At the end there will be a snippet of code you could use as the base for your first configuration.
The config directory
By default Neovim's main configuration file needs to be in a dedicated directory. The path to this directory can change depending on the operating system or environments variables, but these are the usual places:
~/.config/nvim/ (Unix and OSX)
~/AppData/Local/nvim/ (Windows)
You must create this directory yourself.
To know the exact path of Neovim's config directory execute this command on the terminal.
nvim --headless -c 'echo stdpath("config") . "\n"' -c 'quit'
The init file
Here decisions need to be made. The configuration file for Neovim can be written in vimscript or lua.
I will use vimscript because I want to show a configuration that works in Vim and Neovim. But do keep in mind Vim and Neovim have different names and location for the configuration file.
In Neovim the configuration file should be called init.vim
. And this would be the (usual) path.
~/.config/nvim/init.vim (Unix and OSX)
~/AppData/Local/nvim/init.vim (Windows)
Of course, if we were to choose lua the file wouldn't be init.vim
, it would be init.lua
.
Set your settings
In vimscript we use the :set command to configure Vim options. These are the settings I find useful.
set number
set norelativenumber
set signcolumn=yes
set tabstop=2
set shiftwidth=2
set expandtab
set nowrap
set nohlsearch
set smartcase
set ignorecase
set mouse=nvi
set termguicolors
set cursorline
set noswapfile
set completeopt=menu,menuone,noinsert
Notice some of these start with the prefix no
. This works for a specific type called boolean
. Boolean options can only have two values, it's either enabled or disabled. Consider this.
set relativenumber
set norelativenumber
relativenumber
is the name of the option itself. But if it has the prefix no
then it means we want to disable it.
To know more details about an option you can read the help page. Write the command :help
and wrap the name of the option in single quotes. For example:
:help 'relativenumber'
Changing the color scheme
Interestingly enough there isn't an option to change the theme of the editor. Instead we have a dedicated command, :colorscheme.
colorscheme habamax
Unfortunately the command colorscheme habamax
will fail on older versions of Neovim below v0.8.
If we don't want the execution of our config to be interrupted by an error we can use the :try command.
try
colorscheme habamax
endtry
Check Neovim's version
Not every package manager will have the latest Neovim available in its official repository. Installing Neovim on OSX via homebrew
can get you v0.11 or greater. But using apt install
on Ubuntu 24.04 will get you v0.9.5.
If we want to have a configuration that's backwards compatible is a good idea to check Neovim's version before using a feature that we know is only available in newer versions.
Here's an example using a new colorscheme called retrobox
.
if has('nvim-0.10')
colorscheme retrobox
endif
In this snippet we are using two features of vimscript. We have a conditional block and the has() function. In this case we check if we have Neovim v0.10, and if it's true use the retrobox
theme.
has()
can also be used to detect if we are using Vim or Neovim. We can do this.
if !has('nvim')
set hidden
set belloff=all
set autoread
set autoindent
set laststatus=2
set wildmenu
set wildoptions=pum,tagfile
syntax enable
endif
Here you can read !has('nvim')
as "we are not inside Neovim" and so the code inside the block will only execute on Vim. Note the code inside the if
block is already part of Neovim's default, there is no need to execute it (again) if we are already in Neovim.
Configure Netrw
Right now Netrw is the default file explorer in Vim and Neovim. This is implemented as a plugin written in vimscript. This means we have to use global variables to configure it.
To modify global variables we use the :let command. Here is an example.
let g:netrw_banner = 0
Here g:netrw_banner
is the name of the variable. The equal sign means this is an assignment. The thing on the right hand side of =
must be valid vimscript. Although most of the time we will use numbers or text wrapped in quotes.
To know what settings are available in Netrw read the documentation.
:help netrw-browser-settings
Now, if your configuration is written in lua then the syntax will change a little bit. In lua we must use vim.g
to modify global variables of vimscript plugins.
vim.g.netrw_banner = 0
Remember that lua is another scripting language. We can't just write valid vimscript in a lua file. In lua there are special features we can use to interact with vimscript plugins, vim.g
is just one of them.
Simple mappings
Keymaps in Vim are basically a way of automating keystrokes. Here is a good example.
xnoremap gy "+y
This command will create the keymap gy
in visual mode. So in visual mode when you press gy
it'll be the same as pressing "+y
.
"+y
is the annoying way we can copy text from Neovim to the system clipboard.
xnoremap
is part of a family of commands. These are the ones we'll be using most of the time.
nnoremap -> normal mode mapping
xnoremap -> visual mode mapping
inoremap -> insert mode mapping
Now, to execute ex-commands we can use :
. Like this.
nnoremap <C-g> :echo "Hello there"<cr>
With this pressing Ctrl + g
in normal mode will print the message Hello there
. Notice the :
before the echo
command, and also the <cr>
at the end.
But there is another way to trigger a command, that is using the special sequence <cmd>
. I like this more than :
because it'll tell you if you forget to add <cr>
at the end. Also, according to the documentation, is a little bit more flexible than :
.
The previous example can be written like this.
nnoremap <C-g> <cmd>echo "Hello there"<cr>
One more thing...
We have to talk about "the leader key." This is a special sequence people use as a prefix for their custom keymaps. If you go around in the wild you might find a keymap like this.
nnoremap <leader>w <cmd>write<cr>
This <leader>
sequence can be configured, so it can be whatever we want. Most people like to use the Space
key.
We modify the value of the leader key by assigning a value to the global variable mapleader
. This is the most common setup.
let g:mapleader = " "
A more complete example would look like this.
let g:mapleader = " "
" Exit Neovim
nnoremap <leader>q <cmd>quitall<cr>
" Save file
nnoremap <leader>w <cmd>write<cr>
We have to configure g:mapleader
before we use it. Here Space + q
would exit Neovim. Space + w
would save the current file.
First look at autocommands
Autocommands is the mechanism we use to execute code when an "event" happens.
Consider this piece of code.
autocmd filetype help nnoremap <buffer> q <cmd>close<cr>
Here we are creating an autocommand on the event filetype
. This event is triggered after Neovim figures out what type of file we are editing. In this specific example we only care about the help
filetype. So when we open help
page Neovim will execute the nnoremap
command.
Sometimes people like to group autocommands together. That way they can track better the code. For example.
augroup hello_cmds
autocmd!
autocmd filetype netrw echo "Hello from netrw"
autocmd filetype help echo "Hello from the help page"
augroup END
Here we have the hello_cmds
group. If we want to inspect all the autocommands in this group, we execute this command.
:autocmd hello_cmds
Example init.vim
" ============================================================================
" === EDITOR SETTINGS ===
" ============================================================================
set number
set norelativenumber
set signcolumn=yes
set tabstop=2
set shiftwidth=2
set expandtab
set nowrap
set nohlsearch
set smartcase
set ignorecase
set mouse=nvi
set noswapfile
set completeopt=menu,menuone,noinsert
if !has('nvim')
set hidden
set belloff=all
set autoread
set autoindent
set laststatus=2
set wildmenu
set wildoptions=pum,tagfile
syntax enable
endif
try
set termguicolors
set cursorline
colorscheme habamax
catch
set notermguicolors
set nocursorline
colorscheme default
highlight clear SignColumn
endtry
let g:netrw_banner = 0
let g:netrw_winsize = 30
let g:netrw_liststyle = 0
" ============================================================================
" === KEYMAPS ===
" ============================================================================
" Use <Space> as a leader key
let g:mapleader = " "
" Copy/paste using system clipboard
nnoremap gy "+y
xnoremap gy "+y
nnoremap gp "+p
xnoremap gp "+p
" Exit Neovim
nnoremap <leader>q <cmd>quitall<cr>
nnoremap <leader>Q <cmd>quitall!<cr>
" Save file
nnoremap <leader>w <cmd>write<cr>
" Toggle file explorer
nnoremap <expr> <leader>e &ft=='netrw' ? '<cmd>close<cr>' : '<cmd>Lexplore<cr>'
function NetrwMapping()
" Go back in history
nmap <buffer> H u
" Go up a directory
nmap <buffer> h -^
" Open file/directory
nmap <buffer> l <cr>
endfunction
augroup user_cmds
autocmd!
autocmd filetype netrw call NetrwMapping()
autocmd filetype help,man,checkhealth nnoremap <buffer> q <cmd>close<cr>
augroup END