Emacs: Check Parenthesis/Brackets Balance

By Xah Lee. Date: . Last updated: .

Here's a command to check if parentheses or brackets or curly quotes are balanced.

(defun xah-check-parens-balance ()
  "Check if there are unbalanced parentheses/brackets/quotes in current bufffer or selection.
If so, place cursor there, print error to messages buffer.

URL `http://xahlee.info/emacs/emacs/emacs_check_parens_balance.html'
Created: 2019-09-18
Version: 2023-08-12"
  (interactive)
  (let* ((xbracket-alist
          (list (cons ?“ ?”)
                (cons ?‹ ?›)
                (cons ?« ?»)
                (cons ?【 ?】)
                (cons ?〖 ?〗)
                (cons ?〈 ?〉)
                (cons ?《 ?》)
                (cons ?「 ?」)
                (cons ?『 ?』)
                (cons ?〔 ?〕)
                (cons ?{ ?})
                (cons ?\[ ?\])
                (cons ?\(?\))))
         ;; regex string of all pairs to search.
         (xbregex
          (let ((xtempList nil))
            (mapc
             (lambda (x)
               (push (char-to-string (car x)) xtempList)
               (push (char-to-string (cdr x)) xtempList))
             xbracket-alist)
            (regexp-opt xtempList)))
         xp1
         xp2
         ;; each entry is a vector [char position]
         (xstack '())
         (xchar nil)
         xpos
         xis-closing-char-p
         xmatched-open-char
         )
    (if (region-active-p)
        (setq xp1 (region-beginning) xp2 (region-end))
      (setq xp1 (point-min) xp2 (point-max)))
    (save-restriction
      (narrow-to-region xp1 xp2)
      (progn
        (goto-char (point-min))
        (while (re-search-forward xbregex nil "move")
          (setq xpos (point))
          (setq xchar (char-before))
          (progn
            (setq xis-closing-char-p (rassoc xchar xbracket-alist))
            (if xis-closing-char-p
                (progn
                  (setq xmatched-open-char
                        (if xis-closing-char-p
                            (car xis-closing-char-p)
                          (error "logic error 64823. The char %s has no matching pair."
                                 (char-to-string xchar))))
                  (if xstack
                      (if (eq (aref (car xstack) 0) xmatched-open-char)
                          (pop xstack)
                        (push (vector xchar xpos) xstack))
                    (progn
                      (goto-char xpos)
                      (error "First mismtach found. the char %s has no matching pair."
                             (char-to-string xchar)))))
              (push (vector xchar xpos) xstack))))
        (if xstack
            (let (xfirst xcharT xposT)
              (setq xfirst (car xstack)
                    xcharT (aref xfirst 0)
                    xposT (aref xfirst 1))
              (goto-char xposT)
              (message "Mismtach found. The char %s
at position %s
has no matching pair."
                       (char-to-string xcharT)
                       xposT))
          (print "All brackets/quotes match."))))))