1 points par GN⁺ 2 시간 전 | 1 commentaires | Partager sur WhatsApp
  • zig fmt peut 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 fmt gé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 --key et value à 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 fmt peut ê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 laisser zig fmt faire 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 fmt ne 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 --key et value, on peut concaténer un tableau d’arguments fixes et un tableau de paires d’options pour les aligner comme suit
    try run(&(.{ "aws", "s3", "sync", path, url } ++ .{
        "--include",            "*.html",
        "--include",            "*.xml",
        "--metadata-directive", "REPLACE",
        "--cache-control",      "max-age=0",
    }));
    

1 commentaires

 
GN⁺ 2 시간 전
Commentaires sur Lobste.rs
  • Il me semble que gofmt avait lui aussi un comportement de guidage de mise en forme similaire, et je préfère ce genre de formateur à rustfmt
    Cela 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

    • La formule « n’importe quel formateur vaut mieux que pas de formateur du tout » ne passe pas si facilement
      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 ! »
    • Si je me souviens bien, le formateur Elm fonctionnait lui aussi de manière similaire, et je le trouvais nettement meilleur que les formateurs qui ignorent totalement la mise en forme d’origine
    • J’utilise clang-format sur certains projets C++, et c’est affreux
      La stabilité entre versions est si faible qu’une mise à niveau de clang-format se traduit par un commit de mise en forme touchant chaque ligne du code
      Je ne suis vraiment pas sûr que ce soit mieux que de ne pas avoir de formateur du tout
    • J’ai longtemps pensé que « n’importe quel formateur vaut mieux que pas de formateur », mais j’ai complètement changé d’avis récemment
      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

    [  
      "aws",  
      "s3",  
      "sync",  
      path,  
      url,  
            *("--include", "*.html"),  
      *("--include", "*.xml"),  
      *("--metadata-directive", "REPLACE"),  
      *("--cache-control", "max-age=0"),  
    ]  
    
  • La dernière fois que j’ai regardé, zig fmt ne 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 vim et nerd tree

    • zig fmt n’a pas de limite de colonnes
  • En 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 rien
    J’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 :)

    • Prettier a lui aussi une fonctionnalité similaire, mais elle est limitée plus précisément aux objets littéraux et ne permet de choisir qu’entre « tout sur une ligne » et « un élément par ligne »
      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 tokens
    Un 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 ligne
    Dé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 instruction
    Trop 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 ainsi

    [1, 2, 3, 4, 5,  //  
     6, 7, 8, 9, 10, //  
     ...]  
    

    Je 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

    • C’est exactement ainsi que rustfmt se comporte, et ça me rend fou
      Il 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.*, et rustfmt pousse 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 rustfmt
      Les 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
      gl.bind_texture(gl::TEXTURE_2D, tex);  
      gl.tex_parameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST);  
      gl.tex_parameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST);
      
      // -->
      
      gl.bind_texture(gl::TEXTURE_2D, tex);  
      gl.tex_parameteri(  
          gl::TEXTURE_2D,  
          gl::TEXTURE_MIN_FILTER,  
          gl::NEAREST,  
      );  
      gl.tex_parameteri(  
          gl::TEXTURE_2D,  
          gl::TEXTURE_MAG_FILTER,  
          gl::NEAREST,  
      );  
      
      Découper une suite d’appels gl.tex_parameteri de cette manière sur plusieurs lignes est en réalité moins bon que de laisser chaque appel entièrement sur une ligne
      Si 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
      rustfmt ne sait alors pas comment les couper, abandonne et cesse de formater l’instruction entière
      Cela ressemble souvent à ceci
      match something {  
          // ... match arms above this one ...  
          _ => emit_diagnostic(&mut state, "This is a very long message to try and illustrate the problem. Help: please consult a doctor.")  
      }  
      
      Ici, sous prétexte que l’appel à emit_diagnostic n’est qu’une expression, il renonce à formater l’instruction match entière, ce qui est tout simplement stupide
      Tout 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 tableaux
    Donc si l’on sépare un tableau en deux, on peut les faire formater différemment