1 Punkte von GN⁺ 2 시간 전 | 1 Kommentare | Auf WhatsApp teilen
  • zig fmt kann als steuerbarer Formatter verwendet werden, der die bereits im Dateiinhalt vorhandene Syntaxform übernimmt und denselben Code dadurch in mehreren Layouts anordnen kann
  • Bei Funktionsaufrufen verändert das Vorhandensein eines trailing comma das Ergebnis: Ohne Komma wird alles in einer Zeile zusammengeführt, mit Komma werden die Argumente zeilenweise angeordnet
  • Der praktische Ablauf besteht darin, zunächst die gewünschte Code-Anordnung festzulegen, dann ein paar Kommata hinzuzufügen und anschließend die Formatierungs-Tastenkombination zu drücken, damit zig fmt den Rest erledigt
  • Bei Arrays wird nicht nur das trailing comma berücksichtigt, sondern auch die Position des ersten Zeilenumbruchs; liegt dieser nach dem dritten Element, werden die Elemente in Dreiergruppen ausgerichtet
  • Mit vorsichtig eingesetzter ++-Array-Verkettung lässt sich die Anzahl der Elemente pro Zeile variieren; beim Übergeben von --key- und value-Paaren an einen Subprozess können ein Array fester Argumente und ein Array von Optionspaaren verkettet und so ausgerichtet werden

So lässt sich zig fmt steuern

  • zig fmt kann als steuerbarer Formatter genutzt werden, weil es die im aktuellen Dateiinhalt bereits vorhandene Syntaxform betrachtet und dieselbe Syntax auf verschiedene Arten anordnen kann
  • Bei Funktionsaufrufen verändert das Vorhandensein eines trailing comma das Layout
    f(1, 2,
          3);
    
    // -> zig fmt ->
    
        f(1, 2, 3);
    
    f(1, 2,
          3,);
    
    // -> zig fmt ->
    
        f(
            1,
            2,
            3,
        );
    
  • In der Praxis legt man zuerst die gewünschte Code-Anordnung fest, fügt dann einige , hinzu und drückt die Formatierungs-Tastenkombination, damit zig fmt den Rest erledigt
  • Statt den Formatter das Layout erraten zu lassen, kann es besser passen, wenn die Nutzer die zentralen Entscheidungen selbst im Code hinterlassen
  • 90 % guter Formatierung hängen von Leerzeilen zwischen logischen Blöcken und der passenden Wahl von Zwischenvariablen ab; daher ist es besser, solche Entscheidungen zu nutzen statt sie zu eliminieren

Spaltenausgerichtete Layouts für Arrays

  • Bei Arrays führt nicht nur das trailing comma dazu, dass Elemente einzeln pro Zeile angeordnet werden; zig fmt berücksichtigt auch die Position des ersten Zeilenumbruchs
    .{ 1, 2, 3,
          4, 5, 6, 7, 8, 9, 10, 11,  };
    
  • Wenn der erste Zeilenumbruch nach dem dritten Element steht, wird auch das Ergebnis in Dreiergruppen ausgerichtet
    .{
            1,  2,  3,
            4,  5,  6,
            7,  8,  9,
            10, 11,
        };
    
  • Mit bedacht eingesetzter ++-Array-Verkettung lässt sich die Anzahl der Elemente pro Zeile unterschiedlich gestalten
  • Wenn --key- und value-Paare an einen Subprozess übergeben werden, können ein Array fester Argumente und ein Array von Optionspaaren verkettet und wie folgt ausgerichtet werden
    try run(&(.{ "aws", "s3", "sync", path, url } ++ .{
        "--include",            "*.html",
        "--include",            "*.xml",
        "--metadata-directive", "REPLACE",
        "--cache-control",      "max-age=0",
    }));
    

1 Kommentare

 
GN⁺ 2 시간 전
Lobste.rs-Meinungen
  • Ich meine mich zu erinnern, dass es in gofmt ein ähnliches formatierungssteuerndes Verhalten gab, und solche Formatter gefallen mir besser als rustfmt
    Trotzdem finde ich, dass jede Form von automatischer Formatierung besser ist als gar kein Formatter

    • Über den Satz „Irgendetwas ist besser als kein Formatter“ kann ich nicht einfach hinweggehen
      Auto-Formatter erzwingen Mittelmaß; sie ziehen Leute nach oben, die Formatierung nicht gut einsetzen können, drücken aber auch jene nach unten, die gut damit umgehen
      Bei Zusammenarbeit würde ich sie nutzen, wenn andere es wollen oder wenn man ihren persönlichen Formatierungsregeln nicht trauen kann, aber allein würde ich sie nie verwenden
      Ich habe meinen Geschmack, und der Formatter hat seinen, und beide sind unvereinbar verschieden
      Das, was der Artikel hier zeigt, ist allerdings an sich beeindruckend
      Der Satz erinnert mich an die Zeile der Heiratsvermittlerin Yente in Fiddler on the Roof: „Ein schlechter Ehemann — Gott bewahre — ist immer noch besser als gar kein Ehemann!“
    • Soweit ich mich erinnere, funktionierte der Elm-Formatter ähnlich, und das gefiel mir deutlich besser als Formatter, die die ursprüngliche Formatierung überhaupt nicht berücksichtigen
    • Ich verwende clang-format in einigen C++-Projekten, und es ist furchtbar
      Die Stabilität zwischen Versionen ist viel zu gering, sodass ein Upgrade von clang-format in einem Formatierungs-Commit endet, der jede Zeile im Code anfasst
      Ich bin mir wirklich nicht sicher, ob das besser ist als gar kein Formatter
    • Früher dachte ich lange, „jeder Formatter ist besser als keiner“, aber in letzter Zeit habe ich meine Meinung komplett geändert
      Auto-Formatter lösen vor allem das menschliche Problem, Fahrradschuppen-Diskussionen in Pull Requests zu vermeiden
      Aber jetzt, da wir zu agentenbasierter Entwicklung übergehen, wird dieses Problem immer weniger wichtig
      In mehreren Projekten, an denen ich gerade arbeite, erledigen Maschinen inzwischen den Großteil der Arbeit, und dadurch fühlt es sich eher so an, als wäre es besser, keinen Formatter laufen zu lassen
  • Beim Bauen von Kommandozeilenargumenten in Python mag ich es, Tupel per Splat in eine Liste zu übernehmen, daher würde ich das letzte Beispiel aus dem Artikel wohl so schreiben

    [  
      "aws",  
      "s3",  
      "sync",  
      path,  
      url,  
            *("--include", "*.html"),  
      *("--include", "*.xml"),  
      *("--metadata-directive", "REPLACE"),  
      *("--cache-control", "max-age=0"),  
    ]  
    
  • Als ich zuletzt nachgesehen habe, gab es in zig fmt keine Möglichkeit, statt eines 80-Spalten-Limits ein Limit von 100 Spalten zu verwenden — ist das immer noch so?
    Wenn ich mehrere Stunden am Tag arbeite, ermüden meine Augen weniger, wenn ich die Terminal-Schriftgröße erhöhe, und der Unterschied zwischen 80 und 100 Spalten entscheidet darüber, ob ich zwei vim-Splits und nerd tree nebeneinander unterbringen kann

    • zig fmt hat kein Spaltenlimit
  • Als jemand, der in einem Team ohne jeden Formatter rigid formatter eingeführt hat, vermisse ich manchmal die Möglichkeit, die Formatierung manuell beeinflussen zu können
    In dieser Hinsicht ist es wirklich großartig, dass Zig flexibel ist

  • Großartig!
    Gibt es einen TS/JS-Formatter mit so einer Art Verhalten?
    Ich habe ein Projekt mit maplibre-gl, und Ausdrucke der Style-Spezifikation werden manchmal so überformatiert, dass man gar nichts mehr erkennt
    Im Moment habe ich den Formatter abgeschaltet, aber durch Debugging, Kopieren und Auskommentieren wird der Code zunehmend unordentlich
    Vielleicht könnte man den Zig-Formatter auch andere Sprachen formatieren lassen :)

    • Prettier hat etwas Ähnliches, aber konkret ist es auf Objektliterale beschränkt, und man kann nur zwischen „alles in eine Zeile“ und „jedes Element in eine eigene Zeile“ wählen
      Es gibt zum Beispiel keine Möglichkeit, dem Formatter zu sagen, er solle vier Elemente pro Zeile setzen
      Außerdem stellt Prettier Objektliterale, wenn sie zu lang werden, letztlich immer auf „jedes Element in eine eigene Zeile“ um, egal wie der Eingabetext aussieht
  • Ich war schon von leichtgewichtigen Formattern enttäuscht, also praktisch Formatter, die nur Zeilen umbrechen, daher gefällt mir die Idee und ich beneide sie, innerhalb eines strengeren Beispiels so viel Flexibilität zu haben :p
    Kürzlich habe ich im Fedi auf eine Frage zum Schreiben und Formatieren von Lisp mit proportionalen Schriftarten geantwortet und dabei auf s-Expression-Varianten mit bedeutungstragendem Whitespace hingewiesen, nämlich wisp, Readable/Sweet expressions sowie SRFI 119 und 110
    Ich habe außerdem angemerkt, dass diese Syntaxfamilie mit optionalen Erweiterungen für Infixnotation einen Teil der Kontrolle über Zeilenumbrüche zurückgibt

  • Interessantes Design, aber ich bin mir nicht sicher, ob es mir gefällt
    In meinem Formatter behandle ich es anders: Der Formatter ignoriert Trailing Commas bei der Entscheidung über das Layout; wenn etwas dann mehrzeilig wird, fügt er immer Trailing Commas hinzu, und wenn es einzeilig ist, entfernt er sie immer
    Dadurch kann man nichts „steuern“, aber f(1, 2, 3) wird unabhängig davon, ob ein Trailing Comma vorhanden ist oder wie viel und welche Art von Whitespace zwischen den Tokens steht, konsistent formatiert
    Ein gewisses Maß an Steuerung ist nötig
    Wenn man zum Beispiel ein langes Listenliteral [<expr1>, <expr2>, ..., <expr100>] hat, würden die meisten Formatter wahrscheinlich jeden Ausdruck in eine eigene Zeile setzen, obwohl man vielleicht möglichst viele pro Zeile haben möchte
    Das mit Trailing Commas zu steuern, finde ich merkwürdig; allgemein gibt es eher N Möglichkeiten statt nur 2
    Für diesen Zweck scheinen mir Attribute besser geeignet
    Zum Beispiel könnte man — falls es das nicht ohnehin schon gibt — so etwas wie #[rustfmt::list_layout(flow)] vor eine Anweisung setzen, um die Formatierung von Listenliteralen in dieser Anweisung zu beeinflussen
    Zu viel Steuerbarkeit untergräbt den Zweck eines Formatters, nämlich die Code-Formatierung im gesamten Ökosystem konsistent zu halten und Code-Reviews zu erleichtern, deshalb sollte man sie auf begrenzte Fälle beschränken
    Lange Listenliterale halte ich für ein wirklich gutes Beispiel dafür
    In meinem Projekt gibt es ebenfalls einen Fall, in dem Formatierung beim Review von Test-Expected-Values hilft; hier ist ein Beispiel
    Mir fällt beim Dart-Formatter noch ein anderes „Steuerungs“-Verhalten ein: In langen Listenliteralen kann man Kommentarzeilen einfügen, um Zeilen zu gruppieren
    Bei [1, 2, 3, ..., 1000] würde er also jedes Element in eine eigene Zeile setzen, aber man kann manuell so gruppieren

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

    Ich weiß nicht, ob das absichtlich eingebaut wurde oder ein Nebeneffekt der Art ist, wie Kommentare behandelt werden

    • Genau so verhält sich rustfmt, und das macht mich wahnsinnig
      Manchmal ist es lesbarer, einen Funktionsaufruf nicht aufzuteilen, selbst wenn er das Zeilenlängenlimit überschreitet, und ich hätte gern eine Möglichkeit, dieses Urteil widerzuspiegeln
      Ein Beispiel, das mir einfällt, ist OpenGL
      Oft modifiziert oder verwendet man eine einzelne Ressource und hat dann viele gl.*-Aufrufe hintereinander, etwa bei der Texturinitialisierung, aber rustfmt presst das ohne jedes Feingefühl durch, einzig nach dem roboterhaften Ziel „Zeile zu lang, muss umgebrochen werden“
      Dieses Beispiel ist konstruiert, um das Verhalten zu zeigen, und nicht exakt identisch mit dem tatsächlichen Verhalten von rustfmt
      Die Zeilen sind auch nicht einmal so lang
      Ich schreibe das gerade am Handy und habe kein Werkzeug, um ein 100% exaktes Beispiel zu bauen
      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,  
      );  
      
      Solche aufeinanderfolgenden gl.tex_parameteri-Aufrufe in mehrere Zeilen zu zerlegen, ist schlechter, obwohl es besser wäre, jeden Aufruf vollständig in einer Zeile zu lassen
      Wenn die Spalten ausgerichtet sind, kann man den Unterschied zwischen den beiden Zeilen viel leichter erkennen
      Die umgebrochene Version hat weniger visuelle Nähe und ist schwerer zu lesen
      Man kann die beiden Zeilen nicht mehr leicht mit den Augen vergleichen
      Außerdem kommt es zu der lächerlichen Situation, dass es komplett scheitert, wenn eine Formatierung innerhalb des Zeichenlimits nicht möglich ist
      Das passiert mir oft beim Schreiben von Compiler-Code, wenn ich Diagnosemeldungen als String-Literale formuliere, weil die Meldungen ziemlich lang werden können
      rustfmt weiß dann nicht, wie es das aufteilen soll, gibt auf und formatiert die gesamte Anweisung nicht
      Häufig sieht das etwa so aus
      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.")  
      }  
      
      Hier gibt es die Formatierung des gesamten match-Statements auf, nur weil der Aufruf von emit_diagnostic ein Ausdruck ist — das ist einfach dumm
      Das alles ließe sich vermeiden, wenn es nicht versuchen würde, meinen Code zwanghaft auf maximal 100 Spalten zu pressen
  • Für alle, die wie ich wegen des Kommentars am Ende nachsehen mussten: ++ ist der Array-Konkatenationsoperator
    Wenn man ein Array also in zwei Teile aufteilt, kann man sie unterschiedlich formatieren