¿Cómo formatear un código bonito (insertar líneas nuevas, sangría, etc.)?

24

Estoy usando, spacemacspero presumiblemente es el conocimiento de emacs que se requiere aquí.

Tengo un archivo JSON con una sola línea larga, digamos este JSON de json.org/example:

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

Me gustaría que emacs reindenté esto, lo que significa que no cambiaré el carácter más a la izquierda de la línea al nivel de sangría adecuado, sino que la dividiré en varias líneas.

Si uso spacemacs/indent-region-or-buffer( SPC j =), el texto no cambia en absoluto.

¿Cómo podría pedirle a emacs que rompa realmente esta larga línea y reindent para obtener algo como esto:

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

No estoy interesado en una respuesta específica de JSON, por ejemplo, creo que intelliJ hace eso para cualquier idioma que admita (java, json ...). Creo que es posible para cualquier idioma en el que emacs tenga un modo principal, o digamos los más populares.

EDITAR Descubrí M-x json-reformat-regionque spacemacsviene con y funciona, pero sí, me gustaría eso para cualquier idioma y con siempre el mismo acceso directo, basado en el modo principal ...

EDIT2 Ok, entonces mi conclusión es que está implementado para varios idiomas, JSON y lisp al menos, presumiblemente otros, y sería fácil para aún más (XML / XHTML, vaya que tiene go-fmt y también usa clang). Sin embargo, no hay un nombre de función genérico que lo haga para todos los idiomas. Aquí hay espacio para implementarlo en spacemacscapas para los distintos idiomas ... Sin embargo, no encontré una implementación X / HTML, lo que me sorprende un poco.

Emmanuel Touzery
fuente
3
Para HTML / JS / CSS: web-beautiful.el. Este es el mejor que he encontrado, pero depende de node.js.
niñera

Respuestas:

10

Parece que necesita la fill-regionfunción más que la sangría.

  • Selecciona esa línea y hazlo M-x fill-region.
  • Seleccione lo mismo, ahora divida en varias líneas y haga M-x indent-region.

Sin embargo, eso no insertará nuevas líneas en los puntos exactos como se muestra en su ejemplo. Simplemente hará que la línea encaje en las columnas de relleno.

Kaushal Modi
fuente
1
bueno, eso es algo. Tal vez lo que quería no era alcanzable de todos modos. Tal vez esperaré un poco más en caso de que alguien tenga una solución mágica para una sangría agresiva más inteligente ... Si no surge nada más, marcaré esto como la respuesta.
Emmanuel Touzery
@EmmanuelTouzery Lo que desea se puede lograr con poco elisp siempre y cuando las reglas para insertar la nueva línea sean consistentes. En el ejemplo de resultado con formato, veo que usted no tiene una nueva línea después {de {"menu":Pero usted tiene una después {de {"id":. No conozco JSON, por lo que su respuesta formateada probablemente tenga un patrón que me falta. Pero si puede actualizar su pregunta con un conjunto de reglas para insertar esa nueva línea, entonces alguien puede encontrar la respuesta que desea.
Kaushal Modi
Pensé que habría existido para cualquier idioma, incluidas las reglas específicas del idioma. Por ejemplo {en la primera línea para java, en la siguiente línea para C # digamos, y así sucesivamente.
Emmanuel Touzery
(en otras palabras, algo así como gofmtpara cualquier idioma) - gofmt.com
Emmanuel Touzery
19

json.elEl paquete proporciona json-pretty-print-buffer. Esto es lo que produce para su ejemplo:

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

Me parece bastante decente.

wvxvw
fuente
2
Sí, de hecho, vi en github.com/gongo/json-reformat que "De emacs 24.4, json-pretty-printy json-pretty-print-buffer(especificaciones similares a json-reformat-region) se incluyeron". Pero pensé que emacs podría tener una función que funcionaría para todos los idiomas (específicos para cada lenguaje de modo principal popular), que, como resulta, no lo hace.
Emmanuel Touzery
esta es la respuesta correcta
Joe Heyming
6

De acuerdo con el consejo aquí , puede usar un comando externo para formatear una región en su archivo Json:

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

Puede extenderlo fácilmente para formatear todo el búfer:

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

Emacs no tiene una herramienta de formateo para lenguajes de programación ( excepto Lisp ), solo comandos de sangría.

Tu Do
fuente
1
Descubrí M-x json-reformat-regionque spacemacsviene con y funciona, pero sí, me gustaría eso para cualquier idioma y siempre con el mismo acceso directo, basado en el modo principal ... Parece que esto no es compatible, muy mal ...
Emmanuel Touzery
1
Para formatear correctamente un idioma, necesita un analizador de idioma real. Emacs tiene analizadores de idiomas integrados para algunos idiomas, pero solo el analizador Lisp incorporado se ha utilizado recientemente para reformatear el código, como el enlace a la demostración anterior. Si existen formateadores externos, es fácil de integrar con Emacs, es decir clang-format.
Tu Do
2

Para este escenario específico, json-pretty-printse embellecerá la masa resaltada de json.

Fergie
fuente
1

Por cierto, para los modos principales que usan SMIE como su motor de sangría, hay algo de lo que necesita para eso en forma de auto-fill-modesoporte. Creo fill-paragrapho fill-regionno haré un buen trabajo, pero si pones tu código en una sola línea, ve al final de esa línea y hazlo M-: (smie-auto-fill), debería dar buenos resultados (probablemente no sea perfecto por un largo tramo, aunque).

Stefan
fuente