Blog tech

Faisons le point sur Vim

Rédigé par François Vantomme | 26 août 2015

On a l’habitude de lire et d’entendre que Vim est un éditeur difficile à prendre en main. Certes, Vim a une approche et une philosophie différentes de celles de la plupart des éditeurs de texte et IDE que nous connaissons. Cela demande un petit effort au début, mais cette apparente difficulté est vite surmontée.

Ce que je vous propose c’est d’apprendre ou ré-apprendre ensemble à utiliser Vim en comprenant sa philosophie plutôt qu’en le comparant à d’autres éditeurs. J’en profite pour remercier Drew Neil, dont le livre Practical Vim paru chez The Pragmatic Programmers m’a donné un regard neuf sur mon éditeur favori et m’a inspiré la rédaction de cet article et des suivants.

Prérequis

Il est fort probable que Vim soit déjà livré avec votre distribution si vous êtes sous GNU/Linux, dans le cas contraire, vous pouvez le télécharger depuis le site vim.org ou l’installer via la commande brew si vous êtes sous OSX :

❯ brew install vim

Partons sur de bonnes bases

Nous allons nous concentrer sur les mécanismes de base de Vim en mettant en avant ses concepts principaux. Ces mécanismes sont valables que vous utilisiez une instance locale de Vim dans votre terminal, à distance à travers une connexion SSH ou encore GVim.

Cependant, je ne compte pas ici présenter les fondamentaux de Vim. Un tutoriel très bien réalisé et disponible en français existe déjà et est livré avec Vim lorsque vous l’installez. Ce tutoriel est accessible en lançant la commande suivante dans votre terminal :

❯ vimtutor

De plus Vim étant extrêmement configurable et personnalisable, et la personnalisation étant quelque chose de très subjectif, nous ne rentrerons pas non plus dans le détail de ce qu’il faut mettre ou ne pas mettre dans son fichier de configuration .vimrc.

Un éditeur modal

Petit rappel pour ceux qui auraient survolé trop rapidement vimtutor, Vim est un éditeur modal. Cela signifie simplement que Vim dispose de plusieurs modes d’utilisation. En effet, les origines de Vi, le précurseur de Vim, remontent à des temps reculés où l’on ne trouvait de souris que dans les laboratoires. Du coup, pas de menu déroulant sur lequel cliquer frénétiquement, mais des modes Normal, Insert, Replace et Visual qui réagissent différemment aux délicates pressions que nous exerçons sur notre clavier.

Voici un petit résumé des modes disponibles et de leur utilité :

  • Normal : ce mode nous permet de nous déplacer dans le fichier et d’exécuter des commandes ;
  • Insert : ce mode est le plus habituel pour un éditeur, il nous permet d’insérer du texte dans le document ;
  • Replace : similaire au précédent, ce mode permet de remplacer le texte situé sous le curseur ;
  • Visual : ce mode permet de faire une sélection visuelle du texte.

Le mode par défaut est Normal. En mode Normal, il suffit de presser la touche i, R ou v pour entrer respectivement en mode Insert, Replace ou Visual. Pour repasser en mode Normal il suffit de presser la touche <ESC>.

Don’t Repeat Yourself

Éditer des fichiers a parfois des côtés très répétitifs. Nous effectuons de petits changements à différents endroits d’un fichier, voire de plusieurs à la fois. Nous effectuons en somme beaucoup de manipulations au sein de nos fichiers et nous aimerions bien les automatiser, les simplifier pour éviter d’avoir à se répéter. Ça tombe bien, Vim n’a qu’un souhait : répéter nos dernières actions !

Vim garde en mémoire nos derniers changements pour que nous puissions les rejouer d’une simple touche. Parfait, excellent me direz-vous ! Encore faut-il savoir “construire” ses commandes pour pouvoir tirer profit au maximum de cette fonctionnalité.

Un point c’est tout !

Avant d’expliquer ce que j’entend par “construire” une commande, faisons connaissance avec la commande ., l’une des commandes les plus utiles et puissantes de Vim.

La commande . (point) permet de répéter le dernier changement.

Qu’entend-t-on par “dernier changement” ? Potentiellement beaucoup de choses. Tâchons de voir ce que cela peut couvrir.

Mauvais caractère

La commande x supprime le caractère sous le curseur. Lorsqu’on utilise la commande . dans ce contexte, on va demander à Vim de supprimer de nouveau le caractère se trouvant sous le curseur.

Note : Dans les exemples ci-dessous, j’indiquerai à gauche les commandes exécutées et à droite le résultat, étape par étape. Pour aider à la compréhension, le caractère sous le curseur est signalé par une flèche.

        Ligne une
        ⇡
        Ligne deux
        Ligne trois
x       igne une
        ⇡
        Ligne deux
        Ligne trois
.       gne une
        ⇡
        Ligne deux
        Ligne trois
..      e une
        ⇡
        Ligne deux
        Ligne trois

Astuce : Nous pouvons restaurer l’état original du fichier en pressant la touche u plusieurs fois pour défaire les changements.

Point à la ligne

Un changement peut également s’opérer sur une ligne complète. Par exemple, nous pouvous supprimer la ligne sous le curseur avec la commande dd. Reprenons notre fichier :

        Ligne une
        ⇡
        Ligne deux
        Ligne trois
dd      Ligne deux
        ⇡
        Ligne trois
.       Ligne trois
        ⇡

Un point partout

Il est aussi possible d’effectuer un changement sur plusieurs lignes. Par exemple, nous pouvons décider d’indenter toutes les lignes depuis notre position courante jusqu’à la fin du fichier grâce à la commande >G.

        Ligne une
        Ligne deux
        ⇡
        Ligne trois
        Ligne quatre
>G      Ligne une
          Ligne deux
          ⇡
          Ligne trois
          Ligne quatre
j       Ligne une
          Ligne deux
          Ligne trois
          ⇡
          Ligne quatre
.       Ligne une
          Ligne deux
            Ligne trois
            ⇡
            Ligne quatre
j.      Ligne une
          Ligne deux
            Ligne trois
              Ligne quatre
              ⇡

Note : Comme vous avez pu le constater, la commande j (jump) utilisée ici déplace le curseur sur la ligne suivante.

Insert coin

Les commandes x, d, > sont réalisées en mode Normal, mais Vim considère aussi comme un changement, et un seul, tout ce qui se passe entre le moment où l’on entre en mode Insert et le moment où on le quitte.

            Le canard fait
                          ⇡
acoin<ESC>  Le canard fait coin
                              ⇡
.           Le canard fait coincoin
                                  ⇡

Note : On a vu que la commande i nous permet d’entrer en mode insertion. Ici nous utilisons la commande a qui va faire de même mais en nous positionnant après le caractère sous le curseur.

Point-virgule

Imaginons que nous souhaitions ajouter un point-virgule à la fin de chacune des lignes de notre fichier. Encore une tâche répétitive où la commande . va pouvoir s’illustrer. Mais posons nous quelques instants et réflechissons aux étapes nécessaires. Nous allons utiliser la commande $ pour se placer en fin de ligne, puis a qui nous permet d’insérer du texte après le curseur et enfin ;<ESC> pour insérer notre point-virgule et revenir en mode Normal. Nous n’avons ensuite plus qu’à utiliser la commande j$. pour répéter notre commande à la ligne suivante.

Alors effectivement, ça fait le boulot, mais ne pourrions nous pas économiser quelques touches ? Vim dispose en effet d’un certain nombre de commandes en combinant plusieurs autres. Ici, nous aurions pu utiliser A en lieu et place de $a. Un exemple plus complexe est la commande O qui est un raccourci pour ko ou k$a<CR>.

            var foo = 1
            ⇡
            var bar = 'a'
            var foobar = foo + bar
A;<ESC>     var foo = 1;
                       ⇡
            var bar = 'a'
            var foobar = foo + bar
j           var foo = 1;
            var bar = 'a'
                       ⇡
            var foobar = foo + bar
.           var foo = 1;
            var bar = 'a';
                         ⇡
            var foobar = foo + bar
j.          var foo = 1;
            var bar = 'a';
            var foobar = foo + bar;
                                  ⇡

Cela peut vite être fastidieux de répéter la commande j. sur chaque ligne. Une alternative serait d’effectuer une sélection visuelle des lignes que nous souhaitons modifier, puis de lancer la commande :'<,'>normal .. Ou bien plus simplement, si notre souhait est d’ajouter un point-virgule à chaque fin de ligne du fichier : :%normal A; suffit.

Petit décryptage. '<,'> signifie que notre commande s’applique sur la sélection en cours, alors que % indique que la commande s’applique sur l’intégralité du fichier. La commande normal indique que ce qui suit doit être exécuté en mode normal. Puis nous retrouvons notre A; qui ajoutera donc un point-virgule pour chaque ligne impactée par notre commande.

Un peu plus d’espace

Imaginons dans ce dernier exemple que nous souhaitons reformater une concaténation de chaînes de caractères pour la rendre plus lisible. Nous souhaitons ainsi insérer un espace avant et après le signe +. Voici une approche qui bénéficie de la puissance de notre commande préférée :

            var foo = "method("+argument1+","+argument2+")";
            ⇡
f+          var foo = "method("+argument1+","+argument2+")";
                               ⇡
s+<ESC>   var foo = "method(" + argument1+","+argument2+")";
                                 ⇡
;           var foo = "method(" + argument1+","+argument2+")";
                                           ⇡
.            var foo = "method(" + argument1 + ","+argument2+")";
                                              ⇡
;.          var foo = "method(" + argument1 + "," + argument2+")";
                                                   ⇡
;.          var foo = "method(" + argument1 + "," + argument2 + ")";
                                                               ⇡

Cela mérite quelques explications. La commande f{char} (forward) positionne le curseur sur la prochaine occurence du caractère {char}. La commande s (substitute) efface le caractère sous le curseur et entre en mode Insert. Nous insérons donc ⌴+⌴ et repassons en mode Normal. Ensuite la commande ; amène notre curseur sur la prochaine occurence du caractère recherché précédemment. Enfin nous répétons notre substitution grâce à la commande . et notre déplacement avec la commande ; et ainsi de suite.

Cette approche a l’avantage d’être répétable et, plutôt que de nous battre contre le mode Normal en basculant de celui-ci au mode Insert constamment, nous en faisons un allié et en tirons parti.

Conclusion

Nous n’avons fait que survoler Vim et ce avec un certain parti pris qui est de vous présenter la puissance et l’utilité d’une commande très simple et pourtant trop méconnue.

Volontairement, je ne vous ai pas listé les commandes les plus utilisées. Le tutoriel fait cela très bien et est une excellente mise en bouche. Je vous ai présenté des commandes au fur et à mesure pour illustrer mon propos afin de ne pas vous submerger de commandes dont vous oublirez les neuf dixièmes une fois la lecture de cet article achevée.

Nous avons mis l’accent sur le côté répétitif des opérations que nous pouvons avoir à faire sur un fichier. Et nous avons découvert comment rendre répétable nos actions afin de nous économiser en les réutilisant.

J’espère que cela vous a donné envie de découvrir ou redécouvrir Vim !

Nous aurons l’occasion dans de prochains articles d’aborder bien d’autres aspects fascinants de Vim. Ceux qui ont été attentifs remarqueront que je n’ai pas défini ce que j’entendais pas “construire” une commande. Patience, ce sera l’objet d’un prochain article. Si vous avez des suggestions ou remarques, n’hésitez pas à en faire part dans les commentaires.

L’équipe Synbioz.

Libres d’être ensemble.