mardi 13 octobre 2015
Ce billet a été vu pour la première fois sur le blog de Synbioz le 13 October 2015 sous licence CC BY-NC-SA.

Vim, passez à l'action !

Chose promise, chose due ! Dans la première partie de cette série d’articles traitant de notre éditeur favori — intitulée Faisons le point sur Vim — j’ai mentionné la construction de commande et je m’étais engagé à vous expliquer cette notion. Soyons plus précis : nous nous focaliserons ici sur les commandes nous permettant de réaliser une action sur le texte de notre fichier. Nous appellerons ce type de commande une action. Sans plus attendre, décomposons-la.

Opérateur + Mouvement = Action

Une action peut être décomposée en deux parties : l’opérateur (operator) et le mouvement (motion). Vim tire sa force de la manière dont les opérateurs et les mouvements peuvent être combinés. Voyons comment cela fonctionne et quelles en sont les implications.

La commande d{motion} peut opérer sur un simple caractère (dl), un mot entier (daw) ou tout un paragraphe (dap). Son champ d’application est défini par le mouvement (motion). Il en va de même pour la commande c{motion}, y{motion} et bien d’autres. Ces commandes sont appelées des opérateurs.

Voici une liste des opérateurs les plus courants :

Opérateur Effet
c Changer (change)
d Effacer (delete)
y Couper (yank) et mémoriser dans un registre
g~ Alterner la casse (majuscule / minuscule)
gu Convertir en minuscule
gU Convertir en majuscule
> Décaler vers la droite
< Décaler vers la gauche
= Indenter automatiquement

L’on remarque que certains opérateurs sont composés de g suivi d’un caractère. Nous pouvons simplement considérer g comme un préfixe altérant le comportement du caractère qu’il précède.

Un peu de grammaire

La combinaison d’opérateurs et de mouvements constitue une sorte de grammaire. La première règle est simple. Nous l’avons vu, il suffit d’adjoindre un mouvement à un opérateur. Ainsi, lorsque nous découvrons de nouveaux opérateurs ou de nouveaux mouvements à mesure de notre apprentissage de Vim, nous acquérons davantage de vocabulaire. Avec ce vocabulaire et la connaissance de la grammaire, nous pouvons construire de nouvelles actions.

Supposons que nous sachions déjà effacer un mot à l’aide de l’action daw et que nous découvrions l’existence de la commande gU. Connaissant la grammaire de Vim, nous pouvons en déduire l’action gUaw qui va convertir le mot sous le curseur en majuscule.

Des mouvements fluides et précis

Par défaut, lorsque nous exécutons une action, celle-ci commence sous le curseur et prend fin à l’endroit défini par son mouvement. Par exemple, l’action dw va supprimer tous les caractères depuis celui sous le curseur jusqu’à la fin du mot. Nous avons pourtant utilisé dans les exemples précédents le mouvement aw. Qu’est-ce que cela ? Vim fait référence à ces mouvements sous le nom de text objects. Ils sont composés de deux caractères dont le premier est forcément soit i, soit a. Ils permettent respectivement d’effectuer une sélection en excluant le délimiteur ou en l’incluant. Pour vous en souvenir, dites-vous que i signifie à l’intérieur (inside) et a autour (around ou all).

Voici donc les text objects que nous pouvons rencontrer :

Text Object Sélection
iw Mot courant
aw Mot courant plus un espace
iW MOT courant
aW MOT courant plus un espace
is Phrase courante
as Phrase courante plus un espace
ip Paragraphe courant
ap Paragraphe courant plus une ligne blanche

D’un mot à l’autre

La différence entre un mot et un MOT tient de la manière dont nous définissons ce qu’est un mot. Prenons un exemple.

p.s. s'agit-il d'un mot ?

Combien de mots avez-vous compté ? Cinq ou douze ? Quelque chose entre les deux ? Et bien il y a là cinq MOTS et douze mots. La ponctuation compte comme des mots, donc si nous parcourons la ligne mot par mot, voici ce qu’il se passe :

        p.s. s'agit-il d'un mot ?
        ⇡
wwww    p.s. s'agit-il d'un mot ?
             ⇡
www     p.s. s'agit-il d'un mot ?
                       ⇡

Voyons voir maintenant ce qu’il se passe si nous parcourons cette même ligne MOT par MOT :

        p.s. s'agit-il d'un mot ?
        ⇡
W       p.s. s'agit-il d'un mot ?
             ⇡
W       p.s. s'agit-il d'un mot ?
                       ⇡

Vim nous offre donc un outil d’une extrême précision pour effectuer les actions les plus subtiles. Mais pourquoi s’arrêter en si bon chemin ?

Les text objects sous stéroïdes

Voilà que vous m’apostrophez ! Non pas pour me donner l’accolade, mais pour me faire remarquer, entre parenthèses, que vous êtes développeur et pas écrivain. Et que des mots, des paragraphes, tout ce beau monde est bien joli mais que ça n’arrange pas vos affaires quand vous avez un gabarit HTML sous les yeux !

Qu’à cela ne tienne, prenons un exemple et voyons ce que Vim nous réserve :

        var tpl = [
          '<a href="{url}">{title}</a>'
                      ⇡
        ]
vi}     var tpl = [
          '<a href="{url}">{title}</a>'
                     •—⬏
        ]
a"      var tpl = [
          '<a href="{url}">{title}</a>'
                   •—————⬏
        ]
i>      var tpl = [
          '<a href="{url}">{title}</a>'
            •————————————⬏
        ]
it      var tpl = [
          '<a href="{url}">{title}</a>'
                           •—————⬏
        ]
at      var tpl = [
          '<a href="{url}">{title}</a>'
           •—————————————————————————⬏
        ]
a]      var tpl = [
                  •
          '<a href="{url}">{title}</a>'
          —————————————————————————————
        ]
        ⬏

Habituellement, lorsque nous entrons en mode visuel, un bout de la sélection est ancrée sur un caractère et l’autre extrémité est mobile. Ainsi lorsque nous utilisons des mouvements tels que l ou w, nous déplaçons cette extrémité mobile.

Ce qui se passe ici est différent. Nous demandons à Vim de sélectionner tout ce qui se trouve à l’intérieur des accolades grâce à la commande vi}. Puis nous étendons la sélection au contenu des guillemets, guillemets compris avec a". Puis à l’intérieur des chevrons à l’aide de i>. Ensuite nous décidons de sélectionner le contenu de la balise (tag) avec it. Puis nous nous ravisons et optons pour la balise dans son ensemble avec at. Pour finalement choisir de sélectionner les crochets et leur contenu avec la commande a].

Nous retrouvons ici nos préfixes i et a accolés à des délimiteurs d’un nouveau genre dits “de bloc”. En voici une liste partielle.

Text Object Sélection
a) ou ab Autour d'une paire de (parenthèses)
i) ou ib À l'intérieur d'une paire de (parenthèses)
a} ou aB Autour d'une paire d'{accolades}
i} ou iB À l'intérieur d'une paire d'{accolades}
a] Autour d'une paire de [crochets]
i] À l'intérieur d'une paire de [crochets]
a> Autour d'une paire de <chevrons>
i> À l'intérieur d'une paire de <chevrons>
a’ Autour d'une paire de 'guillemets simples'
i’ À l'intérieur d'une paire de 'guillemets simples'
a" Autour d'une paire de "guillemets doubles"
i" À l'intérieur d'une paire de "guillemets doubles"
a` Autour d'une paire de `backtick`
i` À l'intérieur d'une paire de `backtick`
at Autour d'une paire de <xml>balises</xml>
it À l'intérieur d'une paire de <xml>balises</xml>

Il est à noter que l’on peut indifféremment utiliser i) ou i( et il en va de même pour les autres délimiteurs de bloc.

Bien entendu, il est possible d’effectuer des actions avec ces text objects avancés. Voyons comment remplacer le contenu générique d’un gabarit :

              '<a href="{url}">{title}</a>'
                          ⇡
ci"#<Esc>     '<a href="#">{title}</a>'
                        ⇡
citici<Esc>   '<a href="#">ici</a>'
                             ⇡

Nous pouvons interpréter ces commandes ainsi : “changer à l’intérieur des double guillemets”, puis “changer à l’intérieur de la balise”.

Peut-on aller plus loin ?

Vous n’avez pas trouvé votre bonheur ? Vous souhaiteriez définir d’autres opérateurs ? D’autres délimiteurs ? Et bien c’est tout à fait possible ! C’est d’ailleurs ce qu’ont fait certains contributeurs comme Tim Pope avec son plugin commentary.vim qui définit un nouvel opérateur gc. Ainsi, l’action gcap par exemple, commentera le paragraphe sous le curseur. Kana Natsuno a quant à lui créé deux nouveaux text objects avec son plugin vim-textobj-entire : ae et ie qui agissent sur le fichier tout entier.

Conclusion

Nous avons ainsi vu comment, avec une grammaire succincte et finalement assez peu de vocabulaire de base, Vim nous offre une grande souplesse dans les actions que nous pouvons effectuer sur nos fichiers.

J’espère que cet article vous a donné envie d’explorer Vim davantage !