VIM et les feuilles de style
Bien évidemment, VIM connaît déjà les fichiers CSS. Votre code sera coloriés et vous disposez de l'auto-complètement des propriétés ET de leurs valeurs par Control-x Control-o. Mais cet éditeur permet de faire tellement plus pour nous simplifier la vie qu'il serait dommage de ne pas pousser tout cela un peu plus loin...
Faire ses courses
Avant de commencer à personnaliser, voyons un peu ce qu'offre l'écosystème VIM concernant les feuilles de style.
- Pour gagner un peu de temps, vous pouvez utiliser l'incontournable Snipmate pour définir des portions de code utilisées de manière récurrente.
- Par défaut, VIM comprend la syntaxe CSS 2.0. Pour monter d'un cran, vous devrez installer un plugin comme VIM CSS3 Syntax qui est plutôt complet. Un autre plugin sans doute plus léger, Better CSS Syntax for VIM. C'est celui que j'utilise. En revanche, cela va upgrader la syntaxe (colorisation), mais pas l'auto-complètement.
- vim css color va quant à lui générer dynamiquement le rendu visuel des couleurs que vous saisissez. Ainsi, sous gVim, #FF0000 apparaîtra en rouge, #00FF00 en vert, etc. Attention cependant, cela peut vite devenir lourdingue avec des fichiers CSS fleuves ;-). Une version alternative à ce plugin est Color Highlight qui lui fonctionne avec tous les types de fichiers. Il suffit de tapper LEADER cC pour activer/désactiver la colorisation. Et cerise sur le gâteau, il fonctionne aussi avec Vim en mode terminal (aux approximation prés évidemment).
Configuration d'un plugin pour le type de fichier CSS
Bon tout ceci est bien beau, mais comment aller un peu plus loin et ajouter sa touche perso là-dedans.
Comme vous le savez peut-être déjà, VIM dispose d'un mécanisme bien pratique permettant de déclarer un script qui se lancera uniquement à l'ouverture d'un type de fichier donné. Ce genre de script est à ranger dans le dossier ~/.vim/ftplugin/.
Pour que ceci fonctionne, il faut que vous ayez Proprement configuré vim avec la ligne suivante dans votre ~/.vimrc
filetype plugin indent on
Définition des mots-clefs
Première chose qui agace, la sélection d'un sélecteur sous le curseur ne prend pas le # ou le .. La sélection d'un mot en VIM, consiste à taper la commande viw (v passe en sélection visuelle, et iw pour Inner Word). Un raccourcis connu de cette sélection consiste à double-cliquer sur le mot.
Le concept de "mot" en VIM, est régit par le réglage iskeyword. Ce réglage contient tous les caractères qui définissent un mot. Nous allons donc y ajouter les caractères -, # et .. Pour cela, nous allons créer notre fichier ~/.vim/ftplugin/css.vim
setlocal iskeyword+=.,-,#
Notez l'usage de setlocal au lieu du classique set qui permet d'appliquer le réglage uniquement sur le buffer en cours. Ensuite le += qui permet non pas d'écraser ce que contient déjà le réglage mais juste d'y ajouter des choses. Et enfin les 3 caractères séparés par des virgules.
Une fois le fichier sauvegardé, il vous suffit de retourner sur le fichier CSS et de forcer sa relecture (commande e!) pour que le ftplugin/css.vim soit lu et la variable définie pour le buffer. Maintenant si vous double-cliquez sur un sélecteur, il doit être sélectionné en entier.
Contracter - Décontracter
En bon développeur Java de base, lorsque je voyais des fichiers CSS arriver avec toutes les propriétés d'un sélecteur sur une seule ligne, je hurlais au scandale. Avec le temps je me suis rendu compte que c'était finalement bien pratique comme notation, sous réserve de pouvoir facilement développeur une ligne puis la re-compresser.
/* version compressée */
#mon-selecteur { border:1px solid red; background-color:green }
/* version décompressée */
#mon-selecteur {
border:1px solid red;
background-color:green
}
Nous allons donc créer deux mappings permettant d'effectuer ces opérations. D'abord la compression :
map <silent> <buffer> Œ /}<CR>V?{<CR>J:let @/=""<CR>
le choix de Œ (aka Shift-œ) est très personnel. C'est la touche au dessus du Tab qui ne me sert pas à grand chose en mode "normal".
La commande map permet de définir un mapping, c'est à dire la correspondance entre une série de touches (ici œ) et un série de commandes. Vous pouvez voir cela comme une macro car vous pourriez aussi bien taper tout ce qui suit après le œ à la main.
map s'applique au mode "normal" de VIM. C'est à dire que la touche œ reste disponible en mode "insertion" (ouf ! ;-).
silent demande à VIM de ne pas afficher chaque séquence composant la macro. Enfin buffer indique à VIM que ce mapping doit être local au buffer en cours. Cette macro ne fonctionnera donc que dans un fichier CSS.
Maintenant voyons la macro à proprement parler. /}
La commande V passe en mode "sélection visuel par ligne". La commande ?{ fonctionne comme /} mais à l'envers. C'est à dire que VIM va chercher la première accolade ouvrant qui se trouve avant le curseur. Comme on est en mode visuel, cela revient à sélectionner toutes les lignes entre les deux accolades, celles-ci comprises.
La commande J va fusionner les lignes de la sélection et tout mettre donc sur une seule. J a en plus le bon goût de compresser les espaces de sorte à n'en laisser qu'un seul entre chaque fusion. Ainsi nous compressions les éventuelles indentations.
Pour finir, la commande :let @/="" affecte une chaine vide au registre de recherche /. Ce n'est utile que si vous avez activé la colorisation de la recherche par set hlsearch.
Pour la décompression de la ligne, le travail est un peu plus simple.
map <silent> <buffer> œ V:s/\\v[{;]\\s*/\\0\\r<CR>V%=:let @/=""<CR>
La commande V passe en mode visuel et sélectionne du coup la ligne à décompresser. Ensuite une simple commande de remplacement pour rajouter des retours chariot après les ; et les {. Petites astuces, le \\v permet de contraindre VIM à ne pas utiliser son mode "magique" pour les expressions régulières, adoptant ainsi une syntaxe plus classique et plus simple (à mon goût). Enfin \\0 renvoie ce qui a été trouvé, soit ; ou { selon les cas.
Pour terminer, V%=. Vous l'aurez maintenant compris, le V passe en sélection par ligne. La commande % permet de sauter d'une accolade à l'autre. Comme le traitement précédent s'achève sur l'accolade finale, ça va sélectionner le bloc de propriétés décompressées. Enfin le = permet de ré-indenter le bloc de code. Le mapping se termine ici aussi sur un let @/="" pour vider le registre de recherche.
C'est toujours assez impressionnant de voir le volume de texte nécessaire pour décrire une simple série de commandes VIM :-).
Gérer les "vendor-prefixes"
Si vous manipulez régulièrement des feuilles de styles, je ne vais pas présenter les -moz-machin-chose et autre joyeusetés qui les polluent régulièrement. Vous savez déjà que c'est un petit enfer à gérer car on se retrouve à décrire 10 fois le même comportement, une fois par navigateur et parfois par version de navigateur.
Pour les vendor prefixes qui correspondent à des propriétés CSS 3.0 (box-shadow, linear-gradient, etc.), il existe un petit outil bien pratique, cssprefixer, qui permet de n'avoir QUE le CSS3 à saisir, cette moulinette se chargeant de compléter avec tout le reste. Magique et bien moins casse-figure que des outils en javascript comme prefixfree.
CssPrefixer a cependant deux soucis. Le premier est qu'il n'aime pas qu'il y ait déjà des vendor prefixes avant d'opérer. Le second est qu'il ne bosse que sur des fichiers css et nom sur des portions.
Nous allons commencer par un petit mapping pour supprimer mes -moz-machin-chose.
map <silent> <buffer> - /}<CR>V?{<CR>:g/\\v-(moz\\|webkit\\|o)-/d<CR>
Cette fois le mapping est associé à la touche - (pour "supprimer les préfixes"). Le début est le même que pour la compression. La différence ici est la commande :g qui au lieu de substituer va appliquer une commande à toutes les lignes qui vont être trouvées. Ici la commande est d pour "supprimer". Ce mapping va donc, curseur placé dans un bloc de propriétés contenant des vendor prefixes, les supprimer sans pitié.
Maintenant pour le mapping qui va faire appel à cssprefixer :
map <buffer> + -:call writefile(split(@*,"\\n"),"/tmp/css-source")<CR>gv!cssprefixer /tmp/css-source<CR>
Bon c'est du lourd, petite explication :-)
Commençons par la commande - qui n'est autre que notre précédent mapping de suppression de vendor prefixes. On aurait pu faire un seul mapping mais il est pratique de pouvoir "nettoyer" ainsi les blocs des préfixes parasites, ne serait-ce pour y voir clair.
Suit la commande :call writefile(split(@*,"\\n"),"/tmp/css-source"). C'est la fameuse création de fichier (writefile). Les données de ce fichier sont issues du registre *, celui de la sélection. @* renvoie le contenu de ce registre (comme @/ vu plus haut). Quelle sélection me direz-vous ? Et bien celle crée par le mapping - pardi :-)
Ensuite nous faisons appel à la commande gv qui rend à nouveau active cette fameuse dernière sélection (très pratique !!). Ensuite nous appelons la commande cssprefixer avec le fichier temporaire en paramètre. Le bang ! utilisé sur une sélection, permet de remplacer la dite sélection par le texte renvoyé par la commande. Le tour est donc joué.
Conclusion
Vous l'aurez compris, le thème "CSS" de cet article est avant tout un prétexte pour présenter ce que l'on peut faire avec VIM. Tout ce qui se trouve ici peut être appliqué à n'importe quel type de fichier pour fluidifier au mieux votre workflow. De même toute les commandes encapsulées dans mappings peuvent être utilisées individuellement pour votre édition quotidienne.
Maintenant, je m'arrête un peu avant l'indigestion, mais il y aurait encore pas mal de chose à dire. Il est ainsi possible de modifier l'auto-complètement de VIM juste pour le CSS de sorte à déclencher sur une propriété *-color: l'affichage d'un sélecteur de couleur. Il est aussi possible de connecter VIM et firefox de sorte à ce qu'en pressant F5 dans une feuille de style, cela recharge juste cette feuille dans le navigateur. Si cela vous intéresse je pourrais vous en parler une prochaine fois.