Cómo orientar `zig fmt`
(matklad.github.io)zig fmtpuede usarse como un formateador orientable que refleja la forma sintáctica ya presente en el archivo y puede acomodar el mismo código en varios layouts- En las llamadas a funciones, la presencia o ausencia de trailing comma cambia el resultado: sin coma se une en una sola línea, y con coma los argumentos se colocan uno por línea
- El flujo real consiste en decidir primero la disposición de código deseada, agregar unas cuantas comas y luego presionar el atajo de formateo para que
zig fmtse encargue del resto - En los arreglos, además del trailing comma, también se refleja la posición del primer salto de línea; si el primer salto va después del tercer elemento, se alinean en grupos de 3 elementos
- Si se usa
++con cuidado para concatenar arreglos, se puede variar la cantidad de elementos por línea y, al pasar pares--keyyvaluea un subprocess, se pueden concatenar un arreglo de argumentos fijos y otro de pares de opciones para alinearlos
Cómo orientar zig fmt
zig fmtpuede usarse como un formateador orientable porque observa la forma sintáctica ya presente en el archivo y puede acomodar la misma sintaxis de varias maneras- En las llamadas a funciones, la presencia o ausencia de trailing comma cambia el layout
f(1, 2, 3); // -> zig fmt -> f(1, 2, 3);f(1, 2, 3,); // -> zig fmt -> f( 1, 2, 3, ); - En el uso real, el flujo consiste en decidir primero la disposición de código deseada, agregar unas cuantas
,y luego presionar el atajo de formateo para quezig fmtse encargue del resto - En lugar de hacer que el formateador adivine el layout, puede funcionar mejor dejar que el usuario conserve directamente las decisiones clave
- La conclusión es que el 90% del buen formateo depende de las líneas en blanco entre bloques lógicos y de elegir variables intermedias adecuadas, así que es mejor aprovechar esas decisiones que eliminarlas
Layout de alineación por columnas en arreglos
- En los arreglos,
zig fmtno solo usa el trailing comma para poner un elemento por línea, sino que también refleja la posición del primer salto de línea.{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, }; - Si el primer salto de línea va después del tercer elemento, el resultado también se alinea en grupos de 3 elementos
.{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, }; - Si se usa con cuidado la concatenación de arreglos con
++, se puede variar la cantidad de elementos por línea - Al pasar pares
--keyyvaluea un subprocess, se puede concatenar un arreglo de argumentos fijos y otro de pares de opciones para alinearlos asítry run(&(.{ "aws", "s3", "sync", path, url } ++ .{ "--include", "*.html", "--include", "*.xml", "--metadata-directive", "REPLACE", "--cache-control", "max-age=0", }));
1 comentarios
Opiniones en Lobste.rs
Recuerdo que
gofmttambién tenía un comportamiento de formato guiado parecido, y ese tipo de formateador me gusta más querustfmtAun así, me parece mejor tener algún tipo de automatización de formato que no tener formateador en absoluto
Los autoformateadores fuerzan la mediocridad: levantan a quienes no saben formatear, pero también bajan a quienes sí saben hacerlo bien
Los usaría al colaborar, si es difícil confiar en lo que otras personas quieren o en sus reglas personales de estilo, pero trabajando solo no los usaría jamás
Yo tengo mis gustos y el formateador tiene los suyos, y son irreconciliablemente distintos
Dicho eso, lo que muestra este artículo en sí es impresionante
Esa frase me recuerda la línea de Yente, la casamentera de Fiddler on the Roof: “¡Hasta un mal marido—que Dios nos libre—es mejor que no tener marido!”
clang-formaten algunos proyectos de C++ y es terribleLa estabilidad entre versiones es demasiado baja, así que actualizar
clang-formattermina en un commit de formato que toca todas las líneas del códigoDe verdad no estoy seguro de que sea mejor que no tener formateador
Los autoformateadores resuelven sobre todo un problema humano: eliminar las discusiones de detalle irrelevante en los pull requests
Pero ahora que estamos pasando al desarrollo con agentes, ese problema cada vez importa menos
En varios proyectos las máquinas ya están haciendo la mayor parte del trabajo, y en ese contexto me da la impresión de que es mejor no correr el formateador
Cuando construyo argumentos de línea de comandos en Python, me gusta desplegar tuplas dentro de una lista, así que el ejemplo final del artículo probablemente lo escribiría así
La última vez que revisé,
zig fmtno tenía forma de configurar un límite de 80 columnas en lugar de 100; ¿sigue siendo así?Si trabajo varias horas al día, me cansa menos la vista usar un tamaño de fuente más grande en la terminal, y la diferencia entre 80 y 100 columnas decide si puedo tener dos divisiones de
vimynerd treeuna al lado de la otrazig fmtno tiene límite de columnasComo alguien que introdujo rigid formatter en un equipo que antes no tenía ningún formateador, a veces extraño poder influir manualmente en el formato
En ese sentido, está muy bueno que Zig sea flexible
¡Excelente!
¿Habrá algún formateador de TS/JS que funcione así?
Tengo un proyecto que usa
maplibre-gl, y a veces las expresiones de la especificación de estilos quedan tan exageradamente formateadas que no se entiende nadaPor ahora dejé de usar formateador, pero entre depurar, copiar y comentar código, todo se va ensuciando
Quizás hasta se podría hacer que el formateador de Zig también formatee otros lenguajes :)
Por ejemplo, no hay manera de indicarle al formateador que ponga cuatro elementos por línea
Además, si un literal de objeto se vuelve demasiado largo, Prettier termina forzándolo al formato de “cada elemento en una línea distinta”, sin importar cómo venga el texto de entrada
Me han decepcionado los formateadores livianos, básicamente formateadores que solo insertan saltos de línea, así que me gusta y me da cierta envidia la idea de tener esta flexibilidad dentro de un ejemplo más estricto :p
Hace poco, respondiendo en el fediverso a una pregunta sobre escribir y formatear Lisp con fuentes proporcionales, mencioné variantes de s-expressions con espacios significativos como wisp, Readable/Sweet expressions y SRFI 119 y 110
También señalé que esa familia de sintaxis devuelve parte del control sobre los saltos de línea al aprovechar extensiones opcionales de notación infija
Es un diseño interesante, pero no estoy seguro de que me guste
En mi formateador lo manejo distinto: el formateador ignora las comas finales al decidir el formato; luego, si algo queda dividido en varias líneas, siempre agrega una coma final, y si queda en una sola línea, siempre la elimina
Así que no permite “guiarlo”, pero
f(1, 2, 3)se formatea de manera consistente sin importar si tenía o no coma final, ni la cantidad o tipo de espacios entre tokensHace falta cierto grado de guía
Por ejemplo, si tienes un literal de lista largo como
[<expr1>, <expr2>, ..., <expr100>], la mayoría de los formateadores pondrán cada expresión en su propia línea, pero puede que quieras meter tantas como sea posible en cada líneaMe parece raro decidir eso a partir de una coma final, y en general las opciones pueden ser N, no solo 2
Creo que para esto encajan mejor los atributos
Por ejemplo, quizá ya exista, pero se podría poner algo como
#[rustfmt::list_layout(flow)]delante de una sentencia para influir en el formato de los literales de lista dentro de esa sentenciaSi hay demasiada “guía”, se perjudica el propósito del formateador de volver consistente el formato del código en todo el ecosistema y facilitar la revisión de código, así que debería limitarse a casos puntuales
Los literales de lista largos me parecen un caso realmente válido
También tengo un ejemplo en mi proyecto donde el formato ayuda a revisar valores esperados en tests, que es este
También se me ocurre otro comportamiento de “guía” en el formateador de Dart: en literales de lista largos puedes agregar líneas de comentarios para agrupar líneas
Por ejemplo, si tienes
[1, 2, 3, ..., 1000], pondrá cada elemento en una línea, pero puedes agruparlos manualmente asíNo sé si eso fue una función puesta a propósito o un efecto secundario de cómo maneja los comentarios
rustfmt, y me vuelve locoA veces, incluso si se supera el límite de longitud de línea, es más legible no partir una llamada de función, y me gustaría poder reflejar mi criterio ahí
Un caso que se me viene a la cabeza es OpenGL
Normalmente modificas o usas un mismo recurso, y por ejemplo al inicializar texturas terminas con muchas llamadas seguidas a
gl.*, perorustfmtlas parte sin ningún criterio más allá del objetivo robótico de “la línea es demasiado larga; hay que cortarla”Este ejemplo es artificial para mostrar el comportamiento y no coincide por completo con el comportamiento real de
rustfmtTampoco las líneas son tan largas
Ahora mismo estoy escribiendo desde el teléfono, así que no tengo herramientas para hacer un ejemplo 100% exacto Dividir en varias líneas una secuencia de llamadas
gl.tex_parametericomo esa en realidad es peor que dejar cada llamada completa en una sola líneaSi las columnas están alineadas, es mucho más fácil ver la diferencia entre ambas líneas
La versión partida pierde proximidad visual y es más difícil de leer
Ya no puedes comparar fácilmente ambas líneas de un vistazo
También pasa la ridiculez de que falla por completo cuando no puede formatear algo para que entre dentro del límite de caracteres
Esto me pasa seguido escribiendo código de compilador, cuando construyo mensajes de diagnóstico como literales de cadena, porque esos mensajes pueden ser bastante largos
rustfmtno sabe cómo dividirlo, así que se rinde y deja sin formatear toda la sentenciaSuele verse algo así El hecho de que
emit_diagnosticsea solo una expresión hace que renuncie a formatear todo elmatch, y eso es simplemente tontoTodo eso se habría evitado si no tratara de forzar mi código a un máximo de 100 columnas
Para quien, como yo, tuvo que buscarlo al ver el comentario del final:
++es el operador de concatenación de arreglosAsí que puedes dividir un arreglo en dos para que se formatee de forma distinta