Comment j'ai configuré neovim pour écrire du LaTeX - Partie 2 : la completion
Ce billet fait suite à un premier billet sur la configuration du serveur LSP. Vous pouvez retrouver la partie 1 ici.
La complétion ?
Une fonctionnalité importante (selon moi) pour un éditeur de texte est sa
capacité à compléter quelque chose.
Par exemple, si vous avez une variable_avec_un_nom_tres_long
, peut-être
n'avez-vous pas envie de taper son nom complet manuellement à chaque fois ;
un mécanisme de complétion le fera à votre place, pour peu que vous tapiez les
premières lettres.
Certains sont plus ou moins intelligents que d'autres, regardent simplement le
contenu de votre fichier (comme neovim
, nativement) ou tirent partie d'un
serveur LSP pour regarder dans votre projet en entier, offrir une complétion
contextuelle (vous proposer une référence si vous êtes dans un environnement
\cite
, par exemple)...
Aujourd'hui, on va parler de complétion et de snippets, pour se simplifier la
vie.
Liste des ingrédients
Cette fois on a besoin de moins d'ingrédients, puisque (en général), le plugin de complétion est autonome. J'utilise personnellement le plugin de la suite mini.nvim, notamment car j'utilise déjà d'autres plugins de cette suite et parce que je trouve que la complétion fonctionne bien par défaut. Donc, on a besoin :
- neovim v0.10.0 ou supérieure ;
- mini.completion,
en tant que partie de
mini.nvim
ou en version autonome (ici, je vais utiliser mini.icons pour avoir de belles icônes dans le menu de sélection, mais c'est juste pour la frime). - mini.snippets, selon le même mécanisme.
J'utilise toujours lazy.nvim pour gérer mes plugins.
Récupérer le plugin
Puisque j'utilise la suite mini.nvim
, la configuration n'est pas exactement
la même en ce qui concerne l'URL de téléchargement, je vous invite à regarder
la
doc
pour avoir toutes les infos.
Cette fois, ça se passe dans ~/.config/nvim/plugin/mini.lua
:
return {
{
"echasnovski/mini.nvim",
version = false,
dependencies = {
{ url = "https://codeberg.org/swytch/snippets.git" }
},
config = function()
-- completion & snippets
local gen_loader = require("mini.snippets").gen_loader
local tex_patterns = { "tex/**/*.json", "**/tex.json" }
local lang_patterns = {
tex = tex_patterns,
plaintex = tex_patterns,
latex = tex_patterns,
}
require("mini.snippets").setup(
{
snippets = {
-- Load snippets for all languages
gen_loader.from_runtime("global.json"),
-- Load snippets based on current language by reading files from
-- "snippets/" subdirectories from 'runtimepath' directories.
gen_loader.from_lang({ lang_patterns = lang_patterns }),
},
mappings = {
-- Expand snippet at cursor position. Created globally in Insert mode.
expand = "<C-l>",
-- Interact with default `expand.insert` session.
-- Created for the duration of active session(s)
jump_next = "<C-j>",
jump_prev = "<C-k>",
stop = "<C-h>",
},
}
)
local MiniCompletion = require("mini.completion")
local process_items = function(items, base)
-- Don't show 'Text' suggestions
items = vim.tbl_filter(function(x) return x.kind ~= 1 end, items)
return MiniCompletion.default_process_items(items, base)
end
MiniCompletion.setup(
{
-- Delay (debounce type, in ms) between certain Neovim event and action.
-- This can be used to (virtually) disable certain automatic actions by
-- setting very high delay time (like 10^7).
delay = { completion = 10 ^ 9 },
-- Way of how module does LSP completion
lsp_completion = {
source_func = 'omnifunc',
auto_setup = false,
process_items = process_items,
},
-- Fallback action as function/string. Executed in Insert mode.
-- To use built-in completion (`:h ins-completion`), set its mapping as
-- string. Example: set '<C-x><C-l>' for 'whole lines' completion.
fallback_action = '<C-n>',
-- Module mappings. Use `''` (empty string) to disable one. Some of them
-- might conflict with system mappings.
mappings = {
-- Force two-step/fallback completions
force_twostep = '<C-Space>',
force_fallback = '<A-Space>',
-- Scroll info/signature window down/up. When overriding, check for
-- conflicts with built-in keys for popup menu (like `<C-u>`/`<C-o>`
-- for 'completefunc'/'omnifunc' source function; or `<C-n>`/`<C-p>`).
scroll_down = '<C-n>',
scroll_up = '<C-p>',
},
}
)
end,
},
}
La configuration est assez simple à comprendre :
puisque mini.snippets
ne gère que l'utilisation de snippets (et pas les
snippets eux-mêmes), on les récupères d'un dossier tiers (ici c'est un
plugin perso que je passe via dependencies.[url = "https://codeberg.org/swytch/snippets.git"]
, mais il existe un
plugin communautaire qui en
donne beaucoup) et on les passe au plugin lors de son activation ;
on peut ensuite personnaliser les commandes claviers qui activent le plugin
pour étendre les snippets et naviguer à l'intérieur de ceux-ci, le cas
échéant.
En ce qui concerne mini.completion
c'est un peu pareil.
D'abord, on filtre un peu les propositions pour ne pas avoir le texte d'un
fichier, mais simplement les éléments « intéressants » (variables,
fonctions...) ;
ensuite, on passe tout ça au plugin, on lui donne un temps d'activation très
long (pour une raison qui m'échappe, la complétion automatique n'est pas
désactivable), on configure l'action « en cas d'échec » (fallback_action
) pour
retomber sur le mécanisme de complétion natif de neovim
, on paramètre les
raccourcis clavier, et voilà.
Et finalement, ça donne quoi ?
La complétion donne ça :
Par défaut, il affiche également une bulle d'info pour, dans notre cas, savoir exactement quelle référence on va citer.
Pour les snippets, ça donne ça :
Ici, le point doré indique le nœud sur lequel on se trouve actuellement, les points bleus sont les nœuds que l'on n'a pas encore visité et le carré rouge est le nœud de sortie. Si ce n'est pas clair, référez-vous à la démo du plugin qui est très bien fichue.
The deed is done.
Je pense que vous avez une bonne base pour la complétion et les snippets ; maintenant, à vous de trouver la configuration qui vous va le mieux.
À ciao !