I'm dealing with large files of output from Haskell code, most of which is debug info of stuff generating using Haskell's show.

The important thing about that is that it's a large file of things, nested in either parentheses, or square-brackets.

Something like this:

[(Assign (FormalReturn (Canonical {home = Local, name = "testState"})) (Label 3),ReachingDefs (fromList [(IntermedExpr (Label 22),Just (Label 22)),(FormalReturn (Canonical {home = Local, name = "testState"}),Just (Label 3))])),
(Assign (ActualParam (Label 12)) (Label 12),ReachingDefs (fromList [(IntermedExpr (Label 22),Just (Label 22)),(ActualParam (Label 12),Just (Label 12)),(ActualParam (Label 19),Just (Label 19)),(FormalParam Anything (Label 9),Just (Label 8)),(FormalParam Anything (Label 16),Just (Label 15)),(Ref (Canonical {home = Local, name = "ref"}),Just (Label 16))]))]

The way it's printed, there's no spacing or newlines, so it's pretty much unreadable.

I'm wondering, is there a quick command which will take output like this in a buffer, and space/indent it in an easy-to-read way, based on the hierarchical structure of the parentheses?


You can try reading the sexp and then printing with pp. The read function expects elisp syntax, so it's going to stumble on a few special chars like ,'#. So you'll have to work around that.

Since your example included commas, here's a hacky snippet that works with commas.

(defun endless/pretty-print-sexp ()
  "Pretty print the sexp after point.
This assumes that the following sexp does not
contain any instance of \"£$comma$£\". "
  (let* ((beg (point))
         (end (save-excursion
                (forward-sexp 1)
    (while (search-forward "," end 'noerror)
      (replace-match " £$comma$£ "))
    (goto-char beg)
    (let ((data (read (current-buffer))))
      (delete-region beg (point))
      (pp data (current-buffer)))
    (let ((end (point-marker)))
      (goto-char beg)
      (while (search-forward-regexp "[[:space:]\n\r]*£$comma$£" end 'noerror)
        (replace-match ","))
      (goto-char end))))

In the case of your example, here's what you're left with after invoking the command.

   (Canonical {home = Local, name = "testState" }))
  (Label 3), ReachingDefs
     (Label 22), Just
     (Label 22)),
     (Canonical {home = Local, name = "testState" }), Just
     (Label 3))])),
   (Label 12))
  (Label 12), ReachingDefs
     (Label 22), Just
     (Label 22)),
     (Label 12), Just
     (Label 12)),
     (Label 19), Just
     (Label 19)),
    (FormalParam Anything
                 (Label 9), Just
                 (Label 8)),
    (FormalParam Anything
                 (Label 16), Just
                 (Label 15)),
     (Canonical {home = Local, name = "ref" }), Just
     (Label 16))]))]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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