Neovim Editor Configuration
Installation
Install Neovim using your package manager:
sudo pacman -S neovim
Configuration
Change to the /home/<username> directory:
cd ~
Inside ~/.config, create an nvim directory to
store the Neovim configuration files:
mkdir .config/nvim
To keep the configuration clean and easy to maintain, create the following directory structure:
~/.config/nvim |-- init.lua |-- lua | |-- options.lua | |-- mappings.lua | |-- package-manager.lua | |-- autocmds.lua | |-- plugins | | |-- colour-scheme.lua | | |-- language-servers.lua | | |-- completion.lua | |-- templates | | |-- tex-temp.tex
Using the following commands:
mkdir .config/nvim/lua mkdir .config/nvim/lua/plugins
Any files within the lua subdirectory will be available on
demand and can be loaded with the require command (this is the
Lua equivalent of the Vimscript auto-load mechanism).
Create the base configuration file in this directory (this can be either
init.vim or init.lua, however, Lua is
recommended):
nvim .config/nvim/init.lua
Leave this file blank for now.
One can force reload the init.lua file at any stage within
Neovim:
:luafile %
To check the health of Neovim (e.g. if there are any issues with the
init.lua file):
:checkhealth
Setting Options
Create the options.lua file:
nvim .config/nvim/lua/options.lua
Within this file, one can configure many of the built-in Neovim options. Setting options is very similar to Vim:
vim.optbehaves like:set.vim.opt_globalbehaves like:setglobal.vim.opt_localbehaves like:setlocal.
Some useful options to set include:
insert some options here...
Within the init.lua file, add the require function
call so that Neovim can read the options.lua file (note the
absence of a .lua extension for the file name):
require("options")
Defining Keyboard Mappings
Create the mappings.lua file:
nvim .config/nvim/lua/mappings.lua
Within this file, set desired key mappings. Some useful mappings include:
insert some options here...
For the basics on Lua mappings, see the Mappings section of the Neovim Lua guide.
Within the init.lua file, add the require function
call so that Neovim can read the mappings.lua file (note the
absence of a .lua extension for the file name):
require("mappings")
Enabling System Clipboard Functionality
By default, Neovim utilises internal registers for managing yanked (copied)
or deleted (cut) data. These registers are independent from the system
clipboard, thus, data yanked or deleted inside a Neovim instance will be
isolated to that instance unless specified otherwise. To enable the system
clipboard functionality, first has to install a command-line tool for
manipulating the system clipboard. For Wayland compositors, install
wl-clipboard:
sudo pacman -S wl-clipboard
For X compositors, install xclip:
sudo pacman -S xclip
The system clipboard is accessed through the + register in
Neovim:
- "+y<movement> to yank (copy).
- "+d<movement> to delete (cut).
- "+p<movement> to paste, or use the terminal paste command Ctrl+Shift+v.
Setting Up Templates
Create the templates directory to store file templates:
mkdir .config/nvim/lua/templates
Create a template for a specific file type, for example, for LaTeX files:
nvim .config/nvim/lua/templates/tex-temp.tex
Add the desired generic content, then save and close the file:
\documentclass[a4paper]{article}
\begin{document}
\tableofcontents
\section{Template}
This is a \LaTeX template.
\end{document}
Create the autocmds.lua file:
nvim .config/nvim/lua/autocmds.lua
Add the following Lua-based Vim API call:
local autocmd_group = vim.api.nvim_create_augroup(
"Custom auto-commands",
{clear = true})
vim.api.nvim_create_autocmd({"BufNewFile"},
{
pattern = {"*.tex"},
desc = ".tex template generation auto-command",
command = "0r ~/.config/nvim/lua/templates/tex-temp.tex",
group = autocmd_group
})
An auto-command group called "Custom auto-commands" is created
(nvim_create_augroup) to which the .tex template
generation auto-command is later assigned. See
Why Use Auto-Command Groups? for
an explanation.
The first argument of nvim_create_autocmd are the event(s) for
which to register the auto-command. In this case, the command will be run
every time the "starting to edit a non-existent file" event happens (i.e.
BufNewFile). The command to be executed is one that checks
whether the file name matches the pattern (i.e. any file that ends in
.tex), and then reads the contents of the template and inserts
it at line 0.
For more information on auto-commands, see the Autocommands section of the Lua guide.
Neovim is able to read any file from disk into the current buffer by calling the read command. For example, if one creates a file that doesn't have the .tex extension, then you can still read the contents of the template by running the following command within Neovim:
:read ~/.config/nvim/lua/templates/tex-template.tex
Package Management
To extend the functionality of Neovim easily, one must set-up a Neovim package manager. Many exist and it seems like the go-to manager changes every few years. Currently, lazy.nvim appears to be the latest and greatest, and is therefore preferred, however, Packer is a close second.
Create the package-manager.lua file:
nvim .config/nvim/lua/package-manager.lua
Add the following code to this file to allow lazy.nvim to bootstrap itself
(i.e. the first time it runs this code, it will download the repository to
~/.local/share/nvim/lazy):
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({
"git",
"clone",
"--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable", -- latest stable release
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
local plugins = {}
local opts = {}
require(lazy).setup(plugins, opts)
Edit the init.lua file and add the
package-manager.lua file as a requirement:
require("package-manager")
Restart Neovim: there will be a slight delay while it downloads the lazy.nvim repository and sets everything up.
Changing the Theme
Find an aesthetic Neovim theme. The Nightfox.nvim package provides a few colour schemes—one of which should suit.
Edit the package-manager.lua file and add the following lines
to the plugins variable:
local plugins = {
{ -- Theme
"EdenEast/nightfox.nvim",
config = function()
vim.cmd "colorscheme terafox"
end
}
}
In Lua, one can wrap functions within other functions. From the lazy.nvim
documentation, lazy.nvim runs the config function whenever a
plugin loads (in this case nightfox.nvim). Knowing this one can redefine
config to wrap other functions to be executed upon loading the plugin.
Normally to set-up the Terafox theme, one would call the Lua function
vim.cmd("colorscheme terafox") from either command mode inside
Neovim, or by placing the functional call somewhere in
init.lua or another file that gets executed. When wrapping
functions in Lua, you pass the function's name followed by the parameters,
without any brackets. If the above lines were added correctly, then when
lazy.nvim loads the nightfox.nvim plugin, it will automatically call the
config function, in turn executing the Vim command
colorscheme with the argument terafox,
subsequently setting the theme.
Setting up the Language Server Protocol
Neovim contains a built-in Language Server Protocol (LSP) client and the nvim-lspconfig plug-in provides common configurations for it. Language servers that can be installed natively using the Arch Linux package manager can be found here.
Install the
LSP configurations
and Mason server
manager by editing the package-manager.lua file and add the
following lines to the plugins variable:
local plugins = {
{ -- LSP
"neovim/nvim-lspconfig",
dependencies = {
"williamboman/mason.nvim",
"williamboman/mason-lspconfig.nvim"
}
}
}
Customising the Status Line
Improve the aesthetics and functionality of the status line (bar) displayed at the bottom of the Neovim window to include the file name, encoding and type, as well as how far you are through the file in both percentage form as well as line number and character (column) number.
Edit the package-manager.lua file and add the following to the
plugins variable:
local plugins = {
{ -- Status Line
"nvim-lualine/lualine.nvim",
opts = {
options = {
icons_enabled = false,
component_separators = "|",
section_separators = ""
},
sections = {
lualine_x = {"encoding", "filetype"}
}
}
}
}
Setting Up Snippets
Setting up snippets requires both a completion engine and a snippet engine. The former is provided by nvim-cmp, and the latter by LuaSnip (along with some other dependencies).
Install the necessary package by editing the editing the
package-manager.lua file and adding the following lines to the
plugins variable:
local plugins = {
{ -- Auto-completion and snippets
"hrsh7th/nvim-cmp",
dependencies = {
"hrsh7th/cmp-nvim-lsp",
"L3MON4D3/LuaSnip",
"saadparwaiz1/cmp_luasnip" -- Snippets engine
}
}
}
Create the snippets directory to store snippets:
mkdir .config/nvim/lua/snippets
Create a snippet file for a particular file type, for example, HTML files:
nvim .config/nvim/lua/snippets/html.lua
Add the desired snippets inside this file. Below is a basic example of a
snippet that automatically expands the HTML <p> paragraph
tag:
return {
s( -- paragraph
{
trig="<p>",
dscr="Automatically expand '<p>' tag to a HTML paragraph",
snippetType="autosnippet"
},
fmt("<p>{}</p>", { i(1) })
),
}
See Elijan J. Mastnak's guide on LuaSnip for LaTeX workflows for a detailed explanation on how to use LuaSnip snippets. That guide, in combination with the documentation available on the LuaSnip GitHub repository, as well as the introductory and advanced tutorials by Timothy J. DeVries, should provide adequate coverage of technical capability of LuaSnip.
Edit the package-manager.lua file and configure the completion
and snippet engines.
Automatically Compiling LaTeX Files on Save
Add the following lines to the autocmds.lua file:
local autocmd_group = vim.api.nvim_create_augroup(
"Custom auto-commands",
{clear = true})
vim.api.nvim_create_autocmd({"BufWritePost"},
{
pattern = {"*.tex"},
desc = "Auto-compile .tex files on save",
callback = function()
local fileName = vim.api.nvim_buf_get_name(0)
local fileDir = string.match(fileName, ".*/")
local cwDir = vim.fn.getcwd()
local returnKey =
vim.api.nvim_replace_termcodes(
'<cr>', true, false, true)
vim.api.nvim_set_current_dir(fileDir)
vim.cmd(":!pdflatex " .. fileName)
vim.cmd(":!biber " .. string.sub(fileName, 1, -5))
vim.cmd(":!pdflatex " .. fileName)
vim.cmd(":!pdflatex " .. fileName)
vim.api.nvim_set_current_dir(cwDir)
vim.api.nvim_feedkeys(returnKey, 'm', true)
end,
group = autocmd_group
})
This code block runs the necessary LaTeX commands to compile a
.tex file automatically when it is saved.
Specifically, it creates a Neovim auto-command
(nvim_create_autocmd) that executes after the buffer has been
written to a file ({"BufWritePost"}). Writing to a file usually
occurs when :w or :x commands are entered, however
:x will only initiate a write if changes to the buffer have been
made since opening the file. The auto-command only executes for
.tex files (pattern = {"*.tex"}), if such a file
type is written to file, then the callback function is executed
which:
-
gets the absolute path and name (
nvim_buf_get_name) of the current buffer (0), -
extracts the absolute path of the file to compile
(
string.match), - gets the current working directory (
getcwd), -
changes the directory (
nvim_set_current_dir) to that of the current file, -
executes the shell commands to compile a LaTeX document using the Biber
back-end for bibliography management (note that the "
.tex" extension is stripped before running thebibercommand, -
changes back to the previous working directory
(
nvim_set_current_dir), -
presses the carriage return key (Enter) to return to the
previous window (
nvim_feedkeys).
Shortcut to Preview LaTeX PDFs via Zathura
Add the following lines to the mappings.lua file:
previewLaTeXPDF = function()
local fileName = vim.api.nvim_buf_get_name(0)
if string.find(fileName, ".tex", -4) then
local pdfName = string.gsub(fileName, ".tex", ".pdf")
vim.fn.jobstart("zathura " .. pdfName)
else
print(".tex extension not found for file: " .. fileName)
end
end
vim.keymap.set({'n'}, '<leader>p', '', { desc = "Preview LaTeX PDF", callback = previewLaTeXPDF })
This code block defines a function called previewLaTeXPDF that
gets the absolute path and name (nvim_buf_get_name) of the
current buffer (0), and then checks if the last four characters
of it are equal to ".tex" (string.find). If the
.tex extension is found, an asynchronous job is started in the
background (jobstart) to launch
Zathura with the path and
name retrieved prior, else, a relevant error message is printed. The
previewLaTeXPDF function is then mapped to the
<leader>p sequence (vim.keymap.set).
Why Use Auto-Command Groups?
In most situations, auto-commands should be assigned to a group that clears
upon resourcing files within Neovim (i.e. whenever the
:so command is executed). This is done to prevent an auto-command
being loaded repeatedly every time a file is resourced which may lead to
slow-downs or unexpected behaviour. Groups are created using the
nvim_create_augroup function which expects the first argument
to be a string for the name of the group, and the second argument a table
with the clear key set accordingly. Documentation for the
autocmd API in general can be found
here (which
includes the nvim_create_augroup function among others). For
more general information on auto-commands, see the
Groups section
of the autocmd user documentation.