blog/content/software/nvim-configure.md

328 lines
17 KiB
Markdown
Raw Normal View History

2023-12-25 16:46:56 +00:00
---
Title: Setup Neovim with kickstart.nvim
2023-12-25 17:14:41 +00:00
Date: 2023-12-25 17:15
2023-12-25 16:46:56 +00:00
Lang: en
Author: Fabrice
Category: software
Tags: vim, neovim, setup
Slug: nvim-kickstart
table-of-contents: true
Header_Cover: ../images/covers/antennae.jpg
Summary: How to create a sane Neovim configuration with kickstart.nvim as a
starting point.
---
# Introduction
## How I managed my configuration
When I started using Vim, I started editing my `.vimrc` bit by bit and
incrementally before it starts getting too big for me to find anything inside
it and not using even half of the plugins I installed. That goes without saying,
there were quite a bit on conflicting keymaps as well as I'm using
[bépo](http://bepo.fr/) as my keyboard layout with [partial remaps
(fr)](https://cdn.bepo.fr/Vim-bepo-066.png).
Obviously, it slowly became quite a mess. To address this issue, I
decided to reorganise my `$HOME/.config/vim` directory using the [vim directory
structure](www.panozzaj.com/blog/2011/09/09/vim-directory-structure/) and did
some cleanup at this point of time. I think it was also around this period that
I discovered that Vim8 added a native package manager that I started to use.
Thus, at this point, I started organising my configuration with semantic files,
such as `$VIMHOME/plugin/spelling.vim` to manage my spelling configuration for
instance. This approach makes debugging easier, and also checking custom
keyboard shortcuts easier, as I just have to check
`$VIMHOME/plugin/omnicomplete.vim` for instance to know which shortcuts I set up
when I'm still getting the habits of using them.
At some point of time, I moved to Neovim, and I simply moved my configuration
from Vim to Neovim and continue on adding more and more plugins on top of each
other depending on my hype, especially because the world of Neovim plugins
opened up to me. Needless to say that less than half of these plugins were put
into good use. Which leads to my first configuration big cleanup.
Six months ago, I wiped my frankenconfig, and started back from scratch in
[lua](https://lua.org/about.html), with the same structural approach as
previously, but now wondering if the plugin would be useful or not. Since my
first time using Vim, there were some big changes in the vim ecosystem,
especially in language management with
[tree-sitter](https://tree-sitter.github.io/tree-sitter/) and
[lsp](https://en.wikipedia.org/wiki/Language_Server_Protocol). These two bring
into the environment a unified way to manage languages without having to depend
on language-specific plugins, henceforth I didn't need specific plugins to have
nice syntax coloration for obscure languages anymore, or get frustrated with
[omnicomplete](https://vim.fandom.com/wiki/Omni_completion) which decided not to
work for some languages… While it's not an absolute rule (for instance, I'm
using [vimtex]({filename}./nvim-latex.md) for latex, which includes a more
accurate syntax coloring than tree-sitter). I also moved from the native vim way
of managing plugins to use [`Lazy`](https://github.com/folke/lazy.nvim) as a
proper plugin manager, which helped me synchronize my configuration between my
different computers. It was working nice and well, with some weird bugs (see
below) on first install, but as it was punctual… I just ignored it.
```plain
E5113: Error while calling lua chunk:
$VIMHOME/nvim/init.lua:13: E21: Cannot make changes, 'modifiable' is off
```
However, I was unhappy with some of my configurations, and if I managed to have
something functional, there were many details that annoy me that stemmed for
some configuration I wrote some times ago and of course didn't document. This
leads us to today, where I just decided to use
[`kickstart.nvim`](https://github.com/nvim-lua/kickstart.nvim), which is a
well-documented vim starting configuration (it's not a distribution, it still
requires your input to obtain something that fits your needs), which was exactly
what I needed to start anew… but not fully from scratch.
## The migration
To move my configuration from `kickstart.nvim`, I wanted to get the best of both
world. For instance, I didn't want to have an
[`init.lua`](https://github.com/nvim-lua/kickstart.nvim/blob/master/init.lua)
that is over 600 lines long. I thus decided to split it into short files that
manages a specific part of the configuration: completion, lsps, treesitter,
mappings after reading the different configuration default from nvim-kickstart
and changing what I disliked. To do that, I started with using the
[`NVIM_APP`](https://practical.li/neovim/configuration/) environment option in
order to make the move in a non-destructive way. After installing the bare
minimum to make it usable for me (as a bépo user), I exported the `NVIM_APP`
variable to start using my configuration to help me debug it on the fly.
I also decided to write this blog post to remember the process and maybe helped
some people who want to configure their text editor.
Note that in the following, we will assume that the reader is already familiar
with Neovim and lua.
# Configuring Neovim
My (in use) configuration for Neovim is available [here](https://git.epheme.re/fmouhart/nvim-config-kickstart).
I started using git from the start in order to remember what I did by using its
[history](https://git.epheme.re/fmouhart/nvim-config-kickstart/commits/branch/master).
As it's not the easier thing to read however, here follows my rationals, and
thought during this process in a chronological order.
## kickstart.nvim
`kickstart.nvim` is a starting Neovim configuration file which was created by
[TJ DeVries](https://github.com/tjdevries), a core developer of Neovim, author
of [telescope.nvim](https://github.com/nvim-lua/telescope.nvim) and content
creator about Neovim. You can see a quick presentation on his YouTube channel
[[here]](https://www.youtube.com/watch?v=stqUbv-5u2s).
To summarise, it is a starting configuration including a minimal set of plugins
that helps to have a modern editor, that has a working and customizable LSP
configuration with [Mason](https://github.com/williamboman/mason.nvim) to help
install LSP servers, git helpers, completion, telescope, and a choice of
shortcuts that are quite natural to learn (unlike what I used previously because
I was simply adding shortcuts one after another without thinking of the
compatibility between them).
Note that it is made for educational purpose, and thus is not modularised as is
(hence the single self-contained `init.lua` file). Which leads us to our first
step after simply pasting the content of `init.lua` into the `$VIMHOME/init.lua`
file.
## Modular configuration
When in doubt about some shortcuts, I'm under the habit of going to read the
corresponding configuration file in my `$VIMHOME/plugin` directory.
`kickstart.nvim` includes `which-key`, that is a plugin that pops a helper when
waiting for a command as shown hereunder.
[![which-key plugin
illustration](../images/nvim-which-keys.png)](../images/nvim-which-keys.png)
Thanks to that, I start getting rid of this habit. However, having a modular
configuration helps debugging it. Usually, when an error spawns, the filename
and location of what has triggered it appears in the stack trace, and it's
easier to search in a short file than a thousand-line long one.
After a first read of the configuration file, I decided to split it into smaller
files. Note that if you want to start directly from there a project that does
exactly that exists:
* [kickstart-modular.nvim](https://github.com/dam9000/kickstart-modular.nvim)
However, I find it easier for educational purpose to have everything in one
place to linearly read it first.
The process was quite simple, as the file was already divided logically into
components that make sense, I just had to take the content of those sections and
move them into the `$VIMHOME/lua` folder before including them in `init.lua`. I
hesitated to continue using the `$VIMHOME/plugin` directory for that, but I then
realised that having it inside init.lua allows having a structure that allows
using `init.lua` as an index, and I can start
[jumping](https://vimhelp.org/motion.txt.html) from there to access my
specific configurations.
To illustrate it, let's take the example of completion. In `kickstart.nvim`,
there is a section called "Configure nvim-cmp", that deleted and pasted into a
file `$VIMHOME/lua/complete.lua` before adding the line `require('complete')` to
load it. You can see the result in this
[commit](https://git.epheme.re/fmouhart/nvim-config-kickstart/commit/7ce423fade9d6877b2e9174dd9b9dea36254ac19).
## Survival
Now that it's done, I need my basic keymaps for using Vim/Neovim in bépo. I
added the file `$VIMHOME/lua/bepo.lua` and simply load it with a line
`require('bepo')` in my `$VIMHOME/init.lua` file.
I also merged my personal remap inside the `$VIMHOME/lua/mappings.lua` file
which already contained the ones imported from `kickstart.nvim` from the
previous step. These mappings are convenient ones such as the following one to
easily open folds to a given level.
```lua
local keymap = vim.keymap.set
-- z0…z9 to open folds to a certain level
for i=0,9 do
keymap('n', 'z' .. i , ':set fdl=' .. i .. '<CR>', {noremap = true, silent = false})
end
```
I also merged and cleaned redundant general options in the
`$VIMHOME/lua/general-options.lua` file. For instance to ignore folded content
when jumping between paragraphs for instance, there is the following line in the
aforementioned file:
```lua
-- folds
vim.g.ip_skipfold=true
```
Once all of that is done, at this point of time, I started moving to use the
configuration by exporting `NVIM_APP=new_nvim` inside my `.zshrc`. The idea is
that now I bootstrapped my Neovim config to proficiently edit the configuration,
which in lua also uses LSP and many of `kickstart.nvim` features. During this
process I notice what I liked and disliked to know how to edit the configuration
while editing the configuration.
## Importing my former configuration
After having the minimal setup top edit a configuration, I now need to make
things work for other things as well.
That is dependent of your workflow. For reference, I personally use Neovim to:
* Write text in [markdown](https://daringfireball.net/projects/markdown/) (such as what I'm currently doing)
for different purposes;
* blog post, emails or more generally text blocks that will be exported in
html.
* Read text written in Markdown;
* Try to organise my life using [neorg](https://github.com/nvim-neorg/neorg);
* [LaTeX](https://en.wikipedia.org/wiki/LaTeX) documents and slideshows;
* Write code in a variety of languages.
To do that I went to my previous configuration (which fortunately was already
using [`Lazy`](https://github.com/folke/lazy.nvim) as a plugin manager). To do
that, I picked my specific plugins, for instance `Neorg`, to import the
configuration. For the example of `Neorg` it has multiple steps as I had a
`$VIMHOME/plugin/neorg.lua` that contained my general configuration and
`$VIMHOME/ftplugin/norg.lua` which has specific configuration when editing a
note in `Neorg`.
After asking `Lazy` to install `Neorg`, I first imported the general
configuration from my previous `plugin` folder in my new `lua` folder, as
depicted by this
[commit](https://git.epheme.re/fmouhart/nvim-config-kickstart/commit/0e8587b461b67082c1e34ef9cb07180ccfee9f8b).
After wondering if I should create a `ftplugin` directory, I finally decided to
move to autocommands to manage different filetypes. The reason behind that was
that I had a limited amount of lines in total in my former `ftplugin` directory,
and the subdivision with `augroup` and `autocmd` in Vim makes it reasonably
readable. Which brought me to this
[commit](https://git.epheme.re/fmouhart/nvim-config-kickstart/commit/c506a7ea7868ba80dc053a59cbb66c5efa666e2c).
Then some sanity and cleanup have been made. For example, adding a description
field to my key maps so that `which-key` nicely prints them. See this
[commit](https://git.epheme.re/fmouhart/nvim-config-kickstart/commit/689bb2024d97fdc9e5e656517f00e446e95ae198).
Now, rinse and repeat for each plugin/specific configuration set: `vimtex`,
`vim-pandoc-syntax` (which I mainly use for the
[concealer](https://vimhelp.org/syntax.txt.html#conceal)), spelling
configuration, etc.
All the while keeping a critical eye on what I'm moving. For instance, I have a
mapping on the following command to fix typo on a misspelled word under the
cursor when writing text: <code>mz[s1z=\`z</code>. However, the key was bound at
anytime, even when spelling was not enabled. To fix that, we changed the way the
binding was called: instead of being called everytime, we embedded it inside an
[`autocmd`](https://vimhelp.org/autocmd.txt.html#autocommands) which [triggers
when the option](https://vimhelp.org/autocmd.txt.html#OptionSet) `spell` is set.
To see the resulting configuration, see these two files:
[`autocommands.lua`](https://git.epheme.re/fmouhart/nvim-config-kickstart/src/commit/d0afa1066cabab3d2b0aa7e2e84a267ce0532c61/lua/autocommands.lua#L32-L37)
for the autocommand setting, and
[`spelling.lua`](https://git.epheme.re/fmouhart/nvim-config-kickstart/src/commit/d0afa1066cabab3d2b0aa7e2e84a267ce0532c61/lua/spelling.lua)
for the utils module.
Just for the record, this is what it does:
1. Store the current cursor location: `mz` [sets a
mark](https://vimhelp.org/motion.txt.html#mark) z on current position;
2. [Go to the previous spelling error](https://vimhelp.org/spell.txt.html#%5Bs): `[s`;
3. [Pick the first spelling suggestion](https://vimhelp.org/spell.txt.html#z%3D): `1z=`;
4. Go back to the stored location: <code>\`z</code> [jumps to
mark](https://vimhelp.org/motion.txt.html#%60) z at the right column.
## Adjusting the configuration
While testing the default behaviour of `kickstart.nvim`, which changes quite a
few things for me, I realised that some of them were quite smart, such as
<Space> as the leader key, which was on `,` before because of its accessibility
in bépo, disabling quite a [useful motion
binding](https://vimhelp.org/motion.txt.html#%2C), some are more personal
tastes, such as the default register to be the system one or not.
I thus tried some of these options and decided while editing the configuration
and writing this blog post which one where working nicely for me (with the help
of `which-key` to help me during this whole process), and which one were not
quite working (`unnamedplus` as default clipboard, I really use both separately,
and I don't want to have my system clipboard polluted)
Moreover, `:healthcheck which-keys` was really helpful to debug some colliding
key bindings, especially because of bépo, which has been incrementally fixed
while editing the configuration. I already wrote a blog post about how I handle
those in [vimtex]({filename}./nvim-latex.md).
My former configuration also featured LSP, but Mason was not used, which made me
install my LSP server from my system package manager. However, I still prefer
using the system one for some languages that features some changes between
versions, which I [also
configured](https://git.epheme.re/fmouhart/nvim-config-kickstart/src/commit/d0afa1066cabab3d2b0aa7e2e84a267ce0532c61/lua/lsp.lua#L120-L149)
in the `$VIMHOME/lua/lsp-configure.lua` file.
# Final thoughts
To conclude, I would like to say thanks to the French
[tuppervim](https://tuppervim.org) community, which regularly organises meetings
where we can show our latest configuration file, or just exchange nice tips. I
discovered both [TJ DeVries](https://www.youtube.com/c/TJDeVries) and
[`kickstart.nvim`](https://github.com/nvim-lua/kickstart.nvim) there.
I still have to get rid of some habits (such as the comma as a leader key) and
get used to it, but I'm happy with the change so far, beside knowing exactly
what is in my configuration, it also helped me fix some weird key conflicts
while editing markdown, making writing this blog post quite pleasant.
While trying the Git-related key bindings utilities bundled with
`kickstart.nvim`, while being quite minimal, it still filled my needs
(especially adding a hunk from visual selection, which is helpful to split
commits into sub-blocks when `git add -p` would have been quite tedious to use).
The [status bar](https://github.com/nvim-lualine/lualine.nvim) was also a
pleasant surprise for me. It is exactly the kind of things I find useful but a
pain to configure. I may tweak it a bit in the future, but so far it's fine as
it is.
The configuration will continue to evolve from this point, as my use of computer
and Neovim will change as well. And to finish, I think what TJ Devries said in
[this video](https://www.youtube.com/watch?v=QMVIJhC9Veg) about text editor is
quite on point: you don't have to spend time in your configuration if it is not
fun for you, just take something that works for you. I actually took the time to
do it because I find it interesting and fun 🙂
If you also find it fun, and want to try it, I strongly encourage you to take a
cup of hot cocoa, put on some relaxing music, and just dive head first!