Skip to content

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

bash
# 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/nvim

Fedora / RHEL / Alma

bash
sudo dnf install -y neovim python3-neovim

Arch / CachyOS

bash
sudo pacman -S neovim

macOS (Homebrew)

bash
brew install neovim

Windows

powershell
# Via winget
winget install Neovim.Neovim

# Via Scoop
scoop install neovim

Vérifier l'installation

bash
nvim --version
nvim

Une 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) :

bash
~/.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.lua

Une 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.lua

Et dans init.lua, on se contente généralement de charger ces modules :

lua
require("config.options")
require("config.keymaps")
require("config.autocmds")
require("config.lazy")

Options de base

lua
-- 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 CursorHold

Raccourcis (keymaps)

lua
-- 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
-- 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
-- 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
-- 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

vim
: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émarrage

LSP : autocomplétion intelligente, navigation, refactoring

Neovim intègre un client LSP, mais pas les serveurs eux-mêmes. La stack standard :

lua
-- 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.

lua
-- 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
-- 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
-- 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
-- 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
-- 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

lua
-- 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 ~/.vimrc en Vimscript s'il n'y a pas d'init.lua, donc la migration peut être progressive.
  • La commande :help nvim-from-vim liste les différences de comportement par défaut.
  • Un .vimrc peut être chargé depuis init.lua avec vim.cmd.source("~/.vimrc") pendant la transition.
  • Les raccourcis et commandes de base (mouvement, édition, registres, macros...) sont identiques : voir la cheat sheet Vim.

Ressources

Publié sous lience MIT.