1

The documentation of hs-minor-mode explains:

In C mode and related modes, blocks are delimited by braces, while in Lisp mode they are delimited by parentheses.

I use the mode to collapse objects while reading JSON files. This works fine, because JSON objects use curly braces. But it does not work for JSON arrays, because arrays are delimited by box brackets ([]).

Is it possible to customize the delimiter in order to make curly braces and box brackets valid delimiters to collapse blocks?

Example:

{
  "list": [
    {
      "id": 1
    },
    {
      "id": 2
    },
    {
      "id": 3
    },
    {
      "id": 4
    },
    {
      "id": 5
    }
  ]
}

When I call hs-hide-block from within the array, the object collapses to:

{...}

But I only want to collapse the array:

{
  "list": [...]
}

And I still want to be able to collapse objects.

I am using "GNU Emacs 27.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.24, cairo version 1.16.0) of 2021-03-28, modified by Debian". JSON files are opened in "JavaScript mode defined in ‘js.el’". I think this is js-mode.

1
  • Could you update your question please to let us know which major mode you are using for JSON files: json-mode, js2-mode or js-mode? A precise answer will depend on that salient fact. Commented Mar 8, 2022 at 22:10

2 Answers 2

1

M-x finder-commentary RET hideshow RET says:

Normally, hideshow tries to determine appropriate values for block
and comment definitions by examining the buffer's major mode.  If
there are problems, hideshow will not activate and in that case you
may wish to override hideshow's heuristics by adding an entry to
variable `hs-special-modes-alist'.  Packages that use hideshow should
do something like:

  (add-to-list 'hs-special-modes-alist '(my-mode "{{" "}}" ...))

If you have an entry that works particularly well, consider
submitting it for inclusion in hideshow.el.  See docstring for
`hs-special-modes-alist' for more info on the entry format.

See also variable `hs-set-up-overlay' for per-block customization of
appearance or other effects associated with overlays.  For example:

(setq hs-set-up-overlay
      (defun my-display-code-line-counts (ov)
        (when (eq 'code (overlay-get ov 'hs))
          (overlay-put ov 'display
                       (propertize
                        (format " ... <%d>"
                                (count-lines (overlay-start ov)
                                             (overlay-end ov)))
                        'face 'font-lock-type-face)))))

The default value of hs-special-modes-alist is:

  '((c-mode "{" "}" "/[*/]" nil nil)
    (c++-mode "{" "}" "/[*/]" nil nil)
    (bibtex-mode ("@\\S(*\\(\\s(\\)" 1))
    (java-mode "{" "}" "/[*/]" nil nil)
    (js-mode "{" "}" "/[*/]" nil))

It's not clear to me whether you're using the standard js-mode for JSON or if you're using the json-mode package from GNU ELPA. The latter derives from the former, however that's only relevant here if you're using Emacs 28+ (refer to bug #39354), so you'll have to decide which of these you need:

(push '(js-mode "[[{]" "[]}]" "/[*/]") hs-special-modes-alist)
(push '(json-mode "[[{]" "[]}]") hs-special-modes-alist)

Be sure to revert the JSON buffer for testing.

5
  • I do not understand, how this answers the question. I see I can change START and END. But I do not see, how to specify multiple corresponding STARTs and ENDs.
    – ceving
    Commented Mar 8, 2022 at 14:42
  • I misinterpreted some things sorry, but those docs do provide for matching multiple characters. I'll update the answer.
    – phils
    Commented Mar 8, 2022 at 20:26
  • I still do not understand why, but the regexps [[{] and []}] seem to work. Thank you!
    – ceving
    Commented Mar 9, 2022 at 19:26
  • They work as long as the JSON data is valid. If the buffer contains miss-balanced braces, they will be collapsed to this: [...}.
    – ceving
    Commented Mar 9, 2022 at 19:33
  • [[{] being a character alternative [...] matching either [ or {. As a START pattern, hideshow will look for that, and then find the balancing end-point for that, which should be a matching ] or } as matched by []}]. I'm not surprised if invalid JSON causes issues, but "garbage in, garbage out" as they say! I don't imagine you're expecting Emacs to fix invalid data :)
    – phils
    Commented Mar 9, 2022 at 21:58
0

I may be misunderstanding what you're requesting. I tried using hide/show with some JSON code in js-mode as a quick experiment just now, and hs-minor-mode seemed to work OK.

On the other hand, JSON does not (in general) have any notion of a comment, so you might want to use an impossible-to-match regexp for the COMMENT-START part of the entry for the mode in variable hs-special-modes-alist. You can use the regexp "^\b$" for that - it can't be matched.

(setq hs-special-modes-alist '((c-mode "{" "}" "/[*/]" nil nil)
                               (c++-mode "{" "}" "/[*/]" nil nil)
                               (bibtex-mode ("@\\S(*\\(\\s(\\)" 1))
                               (java-mode "{" "}" "/[*/]" nil nil)
                               ;; (js-mode "{" "}" "/[*/]" nil) ; <=== Remove
                               (js-mode "{" "}" "^\b$" nil) ; <=== Add
                               ))

But in that case, you'd probably really want to use some mode that's only for JSON, and not also for JavaScript (which has comments).

If you need to use some such other mode, you can redefine hs-special-modes-alist to add an entry for the major mode you use for JSON data. For example, I tried with a json-mode from library json-mode.el by Josh Johnston, and that too seemed to work OK (just tested quickly, and again, I'm not sure what you're asking).

(setq hs-special-modes-alist '((c-mode "{" "}" "/[*/]" nil nil)
                               (c++-mode "{" "}" "/[*/]" nil nil)
                               (bibtex-mode ("@\\S(*\\(\\s(\\)" 1))
                               (java-mode "{" "}" "/[*/]" nil nil)
                               (js-mode "{" "}" "/[*/]" nil)
                               (json-mode "{" "}" "^\b$" nil)))

That leaves js-mode as it was, with comment behavior defined.

3
  • I did not use the wort "comment" at all in my question. But I have added an example to make the question more understandable.
    – ceving
    Commented Mar 8, 2022 at 16:49
  • No, you didn't use the word "comment". But hs-special-modes-alist has, as the 4th element of each language list, regexp COMMENT-START. The JSON language doesn't define/have comments. You can remove the effect of this regexp by giving it a value that can't be matched.
    – Drew
    Commented Mar 8, 2022 at 19:47
  • In theory this never-matching-regexp idea sounded right to me, but in practice I found hideshow mode going into an infinite loop when opening one specific json file I have. That file is well-formed but has unusual whitespace (blank lines), an artefact of being generated in sections by Org babel tangling. Thought I should mention it. Removing this json element from hs-special-modes-alist fixed it. Commented May 5, 2022 at 8:20

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.