Como código de formato bonito (inserir automaticamente novas linhas, recuo, etc.)?

24

Estou usando, spacemacsmas presumivelmente é necessário o conhecimento do emacs aqui.

Eu tenho um arquivo JSON com uma única linha longa, digamos este JSON em json.org/example:

{"menu": {"id": "file", "value": "File", "popup": {"menuitem": [{"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}, {"value": "Close", "onclick": "CloseDoc()"}]}}}

Gostaria que o emacs reinscreva isso, o que significa para mim não alterar o caractere mais à esquerda da linha para o nível de indentação adequado, mas quebrar a linha em várias linhas.

Se eu usar spacemacs/indent-region-or-buffer( SPC j =), o texto não será alterado.

Como eu poderia pedir ao emacs para realmente romper essa longa fila e se reintegrar para obter algo assim:

{"menu": {
  "id": "file",
  "value": "File",
  "popup": {
    "menuitem": [
      {"value": "New", "onclick": "CreateNewDoc()"},
      {"value": "Open", "onclick": "OpenDoc()"},
      {"value": "Close", "onclick": "CloseDoc()"}
    ]
  }
}}

Não estou interessado em uma resposta específica ao JSON, por exemplo, acredito que o intelliJ faz isso para qualquer idioma compatível (java, json ...). Eu acho que é viável para qualquer idioma emacs tem um modo principal para, ou digamos os mais populares.

EDIT Descobri M-x json-reformat-regionque é spacemacsfornecido com e funciona, mas sim, eu gostaria disso para qualquer idioma e sempre com o mesmo atalho, com base no modo principal ...

EDIT2 Ok, então minha conclusão é que ele é implementado para várias linguagens, pelo menos JSON e lisp, provavelmente para outras, e seria fácil ainda mais (XML / XHTML, go que possui go-fmt e também usa clang). No entanto, não há nome de função genérico que o faria para todos os idiomas. Há espaço aqui para implementá-lo em spacemacscamadas para as várias linguagens ... Não encontrei uma implementação X / HTML, o que me surpreende um pouco.

Emmanuel Touzery
fonte
3
Para HTML / JS / CSS: web-beautiful.el. Este é o melhor que encontrei, mas depende do node.js.
nanny

Respostas:

10

Parece que você precisa mais da fill-regionfunção do que do recuo.

  • Selecione essa linha e faça M-x fill-region.
  • Selecione o mesmo, agora divida em várias linhas e faça M-x indent-region.

Porém, isso não inserirá novas linhas nos pontos exatos, como mostrado no seu exemplo. Simplesmente ajustará a linha nas colunas de preenchimento.

Kaushal Modi
fonte
1
bem, isso é alguma coisa. Talvez o que eu queria não fosse viável de qualquer maneira. Talvez eu espere um pouco mais, caso alguém tenha uma solução mágica para um recorte agressivo mais inteligente ... Se nada mais acontecer, vou marcar isso como resposta.
Emmanuel Touzery
@EmmanuelTouzery O que você deseja é possível com pouco esforço, desde que as regras para inserir a nova linha sejam consistentes. No seu exemplo de resultado formatado, vejo que você não tem uma nova linha depois de entrar {, {"menu":mas você tem uma depois {de {"id":. Não conheço JSON e, portanto, sua resposta formatada provavelmente tem um padrão que me falta. Mas se você puder atualizar sua pergunta com um conjunto de regras para inserir essa nova linha, alguém poderá encontrar a resposta que deseja.
Kaushal Modi 5/05
Eu pensei que teria existido para qualquer idioma, incluindo regras específicas de idioma. Por exemplo, {na primeira linha para java, na próxima linha para C #, digamos, e assim por diante.
Emmanuel Touzery
(em outras palavras, algo como gofmt, mas para qualquer idioma) - gofmt.com
Emmanuel Touzery
19

json.elpacote fornece json-pretty-print-buffer. Isto é o que produz para o seu exemplo:

{
  "menu": {
    "popup": {
      "menuitem": [
        {
          "onclick": "CreateNewDoc()",
          "value": "New"
        },
        {
          "onclick": "OpenDoc()",
          "value": "Open"
        },
        {
          "onclick": "CloseDoc()",
          "value": "Close"
        }
      ]
    },
    "value": "File",
    "id": "file"
  }
}

Parece bastante decente para mim.

wvxvw
fonte
2
Sim, na verdade, eu vi no github.com/gongo/json-reformat que "do emacs 24.4 json-pretty-printe json-pretty-print-buffer(especificações semelhantes às json-reformat-region) estavam incluídas.". Mas eu pensei que o emacs poderia ter uma função que funcionaria para todos os idiomas (específicos para cada idioma popular de modo principal), o que, como se vê, não funciona.
Emmanuel Touzery
esta é a resposta correta
Joe Heyming
6

De acordo com a dica aqui , você pode usar o comando externo para formatar uma região no seu arquivo Json:

(defun json-format ()
  (interactive)
  (save-excursion
    (shell-command-on-region (region-beginning)
                             (region-end)
                             "python -m json.tool"
                             (buffer-name)
                             t)))

Você pode estendê-lo facilmente para formatar todo o buffer:

(defun json-format ()
  (interactive)
  (save-excursion
    (shell-command-on-region (point-min)
                             (point-max)
                             "python -m json.tool"
                             (buffer-name) t))) 

O Emacs não possui ferramenta de formatação para linguagens de programação ( exceto Lisp ), apenas comandos de indentação.

Tu Do
fonte
1
Descobri M-x json-reformat-regionque é spacemacsfornecido com e funciona, mas sim, eu gostaria disso para qualquer idioma e sempre com o mesmo atalho, com base no modo principal ... Parece que isso não é suportado, muito ruim ...
Emmanuel Touzery
1
Para formatar corretamente um idioma, você precisa de um analisador de idioma real. O Emacs possui analisadores de idiomas internos para alguns idiomas, mas apenas o analisador Lisp interno é usado recentemente para reformatação de código, como o link para a demonstração acima. Se existem formatadores externos, é fácil integrar-se ao Emacs, por exemplo clang-format.
Tu Do
2

Para este cenário específico, json-pretty-printirá definir a massa destacada de json.

Fergie
fonte
1

BTW, para os principais modos de usar o SMIE como seu mecanismo de indentação, há uma parte do que você precisa para isso na forma de um auto-fill-modesuporte. Penso fill-paragraphou fill-regionnão vou fazer um bom trabalho, mas se você colocar seu código em uma única linha, vá para o final dessa linha e faça M-: (smie-auto-fill)-o com bons resultados (provavelmente não perfeito por um longo período).

Stefan
fonte