Piloter `zig fmt`
(matklad.github.io)zig fmtpeut servir de formateur pilotable capable de disposer un même code selon plusieurs mises en page en se basant sur la forme syntaxique déjà présente dans le fichier- Dans les appels de fonction, la présence ou l’absence d’une trailing comma modifie le résultat : sans virgule, tout est fusionné sur une ligne ; avec une virgule, les arguments sont placés chacun sur leur propre ligne
- En pratique, le flux consiste à choisir d’abord la disposition de code souhaitée, à ajouter quelques virgules, puis à utiliser le raccourci de formatage pour laisser
zig fmtgérer le reste - Dans les tableaux, en plus de la trailing comma, la position du premier saut de ligne est également prise en compte : si le premier saut de ligne vient après le troisième élément, l’alignement se fait ensuite par groupes de 3 éléments
- En utilisant
++avec précaution pour concaténer des tableaux, on peut varier le nombre d’éléments par ligne ; lors du passage de paires--keyetvalueà un subprocess, on peut concaténer un tableau d’arguments fixes et un tableau de paires d’options pour obtenir un alignement propre
Comment piloter zig fmt
zig fmtpeut être utilisé comme un formateur pilotable, car il peut disposer une même syntaxe de différentes façons en observant la forme syntaxique déjà présente dans le fichier- Dans les appels de fonction, la présence ou l’absence d’une trailing comma change la mise en page
f(1, 2, 3); // -> zig fmt -> f(1, 2, 3);f(1, 2, 3,); // -> zig fmt -> f( 1, 2, 3, ); - Dans l’usage réel, on choisit d’abord la disposition de code voulue, on ajoute quelques
,, puis on appuie sur le raccourci de formatage pour laisserzig fmtfaire le reste - Plutôt que de laisser le formateur deviner la mise en page, il peut être plus pertinent de laisser l’utilisateur expliciter lui-même les choix essentiels
- La conclusion est que 90 % d’un bon formatage dépend des lignes vides entre les blocs logiques et du choix judicieux de variables intermédiaires ; mieux vaut donc exploiter ces choix que chercher à les éliminer
Mise en page alignée en colonnes pour les tableaux
- Dans les tableaux,
zig fmtne se contente pas de la trailing comma pour placer un élément par ligne : il prend aussi en compte la position du premier saut de ligne.{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, }; - Si le premier saut de ligne intervient après le troisième élément, le résultat est lui aussi aligné par groupes de 3 éléments
.{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, }; - En utilisant avec soin la concaténation de tableaux via
++, on peut obtenir un nombre d’éléments différent selon les lignes - Lorsqu’on passe à un subprocess des paires
--keyetvalue, on peut concaténer un tableau d’arguments fixes et un tableau de paires d’options pour les aligner comme suittry run(&(.{ "aws", "s3", "sync", path, url } ++ .{ "--include", "*.html", "--include", "*.xml", "--metadata-directive", "REPLACE", "--cache-control", "max-age=0", }));
1 commentaires
Commentaires sur Lobste.rs
Il me semble que
gofmtavait lui aussi un comportement de guidage de mise en forme similaire, et je préfère ce genre de formateur àrustfmtCela dit, j’estime quand même qu’une forme quelconque d’automatisation de la mise en forme vaut mieux que l’absence totale de formateur
Les formateurs automatiques imposent la banalité, tirent vers le haut ceux qui ne savent pas mettre en forme, mais tirent aussi vers le bas ceux qui le font bien
J’en utiliserais en collaboration si les autres le souhaitent ou si je ne peux pas faire confiance à leur discipline personnelle en matière de style, mais seul je n’en utiliserais jamais
J’ai mes préférences, le formateur a les siennes, et elles sont inconciliables
Cela dit, ce que montre cet article est en soi impressionnant
Cette phrase me rappelle la réplique de Yente la marieuse dans Fiddler on the Roof : « Même un mauvais mari — que Dieu nous en préserve — vaut mieux que pas de mari du tout ! »
clang-formatsur certains projets C++, et c’est affreuxLa stabilité entre versions est si faible qu’une mise à niveau de
clang-formatse traduit par un commit de mise en forme touchant chaque ligne du codeJe ne suis vraiment pas sûr que ce soit mieux que de ne pas avoir de formateur du tout
Les formateurs automatiques résolvent surtout un problème humain : éliminer les discussions stériles sur les pull requests
Mais avec le passage au développement agentique, ce problème devient de moins en moins important
Sur plusieurs projets, les machines font déjà l’essentiel du travail, et dans ce contexte j’ai de plus en plus l’impression qu’il vaut mieux ne pas lancer de formateur du tout
En Python, quand je construis des arguments de ligne de commande, j’aime bien éclater des tuples dans une liste, donc j’écrirais probablement le dernier exemple de l’article comme ceci
La dernière fois que j’ai regardé,
zig fmtne permettait pas de configurer une limite à 80 colonnes au lieu de 100 ; est-ce toujours le cas ?Quand on travaille plusieurs heures par jour, les yeux fatiguent moins si on augmente la taille de la police du terminal, et la différence entre 80 et 100 colonnes détermine si l’on peut afficher côte à côte deux splits
vimetnerd treezig fmtn’a pas de limite de colonnesEn tant que personne ayant introduit un rigid formatter dans une équipe qui n’avait jusque-là aucun formateur, la possibilité d’influencer manuellement la mise en forme me manque parfois
De ce point de vue, la souplesse de Zig est vraiment géniale
Excellent !
Existe-t-il un formateur TS/JS de ce genre ?
J’ai un projet qui utilise
maplibre-gl, et les expressions de la spécification de style sont parfois tellement reformatées qu’on n’y voit plus rienJ’ai arrêté d’utiliser un formateur pour l’instant, mais entre le débogage, le copier-coller et les mises en commentaire, le code devient sale
Peut-être qu’on pourrait même faire en sorte que le formateur Zig mette en forme d’autres langages aussi :)
Il n’existe par exemple aucun moyen d’indiquer au formateur d’en mettre quatre par ligne
De plus, si un objet littéral devient trop long, Prettier finit par le convertir en mode « un élément par ligne », quelle que soit la forme du texte d’entrée
J’ai déjà été déçu par les formateurs légers, en pratique des formateurs qui ne font que couper les lignes, donc l’idée d’avoir cette souplesse à l’intérieur d’exemples plus stricts me plaît et me rend envieux :p
Récemment, en répondant sur le fediverse à une question sur l’écriture et la mise en forme de Lisp avec une police proportionnelle, j’ai évoqué des variantes de s-expressions qui utilisent des espaces significatifs, à savoir wisp, Readable/Sweet expressions, ainsi que les SRFI 119 et 110
J’ai aussi fait remarquer que cette famille de syntaxes redonne un certain contrôle sur les retours à la ligne grâce à des extensions optionnelles de notation infixe
La conception est intéressante, mais je ne sais pas si elle me plaît
Dans mon formateur, je fais autrement : le formateur ignore les virgules finales pour décider de la mise en forme, puis ajoute toujours une virgule finale si le résultat est sur plusieurs lignes, et la supprime toujours si tout tient sur une ligne
Du coup, il n’y a pas de « guidage », mais
f(1, 2, 3)est formaté de manière cohérente quelle que soit la présence d’une virgule finale ou la quantité et le type d’espaces entre les tokensUn certain degré de guidage est nécessaire
Par exemple, si l’on a un long littéral de liste
[<expr1>, <expr2>, ..., <expr100>], la plupart des formateurs mettront probablement chaque expression sur sa propre ligne, alors qu’on peut vouloir en mettre autant que possible sur une même ligneDécider cela via la virgule finale me paraît étrange, et plus généralement le nombre de choix possibles peut être N et non 2
Pour ce genre d’objectif, des attributs me semblent mieux adaptés
Par exemple, cela existe peut-être déjà, mais on pourrait imaginer quelque chose comme
#[rustfmt::list_layout(flow)]avant une instruction pour influencer la mise en forme des littéraux de liste à l’intérieur de cette instructionTrop de guidage finit par nuire au but d’un formateur, qui est de rendre la mise en forme du code cohérente à l’échelle de tout l’écosystème et de faciliter la revue de code ; il faut donc limiter cela à des cas précis
Les longs littéraux de liste me semblent être un exemple réellement valable
J’ai aussi dans mon projet un cas où la mise en forme aide à relire des valeurs attendues de tests, comme ici
Il me vient aussi à l’esprit un autre comportement de « guidage » dans le formateur Dart : dans un long littéral de liste, on peut ajouter des lignes de commentaires pour regrouper les lignes
Par exemple, avec
[1, 2, 3, ..., 1000], le formateur mettrait normalement un élément par ligne, mais on peut regrouper manuellement ainsiJe ne sais pas si cette fonctionnalité a été introduite intentionnellement ou si c’est un sous-produit de la façon dont les commentaires sont gérés
rustfmtse comporte, et ça me rend fouIl arrive parfois qu’il soit plus lisible de ne pas éclater un appel de fonction, même si cela dépasse la limite de longueur de ligne, et j’aimerais pouvoir refléter mon propre jugement là-dessus
Un cas qui me vient à l’esprit est OpenGL
En général, quand on modifie ou utilise une même ressource, par exemple lors de l’initialisation d’une texture, on enchaîne beaucoup d’appels
gl.*, etrustfmtpousse cela sans la moindre sensibilité, avec pour seul objectif robotique « ligne trop longue, il faut couper »Cet exemple est artificiel, fait pour illustrer le comportement, et ne correspond pas exactement au comportement réel de
rustfmtLes lignes ne sont d’ailleurs pas si longues
J’écris sur mon téléphone en ce moment, donc je n’ai pas les outils pour produire un exemple 100 % fidèle Découper une suite d’appels
gl.tex_parameteride cette manière sur plusieurs lignes est en réalité moins bon que de laisser chaque appel entièrement sur une ligneSi les colonnes sont alignées, il est beaucoup plus facile de repérer la différence entre les deux lignes
La version éclatée réduit la proximité visuelle et est plus difficile à lire
On ne peut plus comparer facilement les deux lignes d’un simple coup d’œil
Il y a aussi des cas ridicules où l’outil échoue complètement lorsqu’il ne parvient pas à reformater quelque chose dans la limite de caractères imposée
Cela m’arrive souvent en écrivant du code de compilateur avec des messages de diagnostic sous forme de littéraux de chaîne, car ces messages peuvent être assez longs
rustfmtne sait alors pas comment les couper, abandonne et cesse de formater l’instruction entièreCela ressemble souvent à ceci Ici, sous prétexte que l’appel à
emit_diagnosticn’est qu’une expression, il renonce à formater l’instructionmatchentière, ce qui est tout simplement stupideTout cela aurait pu être évité s’il n’avait pas essayé d’imposer à tout prix une largeur maximale de 100 colonnes à mon code
Pour ceux qui, comme moi, ont dû chercher après avoir lu le commentaire de fin :
++est l’opérateur de concaténation de tableauxDonc si l’on sépare un tableau en deux, on peut les faire formater différemment