328 lines
17 KiB
Markdown
328 lines
17 KiB
Markdown
---
|
||
Title: Setup Neovim with kickstart.nvim
|
||
Date: 2023-12-25 17:15
|
||
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!
|