Utiliser les replis (folding) de Vim
La rédaction de documents sur ordinateur fait gagner beaucoup de temps, mais parfois, rien ne remplace la bonne vieille feuille de papier. Il est en effet plus facile de comparer des portions de texte lorsqu'il est présent sur papier plutôt que sur un écran. Sitôt qu'un document devient plus grand que l'écran, il est difficile de comparer et travailler sur des endroits différents du fichier. Les fonctions de partage d'écran (:split) vertical ou horizontal peuvent pallier à ce problème mais nous allons nous intéresser ici aux replis (folding) de Vim. Un repli permet de cacher une portion du fichier en cours d'édition.
Toutes les commandes de repliage commencent par 'z'. D'après la documentation, ce 'z' fait penser à une feuille de papier repliée si on la regarde de profil. Oui, bon...
Création des replis
Commençons d’abord avec certaines actions simples de pliage. Ouvrez un fichier, assez long de préférence. Placez le curseur où bon vous semble. En mode normal, tapez zf10j, Vim crée alors un repli de 11 lignes : la ligne où se trouvait le curseur et les 10 lignes relatives au mouvement '10j'. Il est possible d'utiliser toute sorte de mouvement en combinaison avec 'zf'.
Les replis fonctionnent également en mode visuel. Tapez la touche V, sélectionnez quelques lignes via le mouvement 5k par exemple puis zf, Vim crée alors un repli contenant les lignes sélectionnées.
Il est également possible de créer un repli en indiquant un intervalle de lignes. Si vous souhaitez créer un repli occupant les lignes 50 à 70, tapez :50,70 fold et appuyer sur entrée. Notez que l'espace entre '70' et 'fold' est facultatif et que vous pouvez ne saisir que 'fo' au lieu de 'fold', 'fo' est la forme courte de 'fold'. Il est aussi possible d'utiliser le '.' pour désigner la ligne courante. Ainsi, si le curseur se trouve à la ligne 150 et que l'on désire créer un repli démarrant du curseur à la ligne 180, il suffit de saisir la commande :.,180 fo. Si vous inversez l'intervalle, Vim vous demandera si vous souhaitez intervertir les valeurs.
Enfin, vous pouvez créer un repli à partir de la position du curseur jusqu'à un résultat de recherche. Si vous exécutez zf/ma chaine ,Vim créera un repli allant de la ligne courante à la première occurrence de la chaine ma chaine.
Vim sait sélectionner le texte intelligemment. Vous êtes en train d'éditer un programme et vous avez un bloc de texte entre accolades '{' et '}'. Positionnez le curseur entre ces accolades, et tapez zfa}. Vim crée alors un repli allant de l'accolade située juste avant le curseur jusqu'à l'accolade située juste après le curseur. Ceci fonctionne aussi avec les autres délimiteurs de bloc : les parenthèses zfa), les crochets zfa], et les crochets angulaires zfa>. Vim sait reconnaître aussi les blocs imbriqués. Par exemple, en tapant zf2a}, Vim créera un repli sur le bloc englobant le bloc courant, autrement dit, le bloc de niveau supérieur.
Vous l'avez sans doute deviné avec la phrase précédente, les replis peuvent être imbriqués : un repli peut contenir d'autres replis, et ainsi de suite.
Une fois le repli créé, apparaît en surbrillance le nombre de lignes pliées ainsi qu'un petit échantillon du texte contenu. Les tirets indiquent le niveau hiérarchique du repli. Pour un repli principal (du plus haut niveau), il y a deux tirets. Les replis imbriqués sont représentés par plus de tirets : le niveau 2 est représenté par 3 tirets, le niveau 3 par 4 tirets, etc.

Utiliser les replis
Créer des replis, c'est bien, mais que peut-on en faire ? Il peut être intéressant de pouvoir ouvrir un repli pour voir ou modifier son contenu, non ? Pour ce faire, placez le curseur sur le repli concerné et tapez zo. Pour refermer le repli, tapez zc. Note : 'o' pour 'open' et 'c' pour 'close'.
Pour se déplacer rapidement entre les replis, utilisez les commandes zj et zk pour aller respectivement aux replis suivant et précédent, peu importe qu'ils soient ouverts ou fermés. Ces commandes devraient être faciles à retenir, puisqu'elles combinent la commande de repli z avec les commandes de déplacement j (une ligne vers le bas) et k (une ligne vers le haut). Si vous voulez vous déplacer au début ou à la fin d’un repli, utilisez respectivement [z et ]z. Il est bien sûr possible de répéter ces commandes en les préfixant d'un compteur.
Si le repli que vous venez d'ouvrir avec zo contient d'autres replis, ces derniers resteront fermés. Pour les ouvrir tous (le repli sous le curseur et ses sous-replis), tapez zO. Exécuter zc permet de fermer le repli qui est sous le curseur. zC permet de fermer tous les replis qui sont sous le curseur, faites quelques essais avec cette dernière pour bien comprendre son fonctionnement car dans certains cas, un seul repli est fermé.
La commande zr permet d'ouvrir un niveau de repli à la fois, tapez deux fois zr et deux niveaux de replis seront ouverts. Pour ouvrir récursivement tous les replis, tapez zR. La commande zm permet de fermer un niveau de repli à la fois, tapez deux fois zm et deux niveaux de replis seront fermés. Pour fermer récursivement tous les replis, tapez zM.
Pour supprimer un repli, placez le curseur sur le repli concerné puis tapez zd, pour supprimer un repli et tous ses sous-replis, tapez zD. Pour supprimer tous les replis du fichier, tapez zE. Ceci fonctionne que le repli soit ouvert ou non, cependant, supprimez les replis avec précaution car il n'est pas possible d'annuler la suppression d'un repli.
Vous vous demandez peut-être comment Vim traite le texte entre les replis quand vous effectuez une recherche ? Normalement. Si vous recherchez une chaine qui est dans un repli, Vim l'ouvrira et positionnera le curseur sur l'occurrence trouvée. Malheureusement, les replis ouverts lors d'une recherche ne sont pas refermés automatiquement. Cependant, un zM suffira à refermer tous les replis.
Vim traite aussi les replis fermés comme de simples lignes. Ainsi, si vous placez le curseur sur le repli fermé et que vous faites un dd, cela supprimera le repli ainsi que son contenu, pas simplement la première ligne. Vous pourrez aussi copier un repli fermé et tout son contenu via la commande yy, de la même manière qu'avec dd. Ce texte peut ensuite être collé via p.
L'option foldmethod
L’option 'foldmethod' est très intéressante pour les programmeurs. Par défaut, la méthode de repliage est manuelle. Cependant, Vim peut aussi créer les replis automatiquement en fonction de l'indentation du fichier, de sa syntaxe, ou de marqueurs présents dans le texte.
Pour utiliser la méthode de repliage basée sur l'indentation du fichier (pratique en python), il suffit de taper la commande :set foldmethod=indent. Cela va automatiquement créer les replis à chaque niveau d'indentation, en supposant que le fichier est correctement indenté. J'ai une petite préférence pour :set foldmethod=syntax car les replis sont créés à partir de la syntaxe du fichier (un 'if', un 'while', un commentaire...), donc même si votre fichier est mal indenté, les replis seront quand même créés correctement. Vraiment très pratique !
Un petit exemple pour bien voir à quoi ça ressemble :

Une fois que l'on a tapé la commande :set foldmethod=syntax, les replis sont créés automatiquement :

Ouverture d'un niveau avec zr :

Ouverture du niveau suivant avec zr encore :

Vim permet aussi de créer les replis via des marqueurs présents dans le texte. Pour passer en mode 'marker', tapez :set foldmethod=marker. Lorsque vous créerez un repli, vous verrez alors une marque avec trois accolades au début et à la fin du repli, comme ceci :

Un simple zr affiche ceci :

Ces marqueurs sont mis en commentaire pour ne pas générer d'erreur dans votre code, ceci dépend donc du type de fichier ouvert. Donc, si vous travaillez avec un fichier HTML, vous verrez des <!, et si vous éditez une feuille de styles CSS, vous verrez des {{{>/*{{{*/. Vous pouvez aussi insérer des marqueurs de repli manuellement si vous le voulez, Vim les reconnaitra tout aussi bien et il saura également les supprimer avec zd.
Les replis créés via la méthode 'marker' peuvent être annulés grâce à la commande u car ils agissent sur le contenu du fichier, contrairement aux autres méthodes.
Il est possible d'utiliser des marqueurs autres que {{{ et }}} pour créer les replis. Il suffit de faire un :set foldmarker=begin,end où begin représente la chaine marquant le début du repli, et end celui de fin du repli.
Si vous utilisez souvent les marqueurs, vous pouvez indiquer dans votre fichier .vimrc la méthode de repli que vous préférez :
set foldmethod=marker " par exemple.
J'aime bien utiliser les modelines avec les replis, c'est vraiment pratique. Elles permettent d'indiquer des options particulières à un fichier. Ces options sont écrites dans le fichier lui-même, tout au début. Par exemple, pour une page HTML, on pourra ajouter un commentaire contenant une modeline, comme dans l'exemple suivant.
[html]
<!-- vim: set foldmethod=marker: -->
<html>
<!--{{{-->
...
<!--}}}-->
</html>
Lorsque Vim ouvrira ce fichier, il se mettra en mode 'marker' et repliera donc les portions de texte contenues entre '{' et '
}'.
Sauver les replis
Vous avez passé beaucoup de temps à créer des replis, ce serait vraiment dommage de les perdre en fermant le fichier. Pour les sauvegarder, faites un :mkview puis fermez le fichier. Ouvrez de nouveau le fichier en question, puis faites un :loadview pour restaurer l'état des replis. Pour plus d'informations sur cette commande, :help :mkview.
Personnellement, je n'utilise pas la technique suivante, mais il est possible d'automatiser la sauvegarde et le chargement des vues en ajoutant les lignes suivantes au .vimrc.
au BufWinLeave * mkview au BufWinEnter * silent loadview
Maintenant, chaque fois que vous fermerez un fichier, l’état des replis sera sauvé. Cet état sera rechargé quand vous ouvrirez de nouveau le fichier dans Vim.
Résumé des commandes les plus utiles
zfcrée le repli en mode visuel ou avec un mouvement ;zoouvre le repli sous le curseur ;zcferme le repli sous le curseur ;zdsupprime le repli sous le curseur ;zjdéplace le curseur au prochain repli ;zkdéplace le curseur au précédent repli ;zRouvre tous les replis ;zMferme tous les replis ;zmaugmente le niveau de repli de un ;zrdiminue le niveau de repli de un ;zEsupprime tous les replis du fichier ;[zdéplace le curseur au début du repli ;]zdéplace le curseur à la fin du repli ;zOouvre tous les replis sous le curseur.
Conclusion
En général, vous n'utiliserez que les six premières commandes de la liste. N'oubliez simplement pas qu'elles commencent toutes par 'z'. Vous pouvez consulter l'aide en faisant un :help folding.
Vous pourrez approfondir le sujet avec le livre suivant : Learning the vi and Vim Editors.


Commentaires
Merci pour ton article ! C'est bête mais je ne connaissais pas zr et zm alors que j'utilise déjà fréquemment zR et zM, je vois mal comment je m'en passerai désormais =) Bonne continuation !
Bonjour, ton tutoriel m'a éclaircis les idées il y a quelques mois déjà
J'utilise souvent les repliements à l'aide de marqueurs, mais au final ça défigure un peu mes scripts ou des documents.
Alors je me suis dis que j'allais utiliser une méthode manuelle et sauvegarder mes folds dans un modeline à la fin du fichier.
Seulement lorsque j'ouvre le fichier, vim me donne une erreur car il ne connait pas la commande fold:
> Erreur détectée en traitant modelines :
> ligne 392 :
> E518: Option inconnue: 23,27fold
> Appuyez sur ENTRÉE ou tapez une commande pour continuer
J'utilise ce modeline:
> # vim:fdm=manual:23,27fold:
As-tu une idée sur comment forcer vim à interprêter les folds?
Merci
Il n'est à priori pas possible de faire ce que tu souhaites faire autrement qu'avec les 'markers'.
Il n'est pas possible d'utiliser des commandes autres que celles commençant par 'set' dans les modelines, pour des raisons de sécurité. Donc ce n'est pas possible, à moins qu'il y ait une fonction set ... qui permette de créer un repli.
Cependant, mkview et mksession pourraient permettre de combler ceci, moins pratique que les modelines, mais bon...
A vrai dire, j'avais dans l'optique d'échanger mes fichiers avec d'autres personnes.
L'enjeu des replis dans un modeline est simple: les gens qui n'utilisent pas vim ne sont pas gênés par des symboles qu'ils ne connaissent pas un peu partout, et l'affichage des replis serait facilement activable pour peu qu'on copie quelques lignes dans un .vimrc.
Le problème de mkview et loadview, c'est que les paramètres des replis (et beaucoup d'autres choses) sont enregistrés dans un fichier texte planqué au fin fond de ~/.vim/, donc c'est assez lourd à partager. De même, il suffit de renommer ou copier le fichier contenant les replis pour qu'il perde tout.
Comme tu dis, les commandes ne commençant pas par 'set' ne marchent pas, mais je vais essayer de trouver une solution. Je te tiens au courant à l'occasion