
Il y a quelques temps après avoir vu un post reddit d’une configuration pour neovim sans aucun plugin, uniquement avec les fonctionnalités de base de neovim j’ai tenté de la reprendre pour essayer. C’était interessant mais un peu trop compliqué pour moi de l’utiliser, le confort des plugins me manquait trop.
Puis quelques mois plus tard j’ai voulu refaire ma configuration dans l’optique d’alléger ma configuration maintenant que neovim gere plus de features (évidemment toute la gestion du lsp étant la chose la plus évidente).
Je reste tout de même avec 17 plugins installés donc je suis assez loin d’une configuration OOTB à la helix.
Plugins
Pour la gestion des plugins ma configuration neovim n’utilise pas le populaire gestionnaire de plugins lazy.vim mais directement celui de neovim.
Pour ma config j’ai voulu aussi tenter d’utiliser des fonctionnalités de neovim un peu moins mises en avant, comme la lecture automatique des fichiers mis dans le dossier plugin dans sa config neovim (~/.config/nvim/plugin/*.lua).
Avec un ./plugin/foo.lua contenant :
vim.print("foobarbaz")
en lançant nvim on aura directement foobarbaz affiché dans vim.
En utilisant cette feature de neovim on peut se passer d’avoir un init.lua qui require tous les fichiers de configuration nécessaire.
À savoir que les fichiers contenus dans /plugin sont lus dans l’ordre alphabétique de leur nom. Pour ma part je souhaite que le fichier qui gère l’installation des plugins soit le premier lu, pour que les autres qui vont gérer des choses liées au lsp aient déjà les plugins chargés.
Pour cela je crée un fichier +plugin.lua, avec ce + on s’assure que ce fichier sera lu en premier.
-- ./plugin/+plugin.lua
Maintenant pour l’installation des plugins, comme écrit plus haut j’utilise vim.pack pour les installer, mais je souhaitais tout de même garder la feature de lazy loading très intéressante de lazy. Et heureusement il existe justement des plugins spécialement faits pour cela :
Pour ma part j’utilise lze, je ne sais absolument pas si lz.ne est mieux.
Son utilisation est simple et similaire à l’api de lazy:
-- ./plugin/+plugin.lua
require('lze').load({
-- ici le plugin nvim-tree sera chargé uniquement après avoir exécuté l'un des deux raccourcis via la fonction after
{
"nvim-tree.lua" --
keys = {
{ "<leader>bo", ":NvimTreeFindFileToggle<cr>", silent = true },
{ "<leader>bf", ":NvimTreeFindFile<cr>", silent = true },
},
after = function()
require("nvim-tree").setup({ view = { side = "right" } })
end,
},
-- même principe, le plugin sera chargé dès que l'événement vim est exécuté
{
"nvim-autopairs",
event = "InsertEnter",
after = function()
require("nvim-autopairs").setup()
end,
},
-- on charge ce plugin quand le colorscheme en question est chargé
{
"tokyonight.nvim",
colorscheme = "tokyonight-night",
after = function()
require("tokyonight").setup()
end,
},
-- pour certains plugins on souhaite les charger directement sans lazy load, il suffit de rajouter le `lazy = false`
{
"mason.nvim",
lazy = false,
after = function()
require("mason").setup()
end,
},
})
Pour lazy load j’utilise uniquement les attributs keys et event (et un colorscheme), lze a plusieurs options liées au lazyload et cela est expliqué dans le README.
Si on revient à la gestion des plugins via neovim il faut pouvoir les télécharger mais ne pas les charger dans l’éditeur, ou plutôt il faut uniquement charger lze:
-- ./plugin/+plugin.lua
vim.pack.add({
"https://github.com/BirdeeHub/lze",
}, { load = true }) -- load = true doit être spécifié si on charge les plugins depuis /plugin
vim.pack.add({
"https://github.com/nvim-tree/nvim-tree.lua",
"https://github.com/folke/tokyonight.nvim",
"https://github.com/mason-org/mason.nvim",
}, { load = function() end, confirm = true })
require('lze').load({
... -- comme plus haut
})
Pour les plugins c’est tout, je lance peut-être 1 fois par jour :lua vim.pack.update(), je n’ai pour le moment eu aucun problème lié à cette gestion des plugins.
LSP
Pour le lsp j’utilise:
- mason.nvim pour installer les language servers
- conform pour gérer le formatage des fichiers
Pas de nvim-lspconfig, mais j’utilise les configurations des language servers venant de ce repo
Pour la partie configuration en lua:
-- ./plugin/+plugins.lua
require("lze").load({
{
"mason.nvim",
lazy = false,
after = function()
require("mason").setup()
end,
},
{
"conform.nvim",
lazy = false,
after = function()
local get_js_formatter = function(bufnr)
if require("conform").get_formatter_info("biome", bufnr).available then
return { "biome", lsp_format = "never", stop_after_first = true }
end
return {}
end
require("conform").setup({
notify_on_error = false,
format_on_save = function(bufnr)
local disable_filetypes = { c = true, cpp = true }
return {
timeout_ms = 2000,
lsp_fallback = not disable_filetypes[vim.bo[bufnr].filetype],
}
end,
formatters_by_ft = {
lua = { "stylua" },
typescript = get_js_formatter,
typescriptreact = get_js_formatter,
javascript = get_js_formatter,
javascriptreact = get_js_formatter,
c = { "clang_format" },
},
clang_format = {
prepend_args = { "--style=file", "--fallback-style=LLVM" },
},
})
end,
},
Puis pour activer les language servers on peut directement vim.lsp.enable:
-- ./plugin/lsp.lua
vim.lsp.enable({
"astro",
"lua_ls",
...
})
Neovim va chercher dans le dossier ~/.config/nvim/lsp pour les configurations des language servers avec le nom donné dans lsp.enable.
Dans mon exemple les fichiers astro.lua et lua_ls.lua sont dans ce dossier.
On peut alors les nommer comme on veut, astro_legacy_123.lua par exemple s’il existait un vieux lsp pour astro, puis vim.lsp.enable({ "astro_legacy_123.lua" })
Puis pour le contenu des fichiers je prends exemple sur ceux du repo de nvim-lspconfig. Par exemple celui d’astro.
Je pense que ma façon de faire n’est vraiment pas bonne et ça serait mieux de simplement utiliser le plugin nvim-lspconfig pour avoir toutes les configs des différents lsp dispos directement. Dans mon cas quand j’essaie un nouveau langage ou technos qui a un lsp, je dois aller sur le repo de lspconfig, chercher dans le dossier lsp la config du langage et la c/c chez moi. Et dans un même temps c’est quelque chose que je fais mega rarement donc ce n’est pas si gênant.
Enfin pour configurer mes keymaps ou d’autres configs liés au lsp j’utilise une autocommand avec l’event LspAttach
-- ./plugin/autocmd.lua
vim.api.nvim_create_autocmd("LspAttach", {
callback = function(event)
vim.keymap.set("n", "gd", vim.lsp.buf.definition)
local client = vim.lsp.get_client_by_id(event.data.client_id)
if client and client:supports_method("textDocument/documentHighlight", event.buf) then
local highlight_augroup = vim.api.nvim_create_augroup("HighlightCursorHold", { clear = false })
vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, {
group = highlight_augroup,
buffer = event.buf,
callback = vim.lsp.buf.document_highlight,
})
vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, {
group = highlight_augroup,
buffer = event.buf,
callback = vim.lsp.buf.clear_references,
})
vim.api.nvim_create_autocmd("LspDetach", {
group = vim.api.nvim_create_augroup("LspDetach", { clear = true }),
callback = function(event2)
vim.lsp.buf.clear_references()
vim.api.nvim_clear_autocmds({ group = "HighlightCursorHold", buffer = event2.buf })
end,
})
end
end,
group = vim.api.nvim_create_augroup("LspAttach", { clear = true }),
})