37

I'm using spacemacs but presumably it's emacs knowledge that's required here.

I have a JSON file with a single long line, let's say this JSON from json.org/example:

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

I would like emacs to reindent this, which means to me not change the leftmost character of line to the proper indentation level, but break the line in several lines.

If I use spacemacs/indent-region-or-buffer (SPC j =) then the text is not changed at all.

How could I ask from emacs to actually break this long line and reindent to get something like this:

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

I'm not interested in a JSON-specific answer, for instance I believe that intelliJ does that for any language it supports (java, json...). I would think it's achievable for any language emacs has a major mode for, or let's say the most popular ones.

EDIT I discovered M-x json-reformat-region that spacemacs ships with and works, but yes, I would like that for any language and with always the same shortcut, based on the major mode...

EDIT2 Ok so my conclusion is that it's implemented for various languages, JSON & lisp at least, presumably others, and it would be easy for yet more (XML/XHTML, go which has go-fmt and also using clang). However there's no generic function name that would do it for all the languages. There is space here to implement it in spacemacs layers for the various languages... I didn't find a X/HTML implementation though, which surprises me a bit.

2
  • 3
    For HTML/JS/CSS: web-beautiful.el. This is the best I've found, but it depends on node.js.
    – nanny
    May 5, 2015 at 18:33
  • It actually spells web-beautify.el Jan 15 at 13:18

7 Answers 7

16

It looks like you need the fill-region function more than the indentation.

  • Select that line and do M-x fill-region.
  • Select the same, now split across multiple lines, and do M-x indent-region.

That will, though, not insert new lines at the exact points as shown in your example. It will simply make the line fit in the fill columns.

4
  • 1
    well, that's something. Maybe what I wanted was not achievable anyway. Maybe I'll wait a little longer in case someone has a magical solution for a smarter aggressive indentation... If nothing else comes up I'll mark this as the answer. May 5, 2015 at 11:15
  • @EmmanuelTouzery What you want is achievable with little elisp as long as the rules for inserting the newline are consistent. In your example of formatted result, I see that you don't have a newline after { in {"menu": but you do have one after { in {"id":. I don't know JSON and so your formatted answer probably does have a pattern that I am missing. But if you can update your question with a set of rules for inserting that new line, then someone can come up with the answer you want. May 5, 2015 at 11:54
  • I thought that would have existed for any language, including language-specific rules. For instance { on the first line for java, on next line for C# let's say, and so on. May 5, 2015 at 12:04
  • (in other words, something like gofmt but for any language) -- gofmt.com May 5, 2015 at 12:08
36

json.el package provides json-pretty-print-buffer. This is what it produces for your example:

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

Seems pretty decent to me.

4
  • 2
    Yes in fact I saw on github.com/gongo/json-reformat that "From emacs 24.4, json-pretty-print and json-pretty-print-buffer (similar specifications as json-reformat-region) was bundled.". But I thought emacs could have a function that would work for all languages (specific for each popular major mode language), which it, as it turns out, doesn't. May 5, 2015 at 17:34
  • 1
    this is the correct answer Sep 11, 2019 at 16:35
  • In GNU ELPA's json-mode, this is available via C-c C-f
    – Stefan
    Jul 22, 2020 at 16:44
  • This works well if the buffer isn't screwed up already by trying M-x fill-region which can introduce new lines that makes this fail.
    – poleguy
    Jan 4, 2023 at 16:27
7

According to the tip here, you can use external command to format a region in your Json file:

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

You can easily extend it to format the whole buffer:

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

Emacs does not have formatting tool for programming languages (except for Lisp), only indentation commands.

2
  • 1
    I discovered M-x json-reformat-region that spacemacs ships with and works, but yes, I would like that for any language and with always the same shortcut, based on the major mode... It seems that this is not supported, too bad... May 5, 2015 at 12:30
  • 1
    To properly format a language, you need an actual language parser. Emacs has built-in language parsers for some languages, but only the built-in Lisp parser is recently used for code reformatting, as the link to the demo above. If external formatters exist, it is easy to integrate with Emacs i.e. clang-format.
    – Tu Do
    May 5, 2015 at 12:33
4

For this specific scenario M-x json-pretty-print will prettify the highlighted lump of json.

2

BTW, for major modes using SMIE as their indentation engine, there is some part of what you need for that in the form of an auto-fill-mode support. I think fill-paragraph or fill-region won't do a good job, but if you put your code onto a single line, then go to the end of that line and do M-: (smie-auto-fill) it should give sane results (probably not perfect by a long stretch, tho).

1

With emacs 26.3 you can just use the stock json-pretty-print function.

json-pretty-print is an interactive and compiled function defined in json.el.gz.

-- Emacs 26.3 documentation

select the region and M-x json-pretty-print.

I've just executed this procedure taking your example as input. Here is the result:

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

1

I use json-mode-beautify

GNU Emacs 24.3.1

;;; json-mode.el --- Major mode for editing JSON files.

;; Copyright (C) 2011-2014 Josh Johnston

;; Author: Josh Johnston
;; URL: https://github.com/joshwnj/json-mode
;; Version: 1.6.0
1
  • 1
    Please elaborate. So far, this is essentially a link-only answer, so it risks being deleted. Please describe what that mode does, wrt answering the question.
    – Drew
    Jul 22, 2020 at 14:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.