Emacs has several packages for dealing with parentheses. Emacs comes with ways to highlight the matching parenthesis when you're on one; try show-paren-mode. One of the newer add-on packages is Nikolaj Schumacher's highlight-parentheses mode, which shows the parentheses that enclose the current cursor position. I tried modifying it to highlight the containing expressions instead of only their parentheses:

(defun hl-paren-highlight ()
  "Highlight the parentheses around point."
  (unless (= (point) hl-paren-last-point)
    (save-excursion
      (let ((pos (point))
            (match-pos (point))
            (level -1)
            (max (1- (length hl-paren-overlays))))
        (while (and match-pos (< level max))
          (setq match-pos
                (when (setq pos (cadr (syntax-ppss pos)))
                  (ignore-errors (scan-sexps pos 1))))
          (when match-pos
            (if (eq 'expression hl-paren-type)
                (hl-paren-put-overlay pos match-pos (incf level))
              (hl-paren-put-overlay pos (1+ pos) (incf level))
              (hl-paren-put-overlay (1- match-pos) match-pos 
                (incf level)))
            ))
        (while (< level max)
          (hl-paren-put-overlay nil nil (incf level)))))
    (setq hl-paren-last-point (point))))

Unfortunately, as you can see, it's a mess. I tried better colors (white, gray, etc.) but I just couldn't make it usable. So I gave up on highlighting the regions and went back to highlighting just the parentheses. It's a bit better:

(defun hl-paren-highlight ()
  "Highlight the parentheses around point."
  (unless (= (point) hl-paren-last-point)
    (save-excursion
      (let ((pos (point))
            (match-pos (point))
            (level -1)
            (max (1- (length hl-paren-overlays))))
        (while (and match-pos (< level max))
          (setq match-pos
                (when (setq pos (cadr (syntax-ppss pos)))
                  (ignore-errors (scan-sexps pos 1))))
          (when match-pos
            (if (eq 'expression hl-paren-type)
                (hl-paren-put-overlay pos match-pos (incf level))
              (hl-paren-put-overlay pos (1+ pos) (incf level))
              (hl-paren-put-overlay (1- match-pos) match-pos 
                (incf level)))
            ))
        (while (< level max)
          (hl-paren-put-overlay nil nil (incf level)))))
    (setq hl-paren-last-point (point))))

However it's still a bit too … colorful. So I changed it to simply make the enclosing parentheses bold:

(defun hl-paren-highlight ()
  "Highlight the parentheses around point."
  (unless (= (point) hl-paren-last-point)
    (save-excursion
      (let ((pos (point))
            (match-pos (point))
            (level -1)
            (max (1- (length hl-paren-overlays))))
        (while (and match-pos (< level max))
          (setq match-pos
                (when (setq pos (cadr (syntax-ppss pos)))
                  (ignore-errors (scan-sexps pos 1))))
          (when match-pos
            (if (eq 'expression hl-paren-type)
                (hl-paren-put-overlay pos match-pos (incf level))
              (hl-paren-put-overlay pos (1+ pos) (incf level))
              (hl-paren-put-overlay (1- match-pos) match-pos 
                (incf level)))
            ))
        (while (< level max)
          (hl-paren-put-overlay nil nil (incf level)))))
    (setq hl-paren-last-point (point))))

That's nicer, although perhaps too subtle. I added more bolding:

(defun hl-paren-highlight ()
  "Highlight the parentheses around point."
  (unless (= (point) hl-paren-last-point)
    (save-excursion
      (let ((pos (point))
            (match-pos (point))
            (level -1)
            (max (1- (length hl-paren-overlays))))
        (while (and match-pos (< level max))
          (setq match-pos
                (when (setq pos (cadr (syntax-ppss pos)))
                  (ignore-errors (scan-sexps pos 1))))
          (when match-pos
            (if (eq 'expression hl-paren-type)
                (hl-paren-put-overlay pos match-pos (incf level))
              (hl-paren-put-overlay pos (1+ pos) (incf level))
              (hl-paren-put-overlay (1- match-pos) match-pos 
                (incf level)))
            ))
        (while (< level max)
          (hl-paren-put-overlay nil nil (incf level)))))
    (setq hl-paren-last-point (point))))

It bolds the parentheses and also the first s-expression inside the opening parenthesis. It doesn't understand when the parentheses begin a form (instead of all the other uses of parentheses), so it sometimes highlights the first s-expression even when it's not special in any way. Despite this wart, I like this form of highlighting so far.

Update: [2007-05-29] However, there is one more thing I wanted. I de-emphasize parentheses by using a lighter color for them; I want the enclosing parentheses to be bold and black. However I want the enclosing first s-expressions to be bold, but not necessarily black. Note in the above example the keywords are normally blue, but when enclosing the current point they are black. I fixed this by adding separate highlighting for the enclosing parentheses and the first s-expression:

(defun hl-paren-highlight ()
  "Highlight the parentheses around point."
  (unless (= (point) hl-paren-last-point)
    (save-excursion
      (let ((pos (point))
            (match-pos (point))
            (level -1)
            (max (1- (length hl-paren-overlays))))
        (while (and match-pos (< level max))
          (setq match-pos
                (when (setq pos (cadr (syntax-ppss pos)))
                  (ignore-errors (scan-sexps pos 1))))
          (when match-pos
            (if (eq 'expression hl-paren-type)
                (hl-paren-put-overlay pos match-pos (incf level))
              (hl-paren-put-overlay pos (1+ pos) (incf level))
              (hl-paren-put-overlay (1- match-pos) match-pos 
                (incf level)))
            ))
        (while (< level max)
          (hl-paren-put-overlay nil nil (incf level)))))
    (setq hl-paren-last-point (point))))

I'm pretty happy with this variant of highlight-parentheses.el.

Update: [2014-05-10] Also check out the rainbow-blocks and rainbow-delimiters modes. For Python or Ruby code, highlight-indentation-mode may be useful. Update: [2019-08-05] Also see prism.

Labels:

6 comments:

Amit wrote at Wednesday, May 23, 2007 at 6:53:00 PM PDT

lemonodor has some other packages listed on his blog.

Anonymous wrote at Thursday, July 26, 2007 at 1:05:00 PM PDT

Any chance you could post a link to your version?

Amit wrote at Sunday, August 5, 2007 at 10:17:00 AM PDT

My version is pretty messy and doesn't work reliably, so I didn't put it up. A few days after Anonymous asked, Nikolaj put up a new version with optional background highlighting and bolding. It doesn't highlight the first sexp; I might try patching it to support that.

Amit wrote at Tuesday, September 21, 2010 at 7:49:00 AM PDT

Also see rainbow-delimiters.

Anonymous wrote at Monday, November 21, 2011 at 4:20:00 AM PST

See also HighlightSexp

Amit wrote at Thursday, February 2, 2012 at 8:57:00 AM PST

Also see HighlightSexps (highlights multiple levels, unlike HighlightSexp)