Neovim
Neovim est un fork de Vim créé en 2014 pour moderniser sa base de code et son extensibilité, tout en restant compatible avec l'essentiel de Vimscript et des commandes historiques de Vim. Il ajoute un client LSP natif, le moteur de parsing Tree-sitter, une API scriptable en Lua, un terminal intégré et une architecture client-serveur. Ce guide couvre l'installation, la configuration en Lua et la mise en place d'un environnement complet avec gestion de plugins, LSP, autocomplétion et recherche floue. Pour la liste des commandes/raccourcis, voir la cheat sheet Neovim et la cheat sheet Vim. Source : neovim.io.
Installation
Debian / Ubuntu
# Dépôt officiel (PPA) pour avoir une version récente
sudo add-apt-repository ppa:neovim-ppa/unstable
sudo apt update
sudo apt install neovim
# Alternative : AppImage (marche sur toute distro sans dépôt)
curl -LO https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.appimage
chmod u+x nvim-linux-x86_64.appimage
sudo mv nvim-linux-x86_64.appimage /usr/local/bin/nvimFedora / RHEL / Alma
sudo dnf install -y neovim python3-neovimArch / CachyOS
sudo pacman -S neovimmacOS (Homebrew)
brew install neovimWindows
# Via winget
winget install Neovim.Neovim
# Via Scoop
scoop install neovimVérifier l'installation
nvim --version
nvimUne fois dans Neovim, exécuter :checkhealth pour vérifier que tous les providers (Python, Node, clipboard, compilateur...) sont correctement détectés, et :Tutor pour suivre un tutoriel interactif si vous découvrez Vim/Neovim.
Structure de configuration
Neovim cherche sa configuration dans un dossier standardisé (XDG) :
~/.config/nvim/ # Linux / macOS
~/AppData/Local/nvim/ # Windows
~/.config/nvim/init.lua # Point d'entrée principal (remplace le .vimrc)
~/.config/nvim/lua/ # Modules Lua importés depuis init.luaUne organisation courante :
~/.config/nvim/
├── init.lua
└── lua/
├── config/
│ ├── options.lua -- vim.opt (comportements de l'éditeur)
│ ├── keymaps.lua -- vim.keymap.set (raccourcis)
│ ├── autocmds.lua -- vim.api.nvim_create_autocmd (événements)
│ └── lazy.lua -- bootstrap du gestionnaire de plugins
└── plugins/
├── lsp.lua
├── treesitter.lua
├── telescope.lua
└── ui.luaEt dans init.lua, on se contente généralement de charger ces modules :
require("config.options")
require("config.keymaps")
require("config.autocmds")
require("config.lazy")Options de base
-- lua/config/options.lua
local opt = vim.opt
opt.number = true -- Afficher les numéros de ligne
opt.relativenumber = true -- Numéros relatifs (pratique avec 5j, 3dd...)
opt.tabstop = 2 -- Largeur d'une tabulation
opt.shiftwidth = 2 -- Largeur d'une indentation
opt.expandtab = true -- Convertir les tabulations en espaces
opt.smartindent = true -- Indentation automatique intelligente
opt.wrap = false -- Ne pas retourner à la ligne visuellement
opt.ignorecase = true -- Recherche insensible à la casse...
opt.smartcase = true -- ...sauf si des majuscules sont utilisées
opt.termguicolors = true -- Couleurs 24 bits dans le terminal
opt.signcolumn = "yes" -- Toujours afficher la colonne des signes (LSP)
opt.clipboard = "unnamedplus" -- Utiliser le presse-papier système
opt.splitright = true -- Nouveaux splits verticaux à droite
opt.splitbelow = true -- Nouveaux splits horizontaux en bas
opt.scrolloff = 8 -- Garder 8 lignes visibles autour du curseur
opt.updatetime = 250 -- Délai avant déclenchement des événements CursorHoldRaccourcis (keymaps)
-- lua/config/keymaps.lua
vim.g.mapleader = " " -- Touche leader = espace (à définir avant les plugins)
local map = vim.keymap.set
map("n", "<leader>w", ":w<CR>", { desc = "Enregistrer" })
map("n", "<leader>q", ":q<CR>", { desc = "Quitter" })
map("n", "<C-h>", "<C-w>h", { desc = "Fenêtre de gauche" })
map("n", "<C-l>", "<C-w>l", { desc = "Fenêtre de droite" })
map("n", "<C-j>", "<C-w>j", { desc = "Fenêtre du dessous" })
map("n", "<C-k>", "<C-w>k", { desc = "Fenêtre du dessus" })
map("v", "<", "<gv", { desc = "Dé-indenter et garder la sélection" })
map("v", ">", ">gv", { desc = "Indenter et garder la sélection" })Autocommandes
-- lua/config/autocmds.lua
local augroup = vim.api.nvim_create_augroup("UserConfig", {})
-- Surligner brièvement le texte copié
vim.api.nvim_create_autocmd("TextYankPost", {
group = augroup,
callback = function()
vim.highlight.on_yank()
end,
})
-- Supprimer les espaces en fin de ligne avant sauvegarde
vim.api.nvim_create_autocmd("BufWritePre", {
group = augroup,
pattern = "*",
command = [[%s/\s\+$//e]],
})Gestion de plugins avec lazy.nvim
lazy.nvim est aujourd'hui le gestionnaire de plugins standard de l'écosystème Neovim (successeur de packer.nvim, plus rapide que vim-plug). Il se bootstrap automatiquement : le code ci-dessous le clone depuis GitHub s'il n'est pas déjà présent.
-- lua/config/lazy.lua
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",
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup("plugins") -- charge tous les fichiers de lua/plugins/Chaque fichier dans lua/plugins/ retourne une spec de plugin :
-- lua/plugins/ui.lua
return {
{ "folke/tokyonight.nvim", priority = 1000, config = function()
vim.cmd.colorscheme("tokyonight")
end },
{ "nvim-lualine/lualine.nvim", opts = {} },
{ "lewis6991/gitsigns.nvim", opts = {} },
}Commandes utiles
:Lazy " Interface de gestion (installer/mettre à jour/supprimer)
:Lazy sync " Installer les nouveaux plugins, mettre à jour, nettoyer les inutilisés
:Lazy update " Mettre à jour tous les plugins
:Lazy clean " Supprimer les plugins retirés de la config
:Lazy profile " Voir le temps de chargement au démarrageLSP : autocomplétion intelligente, navigation, refactoring
Neovim intègre un client LSP, mais pas les serveurs eux-mêmes. La stack standard :
mason.nvim: installe les serveurs LSP, linters et formattersmason-lspconfig.nvim: fait le pont entre Mason et lspconfignvim-lspconfig: configurations prêtes à l'emploi pour chaque serveur
-- lua/plugins/lsp.lua
return {
{
"neovim/nvim-lspconfig",
dependencies = {
"williamboman/mason.nvim",
"williamboman/mason-lspconfig.nvim",
},
config = function()
require("mason").setup()
require("mason-lspconfig").setup({
ensure_installed = { "lua_ls", "pyright", "tsserver", "rust_analyzer" },
})
local lspconfig = require("lspconfig")
local servers = { "lua_ls", "pyright", "tsserver", "rust_analyzer" }
for _, server in ipairs(servers) do
lspconfig[server].setup({})
end
-- Raccourcis actifs uniquement quand un LSP est attaché au buffer
vim.api.nvim_create_autocmd("LspAttach", {
callback = function(args)
local map = function(mode, lhs, rhs)
vim.keymap.set(mode, lhs, rhs, { buffer = args.buf })
end
map("n", "gd", vim.lsp.buf.definition)
map("n", "gr", vim.lsp.buf.references)
map("n", "K", vim.lsp.buf.hover)
map("n", "<leader>rn", vim.lsp.buf.rename)
map("n", "<leader>ca", vim.lsp.buf.code_action)
map("n", "<leader>f", function() vim.lsp.buf.format({ async = true }) end)
end,
})
end,
},
}Installer un serveur manuellement : :MasonInstall pyright. Vérifier l'état des clients attachés à un buffer : :LspInfo.
Autocomplétion (nvim-cmp ou blink.cmp)
-- lua/plugins/completion.lua
return {
{
"hrsh7th/nvim-cmp",
dependencies = { "hrsh7th/cmp-nvim-lsp", "L3MON4D3/LuaSnip" },
config = function()
local cmp = require("cmp")
cmp.setup({
snippet = {
expand = function(args) require("luasnip").lsp_expand(args.body) end,
},
mapping = cmp.mapping.preset.insert({
["<C-Space>"] = cmp.mapping.complete(),
["<CR>"] = cmp.mapping.confirm({ select = true }),
["<Tab>"] = cmp.mapping.select_next_item(),
["<S-Tab>"] = cmp.mapping.select_prev_item(),
}),
sources = { { name = "nvim_lsp" }, { name = "luasnip" } },
})
end,
},
}blink.cmp est une alternative plus récente et plus rapide (écrite en Rust), avec une API de configuration similaire.
Tree-sitter (coloration syntaxique et analyse du code)
-- lua/plugins/treesitter.lua
return {
{
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
config = function()
require("nvim-treesitter.configs").setup({
ensure_installed = { "lua", "python", "javascript", "bash", "markdown" },
highlight = { enable = true },
indent = { enable = true },
})
end,
},
}Recherche floue (Telescope)
-- lua/plugins/telescope.lua
return {
{
"nvim-telescope/telescope.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
keys = {
{ "<leader>ff", "<cmd>Telescope find_files<cr>", desc = "Chercher un fichier" },
{ "<leader>fg", "<cmd>Telescope live_grep<cr>", desc = "Chercher dans le texte" },
{ "<leader>fb", "<cmd>Telescope buffers<cr>", desc = "Lister les buffers" },
{ "<leader>fh", "<cmd>Telescope help_tags<cr>", desc = "Chercher dans l'aide" },
},
},
}Explorateur de fichiers
Deux options courantes : nvim-tree.lua (arborescence classique) ou neo-tree.nvim (plus riche, avec sources git/buffers).
-- lua/plugins/explorer.lua
return {
{
"nvim-tree/nvim-tree.lua",
dependencies = { "nvim-tree/nvim-web-devicons" },
keys = { { "<leader>e", "<cmd>NvimTreeToggle<cr>", desc = "Explorateur de fichiers" } },
opts = {},
},
}Formatage et linting
conform.nvim (formatage) et nvim-lint (linting) sont des alternatives légères à null-ls, désormais peu maintenu.
-- lua/plugins/formatting.lua
return {
{
"stevearc/conform.nvim",
opts = {
formatters_by_ft = {
lua = { "stylua" },
python = { "black" },
javascript = { "prettier" },
},
format_on_save = { timeout_ms = 500, lsp_fallback = true },
},
},
}Exemple de configuration minimale complète
-- init.lua (version condensée, tout-en-un pour démarrer rapidement)
vim.g.mapleader = " "
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.tabstop = 2
vim.opt.shiftwidth = 2
vim.opt.expandtab = true
vim.opt.termguicolors = true
vim.opt.clipboard = "unnamedplus"
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", lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup({
{ "neovim/nvim-lspconfig" },
{ "nvim-treesitter/nvim-treesitter", build = ":TSUpdate" },
{ "nvim-telescope/telescope.nvim", dependencies = { "nvim-lua/plenary.nvim" } },
{ "nvim-tree/nvim-tree.lua" },
{ "folke/tokyonight.nvim" },
})
vim.cmd.colorscheme("tokyonight")Migrer depuis Vim
- Neovim lit toujours un
~/.vimrcen Vimscript s'il n'y a pas d'init.lua, donc la migration peut être progressive. - La commande
:help nvim-from-vimliste les différences de comportement par défaut. - Un
.vimrcpeut être chargé depuisinit.luaavecvim.cmd.source("~/.vimrc")pendant la transition. - Les raccourcis et commandes de base (mouvement, édition, registres, macros...) sont identiques : voir la cheat sheet Vim.
Ressources
- neovim.io site officiel
- neovimcraft.com annuaire de plugins
:help nvim-from-vimdifférences avec Vim- github.com/neovim/neovim dépôt source
- github.com/folke/lazy.nvim gestionnaire de plugins
