Skip to content
Disperse Lisp forms (and other languages) into a spectrum of colors by depth
Emacs Lisp
Branch: master
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
images Add: prism-whitespace-mode Aug 26, 2019
.gitignore
LICENSE Docs: Add Aug 5, 2019
README.org Docs: Update usage Sep 3, 2019
notes.org Add: (prism-extrapolate) Sep 8, 2019
prism.el Add: (prism-extrapolate) Sep 8, 2019

README.org

prism.el

prism disperses lisp forms (and other languages) into a spectrum of color by depth. It’s similar to rainbow-blocks, but it respects existing non-color face properties, and allows flexible configuration of faces and colors. It also optionally colorizes strings and/or comments by code depth in a similar, customizable way.

Contents

Screenshots

Lisp and C-like languages

One of the benefits of prism is making it easy to see which list elements are in. For example, in this excerpt from org-get-entries-from-diary from org-agenda.el, the funcall’s first argument is an unusually indented if form, and the indentation nearly aligns the funcall’s second argument, date, at the column where the if’s else clause would usually be. But with depth-based colorization, it’s easy to see that date and 1 are arguments to funcall, not part of the if form.

It’s also easy to distinguish the diary-list-entries-hook variable’s value form from other variables, and the entries variable’s different color clearly shows that it has no value form.

images/one-armed-if.png

It is also useful for non-Lisp languages. For example, here’s an example of JSON in prism-mode:

images/json.png

Here’s an Emacs C function:

images/c.png

It might even help save you from deeply nested, callback-style JavaScript, turning this:

images/js-before.png

Into this (using theme doom-outrun-electric). Note how the bind is the same color as the function keyword and braces that it corresponds to:

images/js-after.png

Whitespace-sensitive languages

For whitespace-sensitive languages, prism-whitespace-mode determines depth by a combination of indentation and list nesting. For example, Python (showing theme doom-vibrant with these faces set in variable prism-colors: font-lock-type-face, font-lock-function-name-face, font-lock-constant-face, and font-lock-keyword-face):

images/python.png

This example shows Python with prism-comments enabled (showing theme doom-challenger-deep):

images/python-doom-challenger-deep.png

It even works in Haskell (showing theme doom-molokai):

images/haskell-doom-molokai.png

Customizable colors

It’s easy to adjust the colors with prism-set-colors. Here are some examples.

You can use just a few faces in combination with the desaturations and lightens to create a palette of colors:

images/2-faces.png images/4-faces.png

Or even a single color, going in one direction:

images/1-color.png

…or the other:

images/1-color-reversed.png

The default configuration looks decent in the default Emacs theme:

images/default-emacs.png

If you use Doom themes, you can use doom-color to get colors from the theme:

images/doom-spacegrey.png

But some of them look nice without any customization, like doom-gruvbox:

images/doom-gruvbox.png

If you use solarized-theme, you can use solarized-with-color-variables to get colors from the theme:

images/1.png

And you can adjust the palette extensively by changing the applied desaturation and lightening:

images/2.png images/5.png

You can shuffle the order of the colors until you find a pattern you like:

images/shuffled.png

Comparisons

prism is much like rainbow-blocks, but it differs in a few ways:

  • prism optionally colorizes comments and strings according to the depth of their surrounding code.
  • prism highlights parens with the color of the outer list’s symbols, which helps parens stand out from symbols and shows which depth surrounds a list.
  • prism adds to the face text property, which respects existing fontification, while rainbow-blocks sets the font-lock-face text property, which overrides existing fontification. This means that prism is compatible with packages like highlight-function-calls and highlight-quoted.
  • prism uses font-lock-add-keywords, while rainbow-blocks uses jit-lock-register. Which is better? Good question. Hopefully, the former…

Installation

The easiest way is to use quelpa-use-package like this:

(use-package prism
  :quelpa (prism :fetcher github :repo "alphapapa/prism.el"))

Usage

  1. Run the appropriate command for the current buffer:
    • For Lisp and C-like languages, use prism-mode.
    • For significant-whitespace languages like Python, or ones whose depth is not always indicated by parenthetical characters, like shell, use prism-whitespace-mode instead.
  2. Enjoy.

When a theme is loaded or disabled, colors are automatically updated.

To customize, see the prism customization group, e.g. by using M-x customize-group RET prism RET. For example, by default, comments and strings are colorized according to depth, similarly to code, but this can be disabled.

Advanced

More advanced customization of faces is done by calling prism-set-colors, which can override the default settings and perform additional color manipulations. The primary argument is COLORS, which should be a list of colors, each of which may be a name, a hex RGB string, or a face name (of which the foreground color is used). Note that the list of colors need not be as long as the number of faces that’s actually set (e.g. the default is 16 faces), because the colors are automatically repeated and adjusted as necessary.

If prism-set-colors is called with the SAVE argument, the results are saved to customization options so that prism-mode will use those colors by default.

Here’s an example that the author finds pleasant (seen in the first screenshot):

(prism-set-colors :num 16
  :desaturations (cl-loop for i from 0 below 16
                          collect (* i 2.5))
  :lightens (cl-loop for i from 0 below 16
                     collect (* i 2.5))
  :colors (list "dodgerblue" "medium sea green" "sandy brown")

  :comments-fn
  (lambda (color)
    (prism-blend color
                 (face-attribute 'font-lock-comment-face :foreground) 0.25))

  :strings-fn
  (lambda (color)
    (prism-blend color "white" 0.5)))

Changelog

0.1-pre

Early prototype stages.

Credits

Inspired by rainbow-blocks, rainbow-identifiers, and rainbow-delimiters.

Development

Bug reports, feature requests, suggestions — oh my!

In the event that a bug in the font-locking functions cause Emacs to enter an infinite loop, you can stop it without killing Emacs by following these steps:

  1. From a shell, run pkill -SIGUSR2 emacs. Usually once is enough, but not always.
  2. After Emacs displays a backtrace, switch to the buffer where prism-mode was enabled and call prism-mode again to disable it.
  3. Please report the backtrace to the issue tracker so it can be fixed. Include contents of the buffer when possible.

License

GPLv3

You can’t perform that action at this time.