Controlando o Zig Fmt
(matklad.github.io)zig fmtpode ser usado como um formatador controlável, refletindo a forma sintática já presente no arquivo e organizando o mesmo código em diferentes layouts- Em chamadas de função, a presença ou ausência de trailing comma muda o resultado: sem vírgula, tudo é unido em uma linha; com vírgula, os argumentos são distribuídos linha por linha
- Na prática, o fluxo é definir primeiro o layout desejado do código, adicionar algumas vírgulas e depois apertar o atalho de formatação para deixar o
zig fmtcuidar do resto - Em arrays, além da trailing comma, também é refletida a posição da primeira quebra de linha; se a primeira quebra vier depois do terceiro item, o alinhamento sai em grupos de 3 itens
- Usando com cuidado a concatenação de arrays com
++, dá para distribuir quantidades diferentes de itens por linha e alinhar a passagem de pares--keyevaluepara um subprocesso conectando um array de argumentos fixos com outro de pares de opções
Como controlar o zig fmt
- O
zig fmtpode ser usado como um formatador controlável, observando a forma sintática já presente no arquivo para organizar a mesma sintaxe de várias maneiras - Em chamadas de função, a presença ou ausência de trailing comma altera o layout
f(1, 2, 3); // -> zig fmt -> f(1, 2, 3);f(1, 2, 3,); // -> zig fmt -> f( 1, 2, 3, ); - No uso real, o fluxo é decidir primeiro o layout desejado, adicionar algumas
,e então usar o atalho de formatação para deixar ozig fmtfazer o restante - Em vez de fazer o formatador adivinhar o layout, pode funcionar melhor deixar explicitamente as escolhas essenciais nas mãos do usuário
- A conclusão é que 90% de uma boa formatação depende das linhas em branco entre blocos lógicos e da escolha adequada de variáveis intermediárias, então é melhor aproveitar esse tipo de decisão do que tentar eliminá-lo
Layout com alinhamento em colunas para arrays
- Em arrays, o
zig fmtnão se limita a colocar um item por linha com base apenas na trailing comma; ele também leva em conta a posição da primeira quebra de linha.{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, }; - Se a primeira quebra de linha vier depois do terceiro item, o resultado também será alinhado em grupos de 3 itens
.{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, }; - Usando com cuidado a concatenação de arrays com
++, dá para distribuir quantidades diferentes de itens por linha - Ao passar pares
--keyevaluepara um subprocesso, é possível alinhar dessa forma concatenando um array de argumentos fixos com outro array de pares de opçõestry run(&(.{ "aws", "s3", "sync", path, url } ++ .{ "--include", "*.html", "--include", "*.xml", "--metadata-directive", "REPLACE", "--cache-control", "max-age=0", }));
1 comentários
Comentários do Lobste.rs
Lembro que o
gofmttambém tinha um comportamento de direcionamento de formatação parecido, e gosto mais desse tipo de formatador do que dorustfmtAinda assim, acho melhor ter algum tipo de automação de formatação do que não ter formatador nenhum
Formatadores automáticos impõem mediocridade: elevam quem não sabe usar formatação, mas também rebaixam quem sabe
Eu usaria em colaboração, se outras pessoas quisessem ou se fosse difícil confiar na disciplina pessoal de formatação delas, mas trabalhando sozinho eu jamais usaria
Eu tenho meu gosto e o formatador tem o dele, e os dois são irreconciliavelmente diferentes
Dito isso, o que este texto mostrou em si é impressionante
A frase me lembra a fala da casamenteira Yente em Fiddler on the Roof: “Mesmo um marido ruim—Deus nos livre—é melhor do que não ter marido!”
clang-formatem alguns projetos C++, e é horrívelA estabilidade entre versões é baixa demais, então atualizar o
clang-formatvira um commit de formatação que mexe em todas as linhas do códigoNão tenho certeza se isso realmente é melhor do que não ter formatador nenhum
Formatadores automáticos resolvem principalmente um problema humano: eliminar discussões de bike shed em pull requests
Mas agora, com a transição para o desenvolvimento orientado por agentes, esse problema está ficando cada vez menos importante
Em vários projetos em que trabalho hoje, a máquina faz a maior parte do trabalho, e nisso tenho sentido que é melhor não rodar formatador
Ao montar argumentos de linha de comando em Python, gosto de espalhar tuplas dentro de listas, então acho que escreveria o último exemplo do texto assim
Da última vez que vi, o
zig fmtnão tinha como configurar limite de 80 colunas em vez de 100 colunas; ainda é assim?Quando trabalho várias horas por dia, uso fonte maior no terminal para cansar menos os olhos, e a diferença entre 80 e 100 colunas determina se dá para deixar dois splits do
vime onerd treelado a ladozig fmtnão tem limite de colunasComo alguém que introduziu um rigid formatter numa equipe que antes não tinha formatador nenhum, às vezes sinto falta da capacidade de influenciar a formatação manualmente
Nesse sentido, é muito legal que o Zig seja flexível
Excelente!
Será que existe algum formatador de TS/JS desse tipo?
Tenho um projeto que usa
maplibre-gl, e expressões da especificação de estilo às vezes ficam formatadas de forma tão agressiva que não dá para enxergar nadaParei de usar formatador por enquanto, mas depurar, copiar e comentar código acaba deixando tudo bagunçado
Talvez desse até para fazer o formatador do Zig formatar outras linguagens também :)
Por exemplo, não há como instruir o formatador a colocar quatro itens por linha
Além disso, quando o literal de objeto fica comprido demais, o Prettier acaba convertendo para o formato “cada item em uma linha diferente” independentemente de como o texto de entrada estiver
Já me decepcionei com formatadores leves, basicamente formatadores que só quebram linhas, então gosto e invejo essa ideia de ter essa flexibilidade dentro de exemplos mais rígidos :p
Recentemente, no fedi, ao responder a uma pergunta sobre escrever e formatar Lisp com fonte proporcional, mencionei variantes de s-expression com espaço significativo, como wisp, Readable/Sweet expressions e SRFI 119 e 110
Também observei que essa família de sintaxes recupera parte do controle sobre quebras de linha ao explorar extensões opcionais de notação infixa
É um design interessante, mas não sei se gosto
No meu formatador, faço diferente: ele ignora vírgulas finais ao decidir a formatação, depois sempre adiciona vírgula final se ficar em várias linhas e sempre remove a vírgula final se ficar em uma linha
Então ele não permite “direcionamento”, mas
f(1, 2, 3)é formatado de forma consistente independentemente de ter ou não vírgula final, ou da quantidade e do tipo de espaços entre os tokensAlgum grau de direcionamento é necessário
Por exemplo, se você tem um literal de lista longo
[<expr1>, <expr2>, ..., <expr100>], a maioria dos formatadores colocaria uma expressão por linha, mas talvez você queira colocar o máximo possível em cada linhaAcho estranho usar vírgula final para decidir isso, e em geral as opções podem ser N, não só 2
Para esse tipo de objetivo, atributos me parecem mais adequados
Por exemplo, talvez já exista algo assim, mas seria possível colocar algo como
#[rustfmt::list_layout(flow)]antes de uma instrução para influenciar a formatação dos literais de lista dentro daquela instruçãoDirecionamento demais prejudica o objetivo do formatador, que é tornar o estilo do código consistente em todo o ecossistema e facilitar revisão de código, então isso deveria existir só em casos limitados
Literais de lista longos me parecem um exemplo realmente necessário
No meu projeto também há um caso em que a formatação ajuda a revisar valores esperados de testes; é este aqui
Também me lembro de outro comportamento de “direcionamento” no formatador do Dart: em literais de lista longos, você pode adicionar linhas de comentário para agrupar as linhas
Por exemplo, em
[1, 2, 3, ..., 1000], ele colocaria um item por linha, mas você pode agrupar manualmente assimNão sei se essa funcionalidade foi colocada de propósito ou se é um efeito colateral do tratamento de comentários
rustfmt, e isso me deixa malucoÀs vezes, mesmo ultrapassando o limite de comprimento de linha, é mais legível não quebrar uma chamada de função, e eu gostaria de poder refletir meu julgamento nisso
Um caso que me vem à cabeça é OpenGL
Normalmente você está modificando ou usando um único recurso e acaba fazendo várias chamadas
gl.*seguidas, como na inicialização de textura, mas orustfmtvai empurrando isso sem nenhuma noção além de um objetivo robótico do tipo “a linha é longa demais, precisa quebrar”Este exemplo é artificial, feito para mostrar o comportamento, e não corresponde exatamente ao comportamento real do
rustfmtAs linhas também não são tão longas assim
Estou escrevendo no celular agora, então não tenho ferramentas para montar um exemplo 100% preciso Quebrar várias chamadas consecutivas como
gl.tex_parameteriem múltiplas linhas desse jeito é pior, porque na verdade é melhor deixar cada chamada totalmente aberta em uma linhaQuando as colunas ficam alinhadas, fica muito mais fácil ver a diferença entre as duas linhas
A versão quebrada perde proximidade visual e é mais difícil de ler
Você deixa de conseguir comparar as duas linhas facilmente com os olhos
Também acontece aquela situação ridícula em que ele falha completamente quando não consegue formatar algo para caber no limite de caracteres por linha
Isso acontece bastante ao escrever código de compilador e montar mensagens de diagnóstico como literais de string, porque essas mensagens podem ficar bem longas
O
rustfmtnão sabe como quebrar isso, então desiste e deixa a instrução inteira sem formatarFrequentemente fica algo assim Aqui ele desiste de formatar a instrução
matchinteira só porque a chamadaemit_diagnosticé uma expressão, o que é simplesmente idiotaTudo isso poderia ser evitado se ele não tentasse forçar meu código para no máximo 100 colunas
Só para poupar a busca de quem, como eu, precisou procurar no comentário final:
++é o operador de concatenação de arraysEntão, se você dividir um array em dois, pode formatar cada parte de maneira diferente