Как красиво отформатировать код (автоматическая вставка новых строк, отступа и т. Д.)?

24

Я использую, spacemacsно, вероятно, это знание emacs, которое требуется здесь.

У меня есть файл JSON с одной длинной строкой, скажем, этот JSON с json.org/example:

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

Я бы хотел, чтобы emacs переопределил это, что означает, что я не изменяю крайний левый символ строки на нужный уровень отступа, а разбиваю строку на несколько строк.

Если я использую spacemacs/indent-region-or-buffer( SPC j =), то текст вообще не изменяется.

Как я могу попросить emacs разорвать эту длинную строку и сделать отступ, чтобы получить что-то вроде этого:

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

Меня не интересует специфичный для JSON ответ, например, я считаю, что intelliJ делает это для любого языка, который он поддерживает (java, json ...). Я думаю, что это достижимо для любого языка, в котором Emacs имеет основной режим или, скажем, самые популярные.

РЕДАКТИРОВАТЬ Я обнаружил, M-x json-reformat-regionчто spacemacsпоставляется с и работает, но да, я хотел бы это для любого языка и с всегда одним и тем же ярлыком, основанным на основном режиме ...

EDIT2 Хорошо, поэтому я пришел к выводу, что он реализован для разных языков, по крайней мере, JSON и lisp, предположительно для других, и это будет легко сделать еще больше (XML / XHTML, go с go-fmt, а также с использованием clang). Однако нет общего имени функции, которое бы делало это для всех языков. Здесь есть место для его реализации в spacemacsслоях для разных языков ... Однако я не нашел реализации X / HTML, что меня немного удивляет.

Эммануэль Тузери
источник
3
Для HTML / JS / CSS: web-beautiful.el. Это лучшее, что я нашел, но это зависит от node.js.
няня

Ответы:

10

Похоже, вам нужна fill-regionфункция больше, чем отступ.

  • Выберите эту строку и сделайте M-x fill-region.
  • Выберите то же самое, теперь разбейте на несколько строк и сделайте M-x indent-region.

Это, однако, не вставит новые строки в точных точках, как показано в вашем примере. Он просто поместит линию в столбцы заливки.

Каушал Моди
источник
1
ну, это что-то Может быть, то, что я хотел, было не достижимо в любом случае. Может быть, я подожду немного дольше, если у кого-то найдется волшебное решение для более умного агрессивного отступа ... Если ничего не подойдет, я отмечу это как ответ.
Эммануэль Тузери
@EmmanuelTouzery То, что вы хотите, достижимо с небольшим elisp, если правила для вставки новой строки являются последовательными. В вашем примере с отформатированным результатом я вижу, что у вас нет новой строки после {in, {"menu":но у вас есть одна после {in {"id":. Я не знаю JSON, и поэтому в вашем отформатированном ответе, вероятно, есть шаблон, который мне не хватает. Но если вы можете обновить свой вопрос с помощью набора правил для вставки этой новой строки, тогда кто-то может придумать ответ, который вы хотите.
Каушал Моди
Я думал, что это существовало бы для любого языка, включая языковые правила. Например, {в первой строке для Java, в следующей строке для C #, скажем, и так далее.
Эммануэль Тузери
(другими словами, что-то вроде, gofmtно для любого языка) - gofmt.com
Emmanuel Touzery
19

json.elПакет обеспечивает json-pretty-print-buffer. Вот что он производит для вашего примера:

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

Кажется довольно приличным для меня.

wvxvw
источник
2
Да, на самом деле я видел на github.com/gongo/json-reformat, что «От emacs 24.4, json-pretty-printи json-pretty-print-buffer(аналогичные спецификации, как json-reformat-region) был в комплекте». Но я думал, что в emacs может быть функция, которая будет работать для всех языков (специфичных для каждого популярного языка основного режима), чего, как оказалось, нет.
Эммануэль Тузери
это правильный ответ
Джо Хейминг
6

Согласно кончику здесь , вы можете использовать внешнюю команду для форматирования области в файле Json:

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

Вы можете легко расширить его для форматирования всего буфера:

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

В Emacs нет инструмента форматирования для языков программирования ( кроме Lisp ), только команды отступа.

Ту До
источник
1
Я обнаружил, M-x json-reformat-regionчто spacemacsпоставляется с и работает, но да, я хотел бы, чтобы это было для любого языка и с всегда одним и тем же ярлыком, основанным на основном режиме ... Кажется, что это не поддерживается, слишком плохо ...
Эммануэль Тузери
1
Чтобы правильно отформатировать язык, вам нужен реальный синтаксический анализатор языка. Emacs имеет встроенные парсеры языков для некоторых языков, но недавно для переформатирования кода используется только встроенный парсер Lisp, как показано в демонстрационной ссылке выше. Если существуют внешние форматтеры, легко интегрируется с Emacs , т.е. clang-format.
Ту До
2

Для этого конкретного сценария json-pretty-printбудет предварительно выделен выделенный кусок JSON.

Fergie
источник
1

Кстати, для основных режимов, использующих SMIE в качестве механизма отступа, есть некоторая часть того, что вам нужно для этого в виде auto-fill-modeподдержки. Я думаю, fill-paragraphили fill-regionне сделаю хорошую работу, но если вы поместите свой код в одну строку, то перейдите в конец этой строки и сделайте M-: (smie-auto-fill)это, чтобы получить нормальные результаты (вероятно, не идеальные при длительном отрезке, хотя).

Стефан
источник