14

When writing lisp codes, sometimes I'm deep in a nested expression and all I want is to insert all the missing closing parenthesis. Right now I'm just inserting them until I get a mismatched paren, but it's not very efficient.
Is there any command to insert all the missing parentheses?

FYI, I'm using smartparens to automatically insert matching parens. Still, sometimes I just need to do this.

  • 2
    FWIW, Franz Lisp (before CL) had a feature where a ] acted as a super right paren, closing all open parens, as you request. – Drew Oct 7 '14 at 19:37
  • 2
    I've used the same methodology in the past. Since then I've started using paredit, which stops the problem before it starts. The only caveat is that pasting in code doesn't get the same balancing treatment. – elarson Oct 7 '14 at 22:46
6

Here's a function that closes all unclosed parentheses and other matched pairs. It relies on Emacs's sexp parsing. It only supports single-character matched pairs, so something like {- will be closed with }, not -}. For Lisp, that doesn't matter.

(defun close-all-parentheses ()
  (interactive "*")
  (let ((closing nil))
    (save-excursion
      (while (condition-case nil
         (progn
           (backward-up-list)
           (let ((syntax (syntax-after (point))))
             (case (car syntax)
               ((4) (setq closing (cons (cdr syntax) closing)))
               ((7 8) (setq closing (cons (char-after (point)) closing)))))
           t)
           ((scan-error) nil))))
    (apply #'insert (nreverse closing))))
  • IIUC, This requires that point not be inside any set of matched parenthesis. I was under the impression the OQ needed to work from some inside a lisp expression, where done parentheses will be mismatched but others won't. – Malabarba Oct 9 '14 at 7:34
  • @Malabarba This closes all previously-opened parentheses, whether they already had matching closing parentheses after point or not. That's how I understand the question, but it is admittedly not clear on this point. Under your interpretation, where would the closing delimiters be inserted? E.g. with ([-!-foo], do you insert ]) at point, or ) after foo]? – Gilles Oct 9 '14 at 7:59
  • from my understanding, if you have ([-!-foo], I would insert ) after foo]. But I could be wrong of course. Maybe @rlazo can elaborate. – Malabarba Oct 9 '14 at 8:22
  • for my use case, @Gilles is right, I don't care if the delimiters are closed after the point, I want to close everything before point. – rlazo Oct 9 '14 at 17:22
3

I've found out that if you have slime installed, there is a command to do this, called slime-close-all-parens-in-sexp

  • Hmm... so this appears to close on the current line. It might be nice if there was an approach that closed "the current block". This could be achieved by going to the end of the file and then moving backward sexp until something no closed in found. – Att Righ Dec 30 '17 at 22:24
1

A very primitive (and almost certainly wrong) way to do that would be

(defun buffer-needs-parens-fixing ()
  (save-excursion
    (condition-case nil
        (check-parens)
      (error (point)))))

(defun buffer-fix-parens ()
  (interactive)
  (while (buffer-needs-parens-fixing)
    (insert ")")))

Amongst other limitations, it assumes that all the parentheses that need inserting are:

  • closing ones
  • needed at the current location

I guess it might be just enough to be useful for your specific use-case

  • This gets stuck in an infinite loop if you have too many closing parentheses. – Emil Vikström Oct 8 '14 at 6:32
  • @EmilVikström yep, that's indeed not compatible with my first stated limitation :) – Sigma Oct 8 '14 at 13:24

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.