blog/content/software/nvim-fr.md

26 KiB
Raw Blame History

Title Date Modified Lang Author Category Tags Slug table-of-contents Header_Cover Summary
Quelques pointeurs pour Vim 2023-05-13 11:00 2023-05-14 14:00 fr Fabrice programmes vim, neovim nvim true ../images/covers/hand-fan.jpg Des informations que jaurais bien aimé connaître plus tôt dans (Neo)Vim.

Neovim est un éditeur de texte modal, héritier direct de Vim lui-même issu de vi. Cette famille déditeurs est assez répandue, et au moment de rechercher un éditeur de texte, on peut se retrouver face à des choix comme Vim vs Emacs.

Trolls mis à part, il savère que jutilise Vim/Neovim comme éditeur de texte au quotidien pour éditer du code, écrire certains e-mails, prendre des notes, écrire ce blog…

Cependant, si vous êtes un vimiste convaincu ou simplement intéressés par la question et avez essayé, vous vous serez sans doute rendu compte que la courbe dapprentissage nest pas des plus douces, et quil est parfois compliqué de trouver linformation que lon cherche… notamment si on ignore quelle existe.

À ce sujet, je ne peux que recommander les rencontres avec dautres usagers, comme par exemple aux tuppervim. Ces rencontres sont loccasion de partager et de découvrir des informations autour de Vim afin de les intégrer progressivement à son flot de travail. Malheureusement, cette solution nest pas forcément des plus pratiques pour tous: les rencontres ont lieu à Paris/Lyon/Grenoble, ce qui les rend difficiles daccès pour le sud-ouest de la France… voire pour les personnes en dehors de la France métropolitaine. Ainsi, même si comme la documentation Vim qui regroupe toutes les informations dont on pourrait avoir besoin, il existe des archives des rencontres précédentes. On se perd cependant très vite au milieu de cette jungle de conseils. Ces archives sont plutôt pratiques pour les personnes ayant déjà assisté à une des réunions et qui cherche à retrouver un point particulier.

Ainsi je vais essayer de compiler quelques astuces et conseils que je pense être intéressant et que jaurais bien aimé découvrir plus tôt par moments… Pour rappeler quelques principes de base du cheminement vers la sagesse: nessayez pas de tout intégrer dun coup: cest un coup à se décourager. Dautant plus que Vim est avant tout un couteau-suisse, ainsi on ne va pas utiliser la lime à ongle pour couper du fromage : ça peut fonctionner mais cest pas très pratique. Toutes les commandes et techniques ne se valent donc pas suivant lusage de Vim que lon a.

Ce billet nest donc pas un cours pour apprendre à utiliser Vim, mais simplement quelques astuces pour des personnes qui utilisent Vim régulièrement sans pour autant vouloir devenir des Vim-wizards et qui pourraient ignorer certains conseils qui améliorent la qualité de vie sans relever de lésotérisme. Je ne vais dailleurs pas aborder le point des modules en détails et essayer de rester le plus agnostique possible. Néanmoins, comme ce billet ne sadresse pas nécessairement à des personnes qui découvriraient Vim, si je me mets à jargonner de manière incompréhensible et que vous trouvez cela dérangeant dans la lecture, merci de me le signaler (par mail, irc, autre).

Parler à son éditeur

Lorsque jai découvert Vim, comme indiqué dans la première phrase de ce billet, ce qui ma marqué est le mot « modal ». Je pensais quil sagissait de la partie importante dans la description de Vim, et que cétait ce qui le différenciait demacs ou autre. En effet, lors de lapprentissage de Vim, la première réaction naturelle est de se dire que pouvoir passer dun mode à lautre en une seule touche permet déviter des acrobaties digitales pour appuyer sur trois touches à la fois, qui ne sont pas toujours bien placées.

Cependant, selon moi, ce qui fait la force de Vim, ce nest pas seulement cette distinction entre modes qui permet de faire de la sélection visuelle, ou de naviguer entre ses différents fichiers pour aller exactement où lon souhaite aller en trois entrées clavier, mais cest la langue de Vim.

Ainsi, lors de lapprentissage, il est important de comprendre ce quil se passe. De la même manière quil ne faut pas copier-coller des lignes de commandes quon ne comprend pas dans son terminal, il est impératif de ne pas simplement apprendre des séquences de commandes dans Vim sans comprendre ce quon est en train de communiquer à son éditeur.

Pour citer une erreur de jeunesse, lorsque jai appris à utiliser Vim, jai lu quelque part sur internet que gqap en mode normal permettait de reformater un bloc de texte. Je ne comprenais pas exactement ce que «bloc» signifiait, mais ça fonctionnait globalement, et les modificateurs de répétition (par exemple 3gqap) ont le comportement attendu. Cependant, ce défaut dabstraction fait dune part que jai appris plus de commandes par cœur que nécessaire, par exemple dap et yap construites sur le même principe, là où simplement savoir ce que signifie la commande aurait été un gain de place en mémoire, et fait gagner en flexibilité.

Pour cela il existe pas mal de tutoriels:

Mais pour faire simple, et ce que jaurais bien aimé quon me dise à mes débuts (mais bon, après faut lire de la documentation rébarbative en anglais, et cétait pas très facile pour moi à lépoque), cest quune commande Vim est en fait… une phrase. On demande une action (par exemple = qui signifie «indenter»), on donne un champ daction (ap qui signifie «autour du paragraphe», où un paragraphe est défini comme un bloc séparé par au moins deux retours chariots avant et après). Et là encore ce champ daction peut être modifié, ainsi le a de ap signifie around (autour), et peut-être remplacé par i pour inside. Pour les paragraphes, cela signifie prendre en compte ou non les lignes vides autour de ce dernier, mais pour des parenthèses, cela peut-être plus intéressant. Ainsi ri( permet de réécrire le contenu dune parenthèse, ce qui peut être utile pour remplacer les arguments dune fonction, là où ra( va aussi effacer les parenthèses lors de la réécriture.

Si vous nêtes pas certain de ce que vous faites, il peut être intéressant de se placer en mode visuel (v) pour voir et assimiler ce quil se passe. Cest un peu comme mettre des sous-titres pour être sûr de comprendre ce quil se dit.

Le mode visuel

Parlons de ce mode visuel dailleurs. Comme beaucoup dutilisateur Linux, jai été formaté pour trouver que tout ce qui se fait simplement en ligne de commande est beaucoup plus pur/élégant que de devoir faire treize clics pour arriver au même résultat. Or comme tout dogmatisme, il révèle parfois ses limites et pousse à lobstination là où ça na pas forcément lieu dêtre. Une des conséquences perverse de cette préconception est davoir ignoré le mode visuel, ou alors essayer de trouver de manière de men passer par moments alors quil permet de faire les choses avec un retour visuel qui permet de limiter les erreurs. Et de manière similaire à la frappe au clavier, la précision est plus importante que la vitesse: on perd beaucoup plus de temps et dénergie à corriger une faute que davoir pris quelques instants de plus pour garantir le résultat… sans parler de la frustration induite.

Avant de passer à la suite, voici deux liens qui présentent la même chose, mais le premier est plus visuel (il y a des vidéos démonstratives) que le second, je vous laisse choisir selon vos préférences.

Changer la position du curseur visuel

Il peut arriver de sélectionner un paragraphe, avec vap par exemple, et de se rendre compte quon aurait bien aussi pris la ligne précédente, qui peut-être un titre par exemple. Or, vap va placer le curseur permettant déditer la zone de sélection visuelle (par exemple avec } pour sélectionner en plus le paragraphe suivant) à la fin de la sélection.

Pour alterner la position du curseur du début à la fin, il suffit dune simple pression sur la touche o.

Par exemple, sur un bloc de trois paragraphes, on peut sélectionner le deuxième (vap) parce que cest celui qui nous intéresse (pour le copier par exemple), puis se rendre compte que le premier introduit le deuxième et avoir envie de le rajouter à la sélection. On peut donc presser o pour replacer le curseur au début, et sélectionner le paragraphe précédent avec {{ (oui, pour, me semble-t-il, de sombres raisons d'inclusion/exclusion, le paragraphe précédent est… une ligne vide). On se rend ensuite compte que les deux paragraphes sélectionnés ne sont pas complets si on ne rajoute par le dernier paragraphe, et pour cela, on peut revenir à la fin par une seconde pression sur o et le sélectionner avec }.

Lexemple précédent illustre également lintérêt du mode visuel pour se rendre compte de ce quil se passe. Intuitivement, je pensais que { au début du paragraphe allait reprendre le paragraphe précédent directement, et cela ma amené à regarder la doc des object-motions, et me rendre compte que cela ne fonctionne pas exactement comme je me le représentais. Durant mes tests pour écrire ce billet, je me suis aussi rendu compte que v3ap sélectionne bien le paragraphe en cours et les trois qui suivent, là où v3ip nen prend que deux pour ces raisons de mouvements inclusifs ou exclusifs.

Incrémenter une colonne de nombres

Si lon souhaite créer une colonne de nombres (par exemple pour une énumération) comme ceci:

1
2
3
4
5
6
7
8
9
10

Une technique consiste à insérer 10 fois 0: 10i0<Enter><Esc>, supprimer la ligne surnuméraire dd, rentrer en mode visuel v, sélectionner le bloc (sil est précédé dune ligne vide ou dun début de fichier): ip, et incrémenter de manière globale g<Ctrl+a>.

Pour comprendre ce quil se passe, <Ctrl-a> permet dincrémenter le nombre sous lequel se trouve le curseur (et sa contrepartie <Ctrl-x> permet de le décrémenter). Si on sélectionne visuellement une colonne et quon applique simplement <Ctrl-a>, la colonne va être incrémentée (et donc donner une colonne de «1» dans le cas précédent). Ici, le modificateur g sinterprète comme «effectue <Ctrl-a> de manière intelligente ».

Utiliser le mode visuel pour limiter certaines actions

On est parfois tenté de lancer de gros remplacements par expressions régulières sur son fichier, mais on est pas toujours sûr de ce quon fait. Lorsquon se met en mode ligne de commande sous Vim pour effectuer un remplacement par exemple, cela va commencer la ligne par '<,'>, qui indique que laction se déroulera entre les marques < et > qui représentent le début et la fin de la sélection visuelle.

Cest ainsi possible de faire des tests pour vérifier si lexpression régulière fait bien ce qui est attendu delle sur un petit exemple avant de passer à léchelle.

Bien entendu, je ne recommande pas cette méthode, principalement parce quaujourdhui il existe dautres méthodes pour faire du remplacement de masse. Par exemple, une des raisons qui peut pousser à cela, est le renommage dune variable dans un programme. Désormais, il est possible de faire appel au « language-server protocol » (LSP) pour faire cela:

Ranger sa configuration

Un autre point que je trouve important et que jai découvert un peu tard est la structure des dossiers .config/{n,}vim/. Jai en effet passé mes premières années avec un seul .vimrc avant de létendre avec dautres fichiers que je changeais (source) par la suite.

Or, le dossier $VIMHOME est rangé de manière sémantique:

Nutilisant pas toute la structure, je vais me concentrer ici sur mon usage: les dossiers ftplugin et plugin. Pour faire simple, le contenu de plugin/*.{vim,lua} sera automatiquement chargé au démarrage, et le contenu de ftplugin/$FT.{vim,lua} sera chargé lorsque vous ouvrez un fichier reconnu comme $FT par son type de fichier.

Ainsi, en ayant un fichier ftplugin/pandoc.lua avec le paramétrage de vim-pandoc-syntax et mes raccourcis pour pandoc pour écrire ce billet. Par la suite, il est plus facile de léditer et de retrouver la signification des différentes lignes grâce au système de fichier.

De manière similaire, je sais que plugin/bepo.lua décrit mon réarrangement partiel des raccourcis Vim pour le bépo.

Type du fichier

Détection automatique

Comme indiqué précédemment, les fichiers dans ftplugin sont chargés en fonction du type de fichier. Celui-ci est défini via loption filetype ou ft pour faire court. Cette abstraction permet de faire partager à une classe de fichier des configurations (par exemple la coloration syntaxique ou l'indentation) malgré des extensions différentes (html/htm, py/sage, c/h). On peut de plus noter que la reconnaissance automatisée de type de fichier (:filetype on) est activée par défaut dans Neovim.

Indication manuelle

Celui-ci peut aussi être défini à la main via :set ft=<…>, par exemple pour que le fichier de syntaxe de pandoc soit chargé, il faut que ce fichier soit de type pandoc. Or, par défaut un *.md est reconnu comme filetype=markdown, et les personnalisations spécifiques de lextension vim-pandoc ne seront pas appliquées.

Modeline

De manière ponctuelle, il est possible de le définir fichier par fichier à laide du modeline. Il sagit de cette ligne commentée étrange que lon retrouve parfois au début ou à la fin d'un fichier qui ressemble à ça:

# vim: noexpandtab

Le modeline permet de préciser certains paramètres à propos d'un fichier, comme précédemment pour indiquer lutilisation de tabulations plutôt que despaces. Mais cela peut aussi être utile pour indiquer que lon souhaite lutilisation dun vérificateur orthographique (spell), la langue de ce vérificateur (spelllang/spl), le type de fichier (ft), et autres.

Il est à noter que le modeline est là pour une utilisation ponctuelle. Comme il sagit dune entrée externe exécutée à l'ouverture du fichier, il peut créer des risques de sécurité au moment douvrir des fichiers issus dune source externe, comme ça a pu être le cas avec les vulnérabilités CVE-2019-12735 et CVE-2016-1248 par exemple.

Autocommands

Autrement, il est aussi possible dexécuter des commandes pour des fichiers particuliers à l'aide des autocommands.

Je souhaite, par la suite faire un billet spécifiquement sur la configuration de Vim, mais il est difficile de parler dautocommands sans lévoquer.

Par exemple, pour spécifier le type de fichier pour les documents de ce blog, détecter la langue à partir de ma convention de nommage ainsi que des options de mise en forme il est possible de définir dans $VIMHOME/plugin/blog.lua:

local blog_group = vim.api.nvim_create_augroup('blog', { clear = true })

vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
  pattern = {vim.fn.expand("~") .. "/chemin/vers/blog/**/*.md"},
  group = blog_group,
  callback = function()
    vim.o.filetype = 'pandoc'
    vim.o.tw = 80
    vim.o.spell = true
    vim.o.spl = 'en'
  end
})

vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
  pattern = {vim.fn.expand("~") .. "/chemin/vers/blog/**/*-fr.md"},
  group = blog_group,
  callback = function()
    vim.o.spl = "fr"
  end
})

La compréhension du bloc de code non commenté ci-dessus est laissée en exercice au lecteur attentif.

Blague à part, on remarque aussi que le fait davoir rangé ses fichiers de manière sémantique dans sa configuration Neovim/Vim permet de s'y retrouver facilement mais surtout de pouvoir tester et revenir en arrière aisément. Ainsi, «configurer son éditeur» devient moins effrayant que ce quil semblerait de prime abord, dautant plus que la configuration de Neovim par défaut va au-delà de la politique de Vim initiale qui est dessayer dêtre compatible avec vi. Conséquence de quoi, la configuration de Neovim, étant plus orientée «utilisable» par défaut est moins verbeuse que celle de Vim.

Je vous conseille ces deux vidéos pour en savoir plus sur les autocommands en Lua pour Neovim:

La navigation

Un autre point important, est la navigation dans vos projets. En effet, à partir dun moment, avoir un seul fichier pour tout devient irréaliste quel que soit le projet, et il convient de savoir naviguer rapidement entre différents emplacements dans le fichier.

Par souci de généralité, je vais, dans la suite, ignorer les actions de navigations spécifiques à certains plugins comme LSP.

Sauter de fichier en fichier

Pour prendre un exemple de ma vie courante, jutilise souvent LaTeX pour générer des documents. Lorsque ces documents commencent à prendre de la place (par exemple un manuscrit de thèse) et quils sont séparés en plusieurs fichiers, on inclut les sous-fichiers à laide de la macro \include{filename}.

Pour aller directement au fichier filename.tex, il suffit de placer le curseur au-dessus et dutiliser la commande gf (go file pour le mnémonique, même si en termes de langue Vim cest pas exactement ça, cest une approximation suffisante). Bien entendu cette commande peut sétendre : <ctrl-w>gf permet de louvrir dans un nouvel onglet.

Et cela fonctionne aussi pour les en-têtes en C par exemple ou dans nimporte quelle situation où un chemin vers un fichier existe dans le fichier ouvert.

Lhistorique de navigation

Si vous avez effectué la commande précédente (gf), pour revenir sur vos pas, il existe la commande <Ctrl-o> qui permet de revenir en arrière dans lhistorique de sauts, que vous pouvez visualiser à laide de la commande :jumps.

Vous pouvez aussi revenir en avant à laide de la commande <Ctrl-i>.

Cest aussi pratique pour revenir plus haut après un grand déplacement (par exemple une recherche avec /).

Repliements

Je ne vais pas rentrer dans les détails des repliements sous Vim, surtout que cest parfois les plugins qui le gèrent, mais apprendre à les ouvrir et les fermer est potentiellement utile alors je pose ça là:

  • zo/zc: ouvrir/fermer dun niveau le repli sous le curseur.
  • zO/zC: ouvrir/fermer complètement le repli sous le curseur.
  • zm/zr: ouvrir/fermer dun niveau tous les replis.
  • zM/zR: ouvrir/fermer complètement tous les replis.

Plus de ressources:

Le reste en vrac

Quelques autres astuces plus ou moins utiles en vrac qui utilisent ou non des concepts présentés précédemment:

  • %r)<Ctrl-o>r(: en se plaçant sur le premier élément dune paire (par exemple des crochets), permet de les remplacer par des parenthèses. La commande va à la paire associée avec %, remplace par une parenthèse fermante avec r), revient en arrière avec <Ctrl-o> (donc au crochet ouvrant) et remplace par une parenthèse ouvrante via r(.
  • @:/@@: je nai rien dit sur les macros parce que si cest puissant, cest aussi un moyen simple de faire des erreurs, mais une utilisation un peu détournée des macros est de remarquer que @: permet de relancer la commande précédente (par exemple un make), et ainsi @@ qui relance la macro précédente, permet de réeffectuer cette commande à moindre coût.
  • <Ctrl-x><Ctrl-f>: complète un nom de fichier. Je voulais en dire plus sur la complétion, mais pour le moment, ma configuration est un peu chaotique à ce niveau et jai trois plugins qui se battent pour la même fonctionnalité, je me suis donc passé de cette section pour le moment.
  • :r !<commande système>: par exemple :r !date permet décrire la date actuelle sur la ligne suivante. De façon plus générale, cela permet décrire la sortie standard dun programme installé sur votre système.
  • Activer undodir et undofile pour avoir un historique de modification (u/<Ctrl-r>) persistant par fichier et non par session. Cela peut être pratique pour pouvoir annuler une modification sur un fichier de configuration quand on se rend compte trois jours après que cela ne nous convient pas par exemple.
  • ]p: pour avoir une indentation cohérente lors d'un copier-coller.
  • :cq: pour quitter sans sauvegarder et en renvoyant un code d'erreur non nul. Cela peut être utile pour annuler lécriture dun message de commit git par exemple.
  • cursorline/cursorcolumn: ces deux options permettent respectivement de surligner la ligne et la colonne du curseur afin de le repérer plus facilement dans la fenêtre. Ce nest pas indispensable, mais je trouve ça plutôt agréable.

Le mot de la fin

Pour conclure, on peut voir que Vim est un éditeur assez puissant et qui peut sadapter à beaucoup de cas dusages. On a juste effleuré ce qui était possible, et à chaque fois que je vais à un tuppervim, je découvre toujours des petits trucs qui modifient un peu mon usage et rendent lutilisation de Vim de plus en plus confortable. De manière similaire à lutilisation de dispositions de claviers dites ergonomiques, ce qui rend Vim agréable à utiliser ce nest pas la course permanente à la productivité, mais le gain de confort. Lamélioration de la vitesse nest quun effet de bord des facilités accordées par léditeur pour effectuer certaines actions autrement plus rébarbatives.

De plus, en rangeant son $VIMHOME, il est possible de pouvoir tester différentes choses rapidement et sans conséquences. Vous avez essayé une commande étrange trouvée sur internet dans $VIMHOME/plugin/test.lua et ça affiche 30 lignes d'erreurs? Pas de problèmes, il suffit de supprimer le fichier de test. Si celui-ci fonctionne comme attendu, il ne reste plus qu'à le renommer de manière plus compréhensible. Je pense qu'il est assez fondamental de sapproprier ses outils, et pour un éditeur de texte aussi configurable que Neovim, cest dautant plus important de ladapter à son utilisation. Une règle dor étant: «Si quelque chose vous dérange, cest quil y a moyen daméliorer ça». D'autant plus que dautres personnes ont sans doute rencontré le même problème avant vous (sauf cas de niche bien entendu). Ainsi, je vous encourage fortement à essayer de nouvelles choses dans Vim, d'autant plus que les usages ne sont pas figés dans le temps, et que ce qui nous convient à un moment, ne sera pas forcément toujours d'actualité trois ans plus tard.

Je nai bien entendu pas parlé dénormément de choses: le découpage de lespace de travail à la tmux, les onglets et la navigation, la complétion automatique, les marques, les tags, les déplacements… Et le but de ce billet nest pas dêtre exhaustif mais dêtre rapidement accessible. Cependant si vous pensez quil manque des choses, nhésitez pas à me contacter à ce sujet, ce billet peut évoluer suivant ce que je découvre et en fonction de ma mémoire.

Enfin, ça a été rapidement évoqué à la fin des points en vrac, mais je pense aussi faire un billet, dans un futur plus ou moins proche, un billet à propos de la configuration de Vim en lua.

Cest tout pour moi, en espérant que vous avez apprécié ce petit pavé. À bientôt!

**Remerciements**: Merci à [Pablo Coves](https://pcoves.gitlab.io/blog/) pour sa relecture et ses conseils pour améliorer le billet.