Coloration syntaxique des templates Hugo dans Vim

Les templates des pages Hugo mêlent du HTML avec une syntaxe qui vient du langage Go. Et à l’écriture sous vim, petite surprise : il n’y a que les balises HTML qui sont correctement colorées :

La coloration syntaxique d'origine. Bien mais pas top : les balises HTML sont correctement colorées mais pas les bouts de templates Go.
La coloration syntaxique d'origine. Bien mais pas top : les balises HTML sont correctement colorées mais pas les bouts de templates Go.

Dans un template de page qui comprend peu d’éléments Go, cela reste lisible dans soucis. Mais dans certains cas, on va se retrouver avec un fichier assez complexe en instructions de templates sans une seule coloration. Et là, c’est tout de suite plus pénible.

Voyons comment améliorer les choses.

La solution simple et rapide

Il suffit d’installer le plugin Go pour Vim dans sa globalité.

Tout est expliqué correctement sur la page du projet, mais ce n’est pas cette solution qui m’intéresse.

La solution « complexe » et lente

Mais plus légère, et moins difficile qu’imaginé.

Après quelques recherches infructueuses contenant pas mal de résultats avec au choix un conseil sur un meilleur éditeur, ou bien une suggestion d’installer le greffon cité précédemment, je finis par tomber sur un article de blog datant de l’été 2022. Bon, ça parle surtout de NeoVim, mais c’est récent, et très certainement adaptable.

Cependant, avant de créer des dossiers à la racine du dossier ~/.vim et d’y déposer des fichiers, intéressons-nous à une nouveauté de la version 8 de vim : les paquets (ou « packages » en anglais).

Apparté sur les packages selon vim 8

Depuis cette version, il y a du nouveau dans les chemins de vim : ~/.vim/pack/<paquet>/start/<plugin>/.

Toute structure de sous-dossiers et vimscripts, à condition de respecter la hiérarchie de dossiers correcte, sera ajoutée aux éléments que vim va exécuter. Pratique, pour des extensions de capacité.

Ici, c’est un peu vague, mais un <paquet> peut contenir tous les plugins que l’on veut. Exemple :

~/.vim/pack/collection_base/start/plugin_un/
~/.vim/pack/collection_base/start/plugin_deux/
~/.vim/pack/collection_base/start/plugin_trois/

C’est plus proche d’une collection d’un certain nombre de plugins que l’on voudrait déployer sur plein de serveur (par exemple pour un parc informatique). Rien n’empêche d’avoir des plugins supplémentaires dans une seconde collection, optionnelle, que l’on ne déploierait que sur certaines machines. Exemple (en reprenant le précédent) :

~/.vim/pack/collection_base/start/plugin_un/
~/.vim/pack/collection_base/start/plugin_deux/
~/.vim/pack/collection_base/start/plugin_trois/
~/.vim/pack/collection_optionnelle/start/plugin_supp_un/
~/.vim/pack/collection_optionnelle/start/plugin_supp_deux/

Je vous renvoie à la documentation si vous voulez plus de détails.

Retour à notre problème

Étape 1 : on ouvre son terminal préféré.

Ensuite, direction le répertoire vim personnel : cd ~/.vim.

S’il n’existe pas, on se rajoute le sous-dossier des packages, ainsi qu’un premier niveau : mkdir -p pack/common/start. Sautez cette étape si vous avez déjà un dossier de paquets.

Tant qu’à faire, entrons-y : cd pack/common/start. Remplacez par le vôtre si vous avez déjà un dossier de paquets.

Créons un espace dédié pour cette extension : mkdir gohtmltmpl et allons-y : cd gohtmltmpl.

Créons les répertoires suivants :

mkdir ftplugin/
mkdir indent/
mkdir syntax/

Maintenant, il faut récupérer depuis le projet du plugin Go les fichiers gohtmltmpl.vim qui correspondent. Attention, il y a une subtilité : dans le dossier syntax il faut également récupérer et déposer gotexttmpl.vim.

Pour terminer, il faut créer un dossier ftdetect et y placer le code suivant dans un fichier gohtmltmpl.vim :

" Source : https://tech.serhatteker.com/post/2022-06/nvim-syntax-highlight-hugo-html/
function DetectGoHtmlTmpl()
    if expand('%:e') == "html" && search("{{") != 0
        setfiletype gohtmltmpl
    endif
endfunction

augroup filetypedetect
    " gohtmltmpl
    au BufRead,BufNewFile *.html call DetectGoHtmlTmpl()
augroup END

C’est terminé.

Nous avons donc :

.vim/pack/common/start/gohtmltmpl/
├── ftdetect
│   └── gohtmltmpl.vim
├── ftplugin
│   └── gohtmltmpl.vim
├── indent
│   └── gohtmltmpl.vim
└── syntax
    ├── gohtmltmpl.vim
    └── gotexttmpl.vim

Le résultat

Un redémarrage de vim plus tard, voici ce que cela donne :

La coloration syntaxique améliorée. Les éléments du langage de template de Go sont maintenant reconnus et colorés.
La coloration syntaxique améliorée. Les éléments du langage de template de Go sont maintenant reconnus et colorés.

C’est tout de même mieux ! Surtout sur les shortcodes et autres partials qui peuvent ne contenir quasi que des éléments de template Go, sans un seul bout de html. Voici un exemple :

Exemple d'un 'partial' correctement colorisé ne contenant que des instructions de template Go.
Exemple d'un 'partial' correctement colorisé ne contenant que des instructions de template Go.

Réflexion sur le sujet

Évidemment, la solution que j’ai préférée mettre en place comporte quelques inconvénients.

Dans un premier temps, plus d’opérations (manuelles) à effectuer pour la mise en place. Ensuite, je n’aurais pas les éventuelles mises à jour de syntaxe et corrections de bugs. Encore que, on peut tirer directement avec git et faire régulièrement ce qu’il faut.

Cela dit, une fois que c’est fait, la solution est autonome. Pas besoin de brancher ça sur un gestionnaire de greffons, ni d’installer tout un outillage dédié à Go, alors que je voulais juste la coloration des templates pour Hugo. De plus je prends le pari que le moteur de templates ne va pas changer radicalement du jour au lendemain.

À vous de peser le pour et le contre, mais je pense que dans un cadre où l’on ne développe pas en Go, il est inutile de tirer autant de ressources pour ensuite coloriser un seul type de fichiers.

Et pour voir plus loin, en vrai, quand on rajoute des plugins stables, qu’on en fait un miroir sur un autre dépôt (le sien ou un dans un cadre pro), ou qu’on les partage avec plusieurs machines, cette organisation de dossiers est clairement plus propre, car elle isole réellement les éléments les uns des autres. Au prix de quelques sous-dossiers supplémentaires cela dit.

Maintenant que j’ai découvert cette fonctionnalité et fait ça sans passer par Plug, je me demande si je ne vais pas complètement m’en passer.

Affaire à suivre.

Liens