Steering Zig Fmt
(matklad.github.io)zig fmtkann 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 fmtden 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- undvalue-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 fmtkann 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, damitzig fmtden 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 fmtberü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- undvalue-Paare an einen Subprozess übergeben werden, können ein Array fester Argumente und ein Array von Optionspaaren verkettet und wie folgt ausgerichtet werdentry run(&(.{ "aws", "s3", "sync", path, url } ++ .{ "--include", "*.html", "--include", "*.xml", "--metadata-directive", "REPLACE", "--cache-control", "max-age=0", }));
1 Kommentare
Lobste.rs-Meinungen
Ich meine mich zu erinnern, dass es in
gofmtein ähnliches formatierungssteuerndes Verhalten gab, und solche Formatter gefallen mir besser alsrustfmtTrotzdem finde ich, dass jede Form von automatischer Formatierung besser ist als gar kein Formatter
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!“
clang-formatin einigen C++-Projekten, und es ist furchtbarDie Stabilität zwischen Versionen ist viel zu gering, sodass ein Upgrade von
clang-formatin einem Formatierungs-Commit endet, der jede Zeile im Code anfasstIch bin mir wirklich nicht sicher, ob das besser ist als gar kein Formatter
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
Als ich zuletzt nachgesehen habe, gab es in
zig fmtkeine 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 undnerd treenebeneinander unterbringen kannzig fmthat kein SpaltenlimitAls 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 erkenntIm 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 :)
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 formatiertEin 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öchteDas 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 beeinflussenZu 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 gruppierenIch weiß nicht, ob das absichtlich eingebaut wurde oder ein Nebeneffekt der Art ist, wie Kommentare behandelt werden
rustfmt, und das macht mich wahnsinnigManchmal 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, aberrustfmtpresst 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
rustfmtDie Zeilen sind auch nicht einmal so lang
Ich schreibe das gerade am Handy und habe kein Werkzeug, um ein 100% exaktes Beispiel zu bauen 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 lassenWenn 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
rustfmtweiß dann nicht, wie es das aufteilen soll, gibt auf und formatiert die gesamte Anweisung nichtHäufig sieht das etwa so aus Hier gibt es die Formatierung des gesamten
match-Statements auf, nur weil der Aufruf vonemit_diagnosticein Ausdruck ist — das ist einfach dummDas 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-KonkatenationsoperatorWenn man ein Array also in zwei Teile aufteilt, kann man sie unterschiedlich formatieren