1 pontos por GN⁺ 1 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • zig fmt pode 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 fmt cuidar 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 --key e value para um subprocesso conectando um array de argumentos fixos com outro de pares de opções

Como controlar o zig fmt

  • O zig fmt pode 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 o zig fmt fazer 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 fmt nã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 --key e value para um subprocesso, é possível alinhar dessa forma concatenando um array de argumentos fixos com outro array de pares de opções
    try run(&(.{ "aws", "s3", "sync", path, url } ++ .{
        "--include",            "*.html",
        "--include",            "*.xml",
        "--metadata-directive", "REPLACE",
        "--cache-control",      "max-age=0",
    }));
    

1 comentários

 
GN⁺ 1 시간 전
Comentários do Lobste.rs
  • Lembro que o gofmt também tinha um comportamento de direcionamento de formatação parecido, e gosto mais desse tipo de formatador do que do rustfmt
    Ainda assim, acho melhor ter algum tipo de automação de formatação do que não ter formatador nenhum

    • É difícil deixar passar a frase “qualquer coisa é melhor do que não ter formatador”
      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!”
    • Pelo que me lembro, o formatador do Elm também funcionava de forma parecida, e isso me parecia bem melhor do que os formatadores que ignoram completamente a formatação original
    • Uso clang-format em alguns projetos C++, e é horrível
      A estabilidade entre versões é baixa demais, então atualizar o clang-format vira um commit de formatação que mexe em todas as linhas do código
      Não tenho certeza se isso realmente é melhor do que não ter formatador nenhum
    • Por muito tempo achei que “qualquer formatador é melhor do que nenhum”, mas recentemente mudei completamente de ideia
      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

    [  
      "aws",  
      "s3",  
      "sync",  
      path,  
      url,  
            *("--include", "*.html"),  
      *("--include", "*.xml"),  
      *("--metadata-directive", "REPLACE"),  
      *("--cache-control", "max-age=0"),  
    ]  
    
  • Da última vez que vi, o zig fmt nã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 vim e o nerd tree lado a lado

    • O zig fmt não tem limite de colunas
  • Como 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 nada
    Parei 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 :)

    • O Prettier tem algo parecido, mas especificamente limitado a literais de objeto, e só dá para escolher entre “tudo em uma linha” e “cada item em uma linha diferente”
      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 tokens
    Algum 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 linha
    Acho 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ção
    Direcionamento 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 assim

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

    Não sei se essa funcionalidade foi colocada de propósito ou se é um efeito colateral do tratamento de comentários

    • Esse é exatamente o comportamento do 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 o rustfmt vai 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 rustfmt
      As 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
      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,  
      );  
      
      Quebrar várias chamadas consecutivas como gl.tex_parameteri em múltiplas linhas desse jeito é pior, porque na verdade é melhor deixar cada chamada totalmente aberta em uma linha
      Quando 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 rustfmt não sabe como quebrar isso, então desiste e deixa a instrução inteira sem formatar
      Frequentemente fica algo assim
      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.")  
      }  
      
      Aqui ele desiste de formatar a instrução match inteira só porque a chamada emit_diagnostic é uma expressão, o que é simplesmente idiota
      Tudo 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 arrays
    Então, se você dividir um array em dois, pode formatar cada parte de maneira diferente