Small rainbow-delimiters tutorial

This post is a more up-to-date version of my older article Living with rainbow-delimiters-mode and more.

1. before installation

1.1. What is Rainbow Delimiters for?

Rainbow delimiters mode highlights lisp parens (i.e., parentheses) of different nesting depth in different colors in Emacs. It also highlights other nesting delimiters like square brackets (used in Emacs Lisp and Clojure) and curly brackets (used in Clojure). Hence the name rainbow-delimiters.

1.2. Isn’t good indentation enough for reading Lisp code? Why color parens then?

Indeed, indentation is enough for readability in most cases. I would advise Lisp beginners to try to rely on indentation alone as much as possible (rather than relying on colors of parens) to read Lisp code, even if they use rainbow-delimiters. Maybe think of rainbow-delimiters as training wheels.

While relying on indentation is enough for most cases, there are a few cases where colorful parens seem to help a lot, at least for me (maybe I’m still a Lisp beginner.). I will talk about what these few cases are later.

Beginners who use rainbow-delimiters and/or paredit should still indent Lisp code they write and still stay away from writing very long one liners.

1.3. Would it slow down my Emacs?

In my very old laptop, it didn’t slow down editing of org.el which is about 930k. If it slows for some buffers in your case, you may want to recall that rainbow-delimiters-mode is a minor mode that can be turned on and off individually on buffers.

2. How do I install rainbow-delimiters?

Install it from MELPA: assuming that you already have added MELPA to package-archives, you could just do M-x package-install and enter rainbow-delimiters to install it.

Then add the following to your init file.

(require 'rainbow-delimiters)

;; Enables rainbow-delimiters-mode in Emacs Lisp buffers
(add-hook 'emacs-lisp-mode-hook 'rainbow-delimiters-mode)

;; Enables rainbow-delimiters-mode in Clojure buffers.
(add-hook 'clojure-mode-hook 'rainbow-delimiters-mode)

;; enables rainbow-delimiters-mode in other Lisp mode buffers.
(add-hook 'lisp-mode-hook 'rainbow-delimiters-mode)

Those two lines are after-package-initialize code, that is, they should be placed somewhere after the (package-initialize) line in the init file.

After you save the init file and restart Emacs, you will see gray parens with a bit of rainbow colors in them when you open Emacs Lisp files or when you create a new one by typing C-x C-f ~/blahblah.el and writing some code. We will get to how to use stronger colors in parens later.

3. I see colors flickering when I am writing code. What’s going on?

This may be something you notice more easily if you use stronger colors. If every time you type a paren, other parens (below the current line) get recolored, that probably means that you are not using paredit or autopair that automatically inserts close parens (i.e., closing parentheses) for you.

If you are a Lisp beginner, you really need to use something like paredit or autopair, even if you may feel a bit restricted at first when using one. Think of them as a safari vehicle where you stay inside to protect yourself from fabulous lions, hungry crocodiles, angry unicorns.

4. customizations from the Customize interface

M-x customize-group RET rainbow-delimiters RET

It provides user options for turning off highlighting of some delimiters and you can also customize the faces used by the package.

5. other customizations

Customizing code examples in this section are usually after-package-initialize code. They are also after-load-theme code, i.e., they should be placed somewhere after the (load-theme ...) line in your init file, if you are using a theme.

5.1. using stronger colors

Some of you might want to use colors stronger than default. By strong, I mean more saturated, i.e., less gray. Use this code:

(require 'cl-lib)
(require 'color)
 for index from 1 to rainbow-delimiters-max-face-count
 (let ((face (intern (format "rainbow-delimiters-depth-%d-face" index))))
   (cl-callf color-saturate-name (face-foreground face) 30)))

There is a reason for default colors being subtle as the package author says “The default colors are intentionally subtle; they are unobtrusive enough to make the mode worth looking at even if you usually don’t like rainbow parentheses modes.”

5.2. making unmatched parens stand out more

Unmatched close parens are highlighted in a color that stands out by default. But if you customize rainbow delimiters to use strong colors, you have to customize the face for unmatched parens too so that they stand out again among all those strongly colorful parens.

This code, for example, will make unmatched parens display in bold red and with a strike through.

(set-face-attribute 'rainbow-delimiters-unmatched-face nil
                    :foreground 'unspecified
                    :inherit 'error
                    :strike-through t)

This code will make them display in violet background.

(require 'paren) ; show-paren-mismatch is defined in paren.el
(set-face-attribute 'rainbow-delimiters-unmatched-face nil
                    :foreground 'unspecified
                    :inherit 'show-paren-mismatch)

5.3. alternating dual color

I use the following code which is for alternating between just two colors.

(defvar my-paren-dual-colors
  '("hot pink" "dodger blue"))

(setq rainbow-delimiters-outermost-only-face-count 0)
(setq rainbow-delimiters-max-face-count 2)

(set-face-foreground 'rainbow-delimiters-depth-1-face
                     (elt my-paren-dual-colors 1))
(set-face-foreground 'rainbow-delimiters-depth-2-face
                     (elt my-paren-dual-colors 0))

The idea is to maximize eye detection of off-by-one paren depth difference especially in code that uses one space indent convention such as cond forms. I find that dual colored parens are very helpful in a few cases such as some defface forms, or let forms or cond forms where some lines are dense or where one space indent convention is used while the form is vertically spread out. See examples in appendix.

5.3.1. other dual color combinations

subtle colors:

'("#a07070" "#7070a0")

louder colors:

'("deep pink" "royal blue")

blending more into white background:

'("pink" "sky blue")

5.4. making the outermost parens stand out

If you want to have the outermost parens display in bold and black, use the following code.

(defface my-outermost-paren-face
  '((t (:weight bold)))
  "Face used for outermost parens.")

(setq rainbow-delimiters-outermost-only-face-count 1)
(set-face-attribute 'rainbow-delimiters-depth-1-face nil
                    :foreground 'unspecified
                    :inherit 'my-outermost-paren-face)

5.5. bold for the outermost parens and then gray all the way

If you want to have just the outermost parens display in bold black, and have all other parens display in gray color. The following code will do the job. You can also customize the two faces defined in the code if you want.

(defface my-outermost-paren-face
  '((t (:weight bold)))
  "Face used for outermost parens.")

(setq rainbow-delimiters-outermost-only-face-count 1)
(set-face-attribute 'rainbow-delimiters-depth-1-face nil
                    :foreground 'unspecified
                    :inherit 'my-outermost-paren-face)

(defface my-inner-paren-face
  ;; face definition I got from esk-paren-face of starter-kit-lisp
  '((((class color) (background dark))
     (:foreground "grey50"))
    (((class color) (background light))
     (:foreground "grey55")))
  "Face used to dim inner parentheses.")

(setq rainbow-delimiters-max-face-count 2)
(set-face-attribute 'rainbow-delimiters-depth-2-face nil
                    :foreground 'unspecified
                    :inherit 'my-inner-paren-face)

6. further reading

7. troubleshooting

7.1. for org users

If export to html doesn’t work with rainbow-delimiters, read the following article which is some part outdated, but the code in there should still work.

how to make rainbow-delimiters-mode work with org-mode export or htmlize

8. appendix

8.1. examples of forms where colored parens help seeing structure

These examples are simplistic for demonstration purposes. For each example, imagine a bigger example.

(when t
  ;; example where arguments of mapcar are
  ;; indented with just one space
  (blah blah)
   (lambda (x y)
     (blah blah)
     (blah blah))
   (list 1
  (blah blah)

  ;; example: let form
  (let ((a 1)
        (b (+ 1
        (c 3))
    (blah blah
    (blah (+ 1 1)

  ;; example: let form 2
  ;; with a line that is about to grow dense
  (let ((a 1) (b (+ 1 1)) (c 3)) ; <--
    (blah blah
    (blah (+ 1 1)

  ;; example: cond form
  ;; one space indent (between (1) and (2))
  (cond ((blih 1 x)
         (blah (+ 1 1)
         (blah blah ; <--(1)
        ((blih x ; <--(2)
               (+ blah blah))
         (blah blah))
        (t (blah)))

  ;; example: cond form 2
  ;; with one space indent (between (1), (2), (3))
   ((blih 1 x)
    (blah (+ 1 1)
    (blah blah ;<--(1)
   ((blih x ;<--(2)
          (+ blah blah))
    (blah blah)))
  (blah blah ;<--(3)

This entry was posted in Emacs and tagged . Bookmark the permalink.

1 Response to Small rainbow-delimiters tutorial

  1. Pingback: SICP を読むために Emacs で Scheme 環境を構築 | Futurismo

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s