Jak ładnie sformatować kod (automatyczne wstawianie nowego wiersza, wcięcia itp.)?

24

Używam, spacemacsale prawdopodobnie jest to wiedza wymagająca tutaj.

Mam plik JSON z jedną długą linią, powiedzmy ten JSON z json.org/example:

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

Chciałbym, aby emacs to powtórzył, co dla mnie oznacza, że ​​nie zmieniam znaku po lewej stronie na odpowiedni poziom wcięcia, ale przerywam linię w kilku wierszach.

Jeśli użyję spacemacs/indent-region-or-buffer( SPC j =), tekst w ogóle się nie zmieni.

Jak mogłem poprosić emacsa, aby rzeczywiście przełamał tę długą linię i był gotowy na coś takiego:

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

Nie interesuje mnie odpowiedź specyficzna dla JSON, na przykład uważam, że intelliJ robi to dla dowolnego obsługiwanego języka (java, json ...). Sądzę, że jest to osiągalne dla każdego emacsa językowego, który ma tryb główny lub, powiedzmy, najpopularniejsze.

EDYCJA Odkryłem, M-x json-reformat-regionże jest spacemacsdostarczany z i działa, ale tak, chciałbym to dla każdego języka i zawsze z tym samym skrótem, w oparciu o tryb główny ...

EDIT2 Ok, więc doszedłem do wniosku, że jest on zaimplementowany dla różnych języków, przynajmniej JSON i lisp, prawdopodobnie innych, i byłoby jeszcze łatwiej (XML / XHTML, go, który ma go-fmt, a także używa clang). Jednak nie ma ogólnej nazwy funkcji, która by to zrobiła dla wszystkich języków. Jest tu miejsce na implementację go w spacemacswarstwach dla różnych języków ... Nie znalazłem jednak implementacji X / HTML, co mnie trochę zaskakuje.

Emmanuel Touzery
źródło
3
Dla HTML / JS / CSS: web-beautiful.el. To jest najlepsze, jakie znalazłem, ale zależy to od node.js.
niania

Odpowiedzi:

10

Wygląda na to, że potrzebujesz fill-regionfunkcji bardziej niż wcięcia.

  • Wybierz tę linię i zrób M-x fill-region.
  • Wybierz to samo, teraz podzielone na wiele linii i zrób M-x indent-region.

Nie spowoduje to jednak wstawienia nowych wierszy w dokładnie takich punktach, jak pokazano w przykładzie. Po prostu dopasuje linię do kolumn wypełnienia.

Kaushal Modi
źródło
1
to jest coś. Może i tak nie chciałem tego, czego chciałem. Może poczekam trochę dłużej, na wypadek, gdyby ktoś znalazł magiczne rozwiązanie dla mądrzejszego agresywnego wcięcia ... Jeśli nic więcej się nie pojawi, zaznaczę to jako odpowiedź.
Emmanuel Touzery
@EmmanuelTouzery To, czego chcesz, można osiągnąć przy niewielkim elisp, o ile zasady wstawiania nowej linii są spójne. W twoim przykładzie sformatowanego wyniku widzę, że nie masz nowego wiersza po {za, {"menu":ale masz go po {za {"id":. Nie znam JSON, więc twoja sformatowana odpowiedź prawdopodobnie ma wzór, którego mi brakuje. Ale jeśli możesz zaktualizować swoje pytanie za pomocą zestawu zasad wstawiania tej nowej linii, wtedy ktoś może znaleźć odpowiedź, którą chcesz.
Kaushal Modi
Pomyślałem, że byłoby to możliwe w przypadku każdego języka, w tym zasad specyficznych dla danego języka. Na przykład {w pierwszym wierszu dla java, w następnym wierszu dla C #, powiedzmy, i tak dalej.
Emmanuel Touzery
(innymi słowy, coś w stylu innym gofmtniż język) - gofmt.com
Emmanuel Touzery
19

json.elpakiet zapewnia json-pretty-print-buffer. Oto, co tworzy dla twojego przykładu:

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

Wydaje mi się całkiem przyzwoity.

wvxvw
źródło
2
Tak, w rzeczywistości widziałem na github.com/gongo/json-reformat, że „Od emacsa 24.4 json-pretty-printi json-pretty-print-buffer(podobnych specyfikacji jak json-reformat-region) zostało dołączone”. Ale myślałem, że emacs może mieć funkcję, która będzie działać dla wszystkich języków (specyficznych dla każdego popularnego języka trybu głównego), czego, jak się okazuje, nie ma.
Emmanuel Touzery
to poprawna odpowiedź
Joe Heyming
6

Zgodnie z wskazówką tutaj możesz użyć zewnętrznego polecenia, aby sformatować region w pliku Json:

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

Możesz go łatwo rozszerzyć, aby sformatować cały bufor:

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

Emacs nie ma narzędzia do formatowania języków programowania ( z wyjątkiem Lisp ), tylko polecenia wcięcia.

Do zrobienia
źródło
1
Odkryłem, M-x json-reformat-regionże jest spacemacsdostarczany z i działa, ale tak, chciałbym to dla każdego języka i zawsze z tym samym skrótem, opartym na trybie głównym ... Wygląda na to, że nie jest to obsługiwane, szkoda ...
Emmanuel Touzery
1
Aby poprawnie sformatować język, potrzebujesz rzeczywistego parsera językowego. Emacs ma wbudowane parsery językowe dla niektórych języków, ale tylko wbudowany parser Lisp jest ostatnio używany do formatowania kodu, jako link do powyższej wersji demonstracyjnej. Jeśli istnieją zewnętrzne formaterery, łatwo je zintegrować z Emacsem, tj clang-format.
Tu Do
2

W tym konkretnym scenariuszu json-pretty-printuwidoczni wyróżnioną bryłę jsona.

Fergie
źródło
1

BTW, w przypadku głównych trybów wykorzystujących SMIE jako silnik wcięcia, jest część tego, czego potrzebujesz w postaci auto-fill-modewsparcia. Myślę, fill-paragraphczy fill-regionnie zrobi dobrą robotę, ale jeśli umieścić swój kod na jednej linii, a następnie przejść do końca tej linii i zrobić M-: (smie-auto-fill)to powinna dać rozsądnych wyników (prawdopodobnie nie doskonalić przez długi odcinek, tho).

Stefan
źródło