]> code.delx.au - gnu-emacs-elpa/commitdiff
Merge commit '32b276e96118f9e34f4cf9a5a2ae6cae3e772144' from context-coloring
authorJackson Ray Hamilton <jackson@jacksonrayhamilton.com>
Sun, 21 Jun 2015 21:15:09 +0000 (14:15 -0700)
committerJackson Ray Hamilton <jackson@jacksonrayhamilton.com>
Sun, 21 Jun 2015 21:15:09 +0000 (14:15 -0700)
1  2 
packages/context-coloring/.travis.yml
packages/context-coloring/Cask
packages/context-coloring/Makefile
packages/context-coloring/README.md
packages/context-coloring/benchmark/context-coloring-benchmark.el
packages/context-coloring/context-coloring.el
packages/context-coloring/test/context-coloring-test.el

index 8a9d303d3abb40f7171ebee80fa1cefbd47569cf,0c3a48da661f4f56bc9fb2c25c3c20213cae25f9..0c3a48da661f4f56bc9fb2c25c3c20213cae25f9
@@@ -1,8 -1,5 +1,5 @@@
  language: emacs-lisp
  
- node_js:
-   - "0.10"
  env:
    - EVM_EMACS=emacs-24.3-bin
    - EVM_EMACS=emacs-24.4-bin
@@@ -17,7 -14,6 +14,6 @@@ before_install
    - evm install ${EVM_EMACS} --use
    - curl -fsSkL https://raw.github.com/cask/cask/master/go | python
    - cask
-   - npm install -g scopifier
  
  script:
    - emacs --version
index db61c1c97a99e98618cadc2c336928bd8fa7f0b4,b1535a927ed8393978058c681de12c319c146601..b1535a927ed8393978058c681de12c319c146601
--- 2/Cask
@@@ -5,5 -5,4 +5,4 @@@
  (depends-on "js2-mode")
  
  (development
-  (depends-on "ert-async")
   (depends-on "undercover"))
index dfa219dc75b5a0a94e7cc4682f7f3510b5f6b411,f729409b9c8d4741e254d0cc2f86193618d49435..f729409b9c8d4741e254d0cc2f86193618d49435
@@@ -1,8 -1,6 +1,6 @@@
  EMACS = emacs
  CASK = EMACS=${EMACS} cask
  DEPENDENCIES = .cask/
- SCOPIFIER_PORT = $$(lsof -t -i :6969)
- KILL_SCOPIFIER = if [ -n "${SCOPIFIER_PORT}" ]; then kill ${SCOPIFIER_PORT}; fi
  
  all: uncompile compile test
  
@@@ -28,22 -26,18 +26,18 @@@ ${DEPENDENCIES}
        ${CASK}
  
  test: ${DEPENDENCIES}
-       ${KILL_SCOPIFIER}
        ${CASK} exec ${EMACS} -Q -batch \
        -L . \
        -l ert \
-       -l ert-async \
        -l test/context-coloring-coverage.el \
        -f context-coloring-coverage-ci-init \
        -l test/context-coloring-test.el \
        -f ert-run-tests-batch-and-exit
  
  cover: ${DEPENDENCIES}
-       ${KILL_SCOPIFIER}
        ${CASK} exec ${EMACS} -Q -batch \
        -L . \
        -l ert \
-       -l ert-async \
        -l test/context-coloring-coverage.el \
        -f context-coloring-coverage-local-init \
        -l test/context-coloring-test.el \
index 6e8865f240a3e56ec6b169fd708b1e6e89b0a547,ff92dd962ec90d23d70400b169c07105433c3add..ff92dd962ec90d23d70400b169c07105433c3add
@@@ -13,182 -13,65 +13,65 @@@ By default, comments and strings are st
  
  ## Features
  
- - Light and dark (customizable) color schemes.
+ - Light and dark customizable color schemes.
  - JavaScript support:
    - Script, function and block scopes (and even `catch` block scopes).
-   - Very fast for files under 1000 lines.
  - Emacs Lisp support:
    - `defun`, `lambda`, `let`, `let*`, `cond`, `condition-case`, `defadvice`,
      `dolist`, `quote`, `backquote` and backquote splicing.
-   - Instantaneous lazy coloring, 8000 lines-per-second full coloring.
    - Works in `eval-expression` too.
  
  ## Installation
  
- Requires Emacs 24.3+.
+ Requires Emacs 24.3+.  JavaScript language support requires
+ [js2-mode](https://github.com/mooz/js2-mode).
  
- JavaScript language support requires either [js2-mode][], or
- [Node.js 0.10+][node] and the [scopifier][] executable.
- ### ELPA
- - `M-x package-install RET context-coloring RET`
- ### Git
- - Clone this repository.
- ```bash
- cd ~/.emacs.d/
- git clone https://github.com/jacksonrayhamilton/context-coloring.git
- ```
- - Byte-compile the package for improved speed.
- ```bash
- cd context-coloring/
- make compile
- ```
- - Add the following to your init file:
+ To install, run the command `M-x package-install RET context-coloring RET`, and
+ then add the following to your init file:
  
  ```lisp
- (add-to-list 'load-path "~/.emacs.d/context-coloring")
- (require 'context-coloring)
- ```
- ### Dependencies (js-mode)
- ```bash
- npm install -g scopifier
- ```
- ## Usage
- Add the following to your init file:
- ```lisp
- ;; js-mode:
- (add-hook 'js-mode-hook #'context-coloring-mode)
- ;; js2-mode:
+ ;; JavaScript:
  (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
  (add-hook 'js2-mode-hook #'context-coloring-mode)
  
- ;; emacs-lisp-mode:
+ ;; Emacs Lisp:
  (add-hook 'emacs-lisp-mode-hook #'context-coloring-mode)
  
  ;; eval-expression:
  (add-hook 'minibuffer-setup-hook #'context-coloring-mode)
  ```
  
- ## Customizing
- ### Options
- - `context-coloring-syntactic-comments` (default: `t`): If non-nil, also color
-   comments using `font-lock`.
- - `context-coloring-syntactic-strings` (default: `t`): If non-nil, also color
-   strings using `font-lock`.
- - `context-coloring-default-delay` (default: `0.25`; supported modes: `js-mode`,
-   `js3-mode`): Default (sometimes overridden) delay between a buffer update and
-   colorization.
- - `context-coloring-js-block-scopes` (default: `nil`; supported modes:
-   `js2-mode`): If non-nil, also color block scopes in the scope hierarchy in
-   JavaScript.
- ### Color Schemes
+ ## Color Schemes
  
- Color schemes for custom themes are automatically applied when those themes are
- active.  Built-in theme support is available for: `ample`, `anti-zenburn`,
- `grandshell`, `leuven`, `monokai`, `solarized`, `spacegray`, `tango` and
- `zenburn`.
+ You can define your own colors by customizing faces like
+ `context-coloring-level-N-face`, where N is a number starting from 0.
  
You can define your own theme colors too:
These are the colors used in the screenshot above:
  
  ```lisp
- (context-coloring-define-theme
+ (custom-theme-set-faces
   'zenburn
-  :colors '("#dcdccc"
-            "#93e0e3"
-            "#bfebbf"
-            "#f0dfaf"
-            "#dfaf8f"
-            "#cc9393"
-            "#dc8cc3"
-            "#94bff3"
-            "#9fc59f"
-            "#d0bf8f"
-            "#dca3a3"))
- ```
- See `C-h f context-coloring-define-theme` for more info on theme parameters.
- ## Extending
- To add support for a new language, write a "scopifier" for it, and define a new
- coloring dispatch strategy with `context-coloring-define-dispatch`.  Then the
- plugin should handle the rest.  (See `C-h f context-coloring-define-dispatch`
- for more info on dispatch strategies.)
- A "scopifier" is a CLI program that reads a buffer's contents from stdin and
- writes a JSON array of numbers to stdout.  Every three numbers in the array
- represent a range of color.  For instance, if I fed the following string of
- JavaScript code to a scopifier
- ```js
- var a = function () {};
+  '(context-coloring-level-0-face  ((t :foreground "#dcdccc")))
+  '(context-coloring-level-1-face  ((t :foreground "#93e0e3")))
+  '(context-coloring-level-2-face  ((t :foreground "#bfebbf")))
+  '(context-coloring-level-3-face  ((t :foreground "#f0dfaf")))
+  '(context-coloring-level-4-face  ((t :foreground "#dfaf8f")))
+  '(context-coloring-level-5-face  ((t :foreground "#cc9393")))
+  '(context-coloring-level-6-face  ((t :foreground "#dc8cc3")))
+  '(context-coloring-level-7-face  ((t :foreground "#94bff3")))
+  '(context-coloring-level-8-face  ((t :foreground "#9fc59f")))
+  '(context-coloring-level-9-face  ((t :foreground "#d0bf8f")))
+  '(context-coloring-level-10-face ((t :foreground "#dca3a3"))))
  ```
  
- then the scopifier would produce the following array
- ```js
- [1,24,0,9,23,1]
- ```
- where, for every three numbers, the first number is a 1-indexed start [point][],
- the second number is an exclusive end point, and the third number is a scope
- level.  The result of applying level 0 coloring to the range &#91;1, 24) and
- then applying level 1 coloring to the range &#91;9, 23) would result in the
- following coloring:
- <p align="center">
-   <img alt="Screenshot of ranges &#91;1, 24) and &#91;9, 23)." src="scopifier.png" title="Screenshot">
- </p>
+ [See here](https://gist.github.com/jacksonrayhamilton/6b89ca3b85182c490816) for
+ some color schemes for popular custom themes.
  
- If there is an abstract syntax tree generator for your language, you can walk
- the syntax tree, find variables and scopes, and build their positions and levels
- into an array like the one above.
+ ## Options
  
- For example, a Ruby scopifier might be defined and implemented like this:
- ```lisp
- (context-coloring-define-dispatch
-  'ruby
-  :modes '(ruby-mode)
-  :executable "ruby"
-  :command "/home/username/scopifier")
- ```
- ```ruby
- #!/usr/bin/env ruby
- def scopifier(code)
-     # Parse code.
-     # Return an array.
- end
- print scopifier ARGF.read
- ```
- When a `--version` argument is passed, a scopifier should print its version
- number and exit.  This allows context-coloring to determine if an update is
- required.
- Alternatively, you could implement a "colorizer" in Emacs Lisp.  A colorizer
- also handles the job of calling `context-coloring-colorize-region` to apply
- colors to a buffer.  A colorizer may have better performance than a scopifier
- when parsing and coloring can be performed in the same pass.
- [js2-mode]: https://github.com/mooz/js2-mode
- [node]: http://nodejs.org/download/
- [scopifier]: https://github.com/jacksonrayhamilton/scopifier
- [point]: http://www.gnu.org/software/emacs/manual/html_node/elisp/Point.html
+ - `context-coloring-syntactic-comments` (default: `t`): If non-nil, also color
+   comments using `font-lock`.
+ - `context-coloring-syntactic-strings` (default: `t`): If non-nil, also color
+   strings using `font-lock`.
+ - `context-coloring-javascript-block-scopes` (default: `nil`): If non-nil, also
+   color block scopes in the scope hierarchy in JavaScript.
index 1f5885c024ecabd9cde62b96e116d0b9dd98a2b7,c627249b31ff22ecc3db01b6b9965320ce608b03..c627249b31ff22ecc3db01b6b9965320ce608b03
    "Resolve PATH from this file's directory."
    (expand-file-name path context-coloring-benchmark-path))
  
- (defun context-coloring-benchmark-next-tick (callback)
-   "Run CALLBACK in the next turn of the event loop."
-   (run-with-timer nil nil callback))
- (defun context-coloring-benchmark-series (sequence callback)
-   "Call each function in SEQUENCE, then call CALLBACK.  Each
- function is passed a single callback parameter for it to call
- when it is done."
-   (cond
-    ((null sequence)
-     (funcall callback))
-    (t
-     (funcall
-      (car sequence)
-      (lambda ()
-        (context-coloring-benchmark-next-tick
-         (lambda ()
-           (context-coloring-benchmark-series
-            (cdr sequence)
-            callback))))))))
- (defun context-coloring-benchmark-mapc (sequence iteratee callback)
-   "For each element in SEQUENCE, call ITERATEE, finally call
- CALLBACK.  ITERATEE is passed the current element and a callback
- for it to call when it is done."
-   (cond
-    ((null sequence)
-     (funcall callback))
-    (t
-     (funcall
-      iteratee
-      (car sequence)
-      (lambda ()
-        (context-coloring-benchmark-next-tick
-         (lambda ()
-           (context-coloring-benchmark-mapc
-            (cdr sequence)
-            iteratee
-            callback))))))))
  (defun context-coloring-benchmark-log-results (result-file fixture statistics)
-   "Log benchmarking results to RESULT-FILE for fixture FIXTURE
- with STATISTICS."
+   "Log results to RESULT-FILE for FIXTURE with STATISTICS."
    (let ((results (prog1
                       (progn
                         (elp-results)
         (buffer-substring-no-properties (point-min) (point-max)))
       nil result-file)))
  
- (defun context-coloring-benchmark (title setup teardown fixtures callback)
-   "Execute a benchmark titled TITLE with SETUP and TEARDOWN
- callbacks.  Measure the performance of all FIXTURES, calling
- CALLBACK when all are done."
-   (funcall setup)
+ (defun context-coloring-benchmark (title fixtures)
+   "Execute a benchmark titled TITLE against FIXTURES."
    (let ((result-file (context-coloring-benchmark-resolve-path
                        (format "./logs/results-%s-%s.log"
                                title (format-time-string "%s")))))
-     (context-coloring-benchmark-mapc
-      fixtures
-      (lambda (path callback)
+     (mapc
+      (lambda (path)
         (let ((fixture (context-coloring-benchmark-resolve-path path))
               colorization-start-time
               (colorization-times '())
            advice
            (let ((count 0))
              (lambda (original-function)
-               (funcall
-                original-function
-                (lambda ()
-                  (setq count (+ count 1))
-                  ;; First 5 runs are for gathering real coloring times,
-                  ;; unaffected by elp instrumentation.
-                  (when (<= count 5)
-                    (push (- (float-time) colorization-start-time) colorization-times))
-                  (cond
-                   ((= count 10)
-                    (advice-remove #'context-coloring-colorize advice)
-                    (context-coloring-benchmark-log-results
-                     result-file
-                     fixture
-                     (list
-                      :file-size (nth 7 (file-attributes fixture))
-                      :lines (count-lines (point-min) (point-max))
-                      :words (count-words (point-min) (point-max))
-                      :colorization-times colorization-times
-                      :average-colorization-time (/ (apply #'+ colorization-times) 5)))
-                    (elp-restore-all)
-                    (kill-buffer)
-                    (funcall callback))
-                   ;; The last 5 runs are for gathering function call and
-                   ;; duration statistics.
-                   ((= count 5)
-                    (elp-instrument-package "context-coloring-")
-                    (context-coloring-colorize))
-                   (t
-                    (setq colorization-start-time (float-time))
-                    (context-coloring-colorize))))))))
+               (funcall original-function)
+               (setq count (+ count 1))
+               ;; First 5 runs are for gathering real coloring times,
+               ;; unaffected by elp instrumentation.
+               (when (<= count 5)
+                 (push (- (float-time) colorization-start-time) colorization-times))
+               (cond
+                ((= count 10)
+                 (advice-remove #'context-coloring-colorize advice)
+                 (context-coloring-benchmark-log-results
+                  result-file
+                  fixture
+                  (list
+                   :file-size (nth 7 (file-attributes fixture))
+                   :lines (count-lines (point-min) (point-max))
+                   :words (count-words (point-min) (point-max))
+                   :colorization-times colorization-times
+                   :average-colorization-time (/ (apply #'+ colorization-times) 5)))
+                 (elp-restore-all)
+                 (kill-buffer))
+                ;; The last 5 runs are for gathering function call and
+                ;; duration statistics.
+                ((= count 5)
+                 (elp-instrument-package "context-coloring-")
+                 (context-coloring-colorize))
+                (t
+                 (setq colorization-start-time (float-time))
+                 (context-coloring-colorize))))))
           (advice-add #'context-coloring-colorize :around advice)
           (setq colorization-start-time (float-time))
           (find-file fixture)))
-      (lambda ()
-        (funcall teardown)
-        (funcall callback)))))
+      fixtures)))
  
- (defconst context-coloring-benchmark-js-fixtures
+ (defconst context-coloring-benchmark-javascript-fixtures
    '("./fixtures/jquery-2.1.1.js"
      "./fixtures/lodash-2.4.1.js"
      "./fixtures/async-0.9.0.js"
      "./fixtures/mkdirp-0.5.0.js")
    "Arbitrary JavaScript files for performance scrutiny.")
  
- (defun context-coloring-benchmark-js-mode-run (callback)
-   "Benchmark `js-mode', then call CALLBACK."
-   (context-coloring-benchmark
-    "js-mode"
-    (lambda ()
-      "Preparation logic for `js-mode'."
-      (add-hook 'js-mode-hook #'context-coloring-mode))
-    (lambda ()
-      "Cleanup logic for `js-mode'."
-      (remove-hook 'js-mode-hook #'context-coloring-mode))
-    context-coloring-benchmark-js-fixtures
-    callback))
- (defun context-coloring-benchmark-js2-mode-run (callback)
-   "Benchmark `js2-mode', then call CALLBACK."
-   (context-coloring-benchmark
-    "js2-mode"
-    (lambda ()
-      "Preparation logic for `js2-mode'."
-      (setq js2-mode-show-parse-errors nil)
-      (setq js2-mode-show-strict-warnings nil)
-      (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
-      (add-hook 'js2-mode-hook #'context-coloring-mode))
-    (lambda ()
-      "Cleanup logic for `js2-mode'."
-      (remove-hook 'js2-mode-hook #'context-coloring-mode)
-      (setq auto-mode-alist (delete '("\\.js\\'" . js2-mode)
-                                    auto-mode-alist))
-      (setq js2-mode-show-strict-warnings t)
-      (setq js2-mode-show-parse-errors t))
-    context-coloring-benchmark-js-fixtures
-    callback))
+ (defun context-coloring-benchmark-js2-mode-run ()
+   "Benchmark `js2-mode'."
+   (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
+   (add-hook 'js2-mode-hook #'context-coloring-mode)
+   (let ((js2-mode-show-parse-errors nil)
+         (js2-mode-show-strict-warnings nil))
+     (context-coloring-benchmark
+      "js2-mode"
+      context-coloring-benchmark-javascript-fixtures))
+   (setq auto-mode-alist (delete '("\\.js\\'" . js2-mode)
+                                 auto-mode-alist))
+   (remove-hook 'js2-mode-hook #'context-coloring-mode))
  
  (defconst context-coloring-benchmark-emacs-lisp-fixtures
    '("./fixtures/lisp.el"
      "./fixtures/simple.el")
    "Arbitrary Emacs Lisp files for performance scrutiny.")
  
- (defun context-coloring-benchmark-emacs-lisp-mode-run (callback)
+ (defun context-coloring-benchmark-emacs-lisp-mode-run ()
    "Benchmark `emacs-lisp-mode', then call CALLBACK."
+   (add-hook 'emacs-lisp-mode-hook #'context-coloring-mode)
    (context-coloring-benchmark
     "emacs-lisp-mode"
-    (lambda ()
-      "Preparation logic for `emacs-lisp-mode'."
-      (add-hook 'emacs-lisp-mode-hook #'context-coloring-mode))
-    (lambda ()
-      "Cleanup logic for `emacs-lisp-mode'."
-      (remove-hook 'emacs-lisp-mode-hook #'context-coloring-mode))
-    context-coloring-benchmark-emacs-lisp-fixtures
-    callback))
+    context-coloring-benchmark-emacs-lisp-fixtures)
+   (remove-hook 'emacs-lisp-mode-hook #'context-coloring-mode))
  
  (defun context-coloring-benchmark-run ()
    "Benchmark all modes, then exit."
-   (context-coloring-benchmark-series
-    (list
-     #'context-coloring-benchmark-js-mode-run
-     #'context-coloring-benchmark-js2-mode-run
-     #'context-coloring-benchmark-emacs-lisp-mode-run)
-    (lambda ()
-      (kill-emacs))))
+   (context-coloring-benchmark-js2-mode-run)
+   (context-coloring-benchmark-emacs-lisp-mode-run)
+   (kill-emacs))
  
  (provide 'context-coloring-benchmark)
  
index 327dbc3e581a97eb9def689c6504cb7c99d5e57a,2b1d7afe4b1af793d68da89330db5e33d5dc48ea..2b1d7afe4b1af793d68da89330db5e33d5dc48ea
@@@ -3,7 -3,7 +3,7 @@@
  ;; Copyright (C) 2014-2015  Free Software Foundation, Inc.
  
  ;; Author: Jackson Ray Hamilton <jackson@jacksonrayhamilton.com>
- ;; Version: 6.5.0
+ ;; Version: 7.0.0
  ;; Keywords: convenience faces tools
  ;; Package-Requires: ((emacs "24.3") (js2-mode "20150126"))
  ;; URL: https://github.com/jacksonrayhamilton/context-coloring
    "Join a list of STRINGS with the string DELIMITER."
    (mapconcat #'identity strings delimiter))
  
- (defsubst context-coloring-trim-right (string)
-   "Remove leading whitespace from STRING."
-   (if (string-match "[ \t\n\r]+\\'" string)
-       (replace-match "" t t string)
-     string))
- (defsubst context-coloring-trim-left (string)
-   "Remove trailing whitespace from STRING."
-   (if (string-match "\\`[ \t\n\r]+" string)
-       (replace-match "" t t string)
-     string))
- (defsubst context-coloring-trim (string)
-   "Remove leading and trailing whitespace from STRING."
-   (context-coloring-trim-left (context-coloring-trim-right string)))
  
  ;;; Faces
  
- (defun context-coloring-defface (level tty light dark)
-   "Define a face for LEVEL with colors for TTY, LIGHT and DARK
- backgrounds."
+ (defun context-coloring-defface (level light dark tty)
+   "Define a face for LEVEL with LIGHT, DARK and TTY colors."
    (let ((face (intern (format "context-coloring-level-%s-face" level)))
          (doc (format "Context coloring face, level %s." level)))
      (custom-declare-face
       doc
       :group 'context-coloring)))
  
- (defun context-coloring-defface-neutral (level)
-   "Define a face for LEVEL with the default neutral colors."
-   (context-coloring-defface level nil "#3f3f3f" "#cdcdcd"))
- (context-coloring-defface 0 nil       "#000000" "#ffffff")
- (context-coloring-defface 1 "yellow"  "#008b8b" "#00ffff")
- (context-coloring-defface 2 "green"   "#0000ff" "#87cefa")
- (context-coloring-defface 3 "cyan"    "#483d8b" "#b0c4de")
- (context-coloring-defface 4 "blue"    "#a020f0" "#eedd82")
- (context-coloring-defface 5 "magenta" "#a0522d" "#98fb98")
- (context-coloring-defface 6 "red"     "#228b22" "#7fffd4")
- (context-coloring-defface-neutral 7)
- (defvar context-coloring-maximum-face nil
-   "Index of the highest face available for coloring.")
- (defvar context-coloring-original-maximum-face nil
-   "Fallback value for `context-coloring-maximum-face' when all
- themes have been disabled.")
- (setq context-coloring-maximum-face 7)
- (setq context-coloring-original-maximum-face
-       context-coloring-maximum-face)
- ;; Theme authors can have up to 26 levels: 1 (0th) for globals, 24 (1st-24th)
- ;; for nested levels, and 1 (25th) for infinity.
- (dotimes (number 18)
-   (context-coloring-defface-neutral (+ number context-coloring-maximum-face 1)))
- ;;; Face functions
+ ;; Provide some default colors based off Emacs's defaults.
+ (context-coloring-defface 0 "#000000" "#ffffff" nil)
+ (context-coloring-defface 1 "#008b8b" "#00ffff" "yellow")
+ (context-coloring-defface 2 "#0000ff" "#87cefa" "green")
+ (context-coloring-defface 3 "#483d8b" "#b0c4de" "cyan")
+ (context-coloring-defface 4 "#a020f0" "#eedd82" "blue")
+ (context-coloring-defface 5 "#a0522d" "#98fb98" "magenta")
+ (context-coloring-defface 6 "#228b22" "#7fffd4" "red")
+ (context-coloring-defface 7 "#3f3f3f" "#cdcdcd" nil)
+ (defconst context-coloring-default-maximum-face 7
+   "Maximum face when there are no custom faces.")
+ ;; Create placeholder faces for users and theme authors.
+ (dotimes (level 18)
+   (let* ((level (+ level 8))
+          (face (intern (format "context-coloring-level-%s-face" level)))
+          (doc (format "Context coloring face, level %s." level)))
+     (custom-declare-face face nil doc :group 'context-coloring)))
+ (defvar-local context-coloring-maximum-face nil
+   "Dynamic index of the highest face available for coloring.")
  
  (defsubst context-coloring-level-face (level)
-   "Return the symbol for a face with LEVEL."
+   "Return symbol for face with LEVEL."
    ;; `concat' is faster than `format' here.
    (intern-soft
     (concat "context-coloring-level-" (number-to-string level) "-face")))
  
  (defsubst context-coloring-bounded-level-face (level)
-   "Return the symbol for a face with LEVEL, bounded by
- `context-coloring-maximum-face'."
+   "Return symbol for face with LEVEL, bounded by the maximum."
    (context-coloring-level-face (min level context-coloring-maximum-face)))
  
+ (defconst context-coloring-level-face-regexp
+   "context-coloring-level-\\([[:digit:]]+\\)-face"
+   "Extract a level from a face.")
+ (defun context-coloring-theme-highest-level (theme)
+   "Return the highest coloring level for THEME, or -1."
+   (let* ((settings (get theme 'theme-settings))
+          (tail settings)
+          face-string
+          number
+          (found -1))
+     (while tail
+       (and (eq (nth 0 (car tail)) 'theme-face)
+            (setq face-string (symbol-name (nth 1 (car tail))))
+            (string-match
+             context-coloring-level-face-regexp
+             face-string)
+            (setq number (string-to-number
+                          (substring face-string
+                                     (match-beginning 1)
+                                     (match-end 1))))
+            (> number found)
+            (setq found number))
+       (setq tail (cdr tail)))
+     found))
+ (defun context-coloring-update-maximum-face ()
+   "Save the highest possible face for the current theme."
+   (let ((themes (append custom-enabled-themes '(user)))
+         (continue t)
+         theme
+         highest-level)
+     (while continue
+       (setq theme (car themes))
+       (setq themes (cdr themes))
+       (setq highest-level (context-coloring-theme-highest-level theme))
+       (setq continue (and themes (= highest-level -1))))
+     (setq context-coloring-maximum-face
+           (cond
+            ((= highest-level -1)
+             context-coloring-default-maximum-face)
+            (t
+             highest-level)))))
  
  ;;; Change detection
  
@@@ -142,7 -158,6 +158,6 @@@ being used."
  
  START, END and LENGTH are recorded for later use."
    ;; Tokenization is obsolete if there was a change.
-   (context-coloring-cancel-scopification)
    (setq context-coloring-changed-start start)
    (setq context-coloring-changed-end end)
    (setq context-coloring-changed-length length)
    "The currently-running idle timer for unconditional coloring.")
  
  (defcustom context-coloring-default-delay 0.25
-   "Default (sometimes overridden) delay between a buffer update
- and colorization.
+   "Default delay between a buffer update and colorization.
  
  Increase this if your machine is high-performing.  Decrease it if
- it ain't.
- Supported modes: `js-mode', `js3-mode'"
+ it ain't."
    :group 'context-coloring)
  
  (make-obsolete-variable
  
  (defun context-coloring-teardown-idle-change-detection ()
    "Teardown idle change detection."
-   (context-coloring-cancel-scopification)
    (dolist (timer (list context-coloring-colorize-idle-timer
                         context-coloring-maybe-colorize-idle-timer))
      (context-coloring-cancel-timer timer))
  ;;; Colorization utilities
  
  (defsubst context-coloring-colorize-region (start end level)
-   "Color characters from the 1-indexed START point (inclusive) to
- the END point (exclusive) with the face corresponding to LEVEL."
+   "Color from START (inclusive) to END (exclusive) with LEVEL."
    (add-text-properties
     start
     end
    :group 'context-coloring)
  
  (defun context-coloring-font-lock-syntactic-comment-function (state)
-   "Tell `font-lock' to color a comment but not a string according
- to STATE."
+   "Color a comment according to STATE."
    (if (nth 3 state) nil font-lock-comment-face))
  
  (defun context-coloring-font-lock-syntactic-string-function (state)
-   "Tell `font-lock' to color a string but not a comment according
- to STATE."
+   "Color a string according to STATE."
    (if (nth 3 state) font-lock-string-face nil))
  
  (defsubst context-coloring-colorize-comments-and-strings (&optional min max)
-   "Color the current buffer's comments or strings if
- `context-coloring-syntactic-comments' or
- `context-coloring-syntactic-strings' are non-nil.  MIN defaults
- to the beginning of the buffer and MAX defaults to the end."
+   "Maybe color comments and strings in buffer from MIN to MAX.
+ MIN defaults to beginning of buffer.  MAX defaults to end."
    (when (or context-coloring-syntactic-comments
              context-coloring-syntactic-strings)
      (let ((min (or min (point-min)))
    "Associate `js2-scope' structures and with their scope
    levels.")
  
- (defcustom context-coloring-js-block-scopes nil
+ (defcustom context-coloring-javascript-block-scopes nil
    "If non-nil, also color block scopes in the scope hierarchy in JavaScript.
  
  The block-scoped `let' and `const' are introduced in ES6.  Enable
- this for ES6 code; disable it elsewhere.
- Supported modes: `js2-mode'"
+ this for ES6 code; disable it elsewhere."
    :group 'context-coloring)
  
+ (make-obsolete-variable
+  'context-coloring-js-block-scopes
+  'context-coloring-javascript-block-scopes
+  "7.0.0")
  (defsubst context-coloring-js2-scope-level (scope)
    "Return the level of SCOPE."
    (cond ((gethash scope context-coloring-js2-scope-level-hash-table))
                         (js2-node-parent current-scope)
                         (setq enclosing-scope
                               (js2-node-get-enclosing-scope current-scope)))
-              (when (or context-coloring-js-block-scopes
+              (when (or context-coloring-javascript-block-scopes
                         (let ((type (js2-scope-type current-scope)))
                           (or (= type js2-SCRIPT)
                               (= type js2-FUNCTION)
             (puthash scope level context-coloring-js2-scope-level-hash-table)))))
  
  (defsubst context-coloring-js2-local-name-node-p (node)
-   "Determine if NODE is a `js2-name-node' representing a local
- variable."
+   "Determine if NODE represents a local variable."
    (and (js2-name-node-p node)
         (let ((parent (js2-node-parent node)))
           (not (or (and (js2-object-prop-node-p parent)
       level)))
  
  (defun context-coloring-js2-colorize ()
-   "Color the current buffer using the abstract syntax tree
- generated by `js2-mode'."
+   "Color the buffer using the `js2-mode' abstract syntax tree."
    ;; Reset the hash table; the old one could be obsolete.
    (setq context-coloring-js2-scope-level-hash-table (make-hash-table :test #'eq))
    (setq context-coloring-point-max (point-max))
    (while (forward-comment 1)))
  
  (defsubst context-coloring-elisp-forward-sws ()
-   "Move forward through whitespace and comments, colorizing
- comments along the way."
+   "Move through whitespace and comments, coloring comments."
    (let ((start (point)))
      (context-coloring-forward-sws)
      (context-coloring-colorize-comments-and-strings start (point))))
  
  (defsubst context-coloring-elisp-forward-sexp ()
-   "Like `forward-sexp', but colorize comments and strings along
- the way."
+   "Like `forward-sexp', coloring skipped comments and strings."
    (let ((start (point)))
      (forward-sexp)
      (context-coloring-elisp-colorize-comments-and-strings-in-region
                                 (context-coloring-exact-or-regexp
                                  '("t" "nil" "." "?")))
                           "\\|")
-   "Match words that might be considered symbols but can't be
- bound as variables.")
+   "Match symbols that can't be bound as variables.")
  
  (defconst context-coloring-WORD-CODE 2)
  (defconst context-coloring-SYMBOL-CODE 3)
@@@ -459,8 -463,7 +463,7 @@@ second."
    "Current number of sexps leading up to the next pause.")
  
  (defsubst context-coloring-elisp-increment-sexp-count ()
-   "Maybe check if the current parse should be interrupted as a
- result of pending user input."
+   "Maybe check if the user interrupted the current parse."
    (setq context-coloring-elisp-sexp-count
          (1+ context-coloring-elisp-sexp-count))
    (when (and (zerop (% context-coloring-elisp-sexp-count
    (member variable (plist-get scope :variables)))
  
  (defsubst context-coloring-elisp-get-variable-level (variable)
-   "Search up the scope chain for the first instance of VARIABLE
- and return its level, or 0 (global) if it isn't found."
+   "Return the level of VARIABLE, or 0 if it isn't found."
    (let* ((scope-stack context-coloring-elisp-scope-stack)
           scope
           level)
     variable))
  
  (defsubst context-coloring-elisp-parse-bindable (callback)
-   "Parse the symbol at point, and if the symbol can be bound,
- invoke CALLBACK with it."
+   "Parse the symbol at point.
If the symbol can be bound, invoke CALLBACK with it."
    (let* ((arg-string (buffer-substring-no-properties
                        (point)
                        (progn (context-coloring-elisp-forward-sexp)
        (funcall callback arg-string))))
  
  (defun context-coloring-elisp-parse-let-varlist (type)
-   "Parse the list of variable initializers at point.  If TYPE is
- `let', all the variables are bound after all their initializers
- are parsed; if TYPE is `let*', each variable is bound immediately
- after its own initializer is parsed."
+   "Parse the list of variable initializers at point.
+ If TYPE is `let', all the variables are bound after all their
+ initializers are parsed; if TYPE is `let*', each variable is
bound immediately after its own initializer is parsed."
    (let ((varlist '())
          syntax-code)
      ;; Enter.
    (context-coloring-elisp-forward-sws))
  
  (defun context-coloring-elisp-colorize-scope (callback)
-   "Color the whole scope at point with its one color.  Handle a
- header in CALLBACK."
+   "Color the whole scope at point with its one color.
Handle a header in CALLBACK."
    (let ((start (point))
          (end (progn (forward-sexp)
                      (point))))
      (funcall callback)))
  
  (defun context-coloring-elisp-colorize-defun-like (callback)
-   "Color the defun-like function at point, parsing the header
- with CALLBACK."
+   "Color the defun-like function at point.
Parse the header with CALLBACK."
    (context-coloring-elisp-colorize-scope
     (lambda ()
       (when (context-coloring-elisp-identifier-p (context-coloring-get-syntax-code))
           (context-coloring-elisp-forward-sws))))))
  
  (defun context-coloring-elisp-colorize-lambda-like (callback)
-   "Color the lambda-like function at point, parsing the header
- with CALLBACK."
+   "Color the lambda-like function at point.
Parsing the header with CALLBACK."
    (context-coloring-elisp-colorize-scope
     (lambda ()
       (context-coloring-elisp-parse-header callback))))
    (forward-char))
  
  (defun context-coloring-elisp-colorize-expression-prefix ()
-   "Color the expression prefix and the following expression at
point.  It could be a quoted or backquoted expression."
+   "Color the expression prefix and expression at point.
+ It could be a quoted or backquoted expression."
    (context-coloring-elisp-increment-sexp-count)
    (cond
     ((/= (char-after) context-coloring-BACKTICK-CHAR)
          (scan-error (progn))))))
  
  (defun context-coloring-elisp-colorize ()
-   "Color the current buffer, parsing elisp to determine its
- scopes and variables."
+   "Color the current Emacs Lisp buffer."
    (interactive)
    (context-coloring-elisp-colorize-guard
     (lambda ()
        (t
         (context-coloring-elisp-colorize-region-initially (point-min) (point-max)))))))
  
+ ;;; eval-expression colorization
+ (defun context-coloring-eval-expression-match ()
+   "Determine expression start in `eval-expression'."
+   (string-match "\\`Eval: " (buffer-string)))
  (defun context-coloring-eval-expression-colorize ()
    "Color the `eval-expression' minibuffer prompt as elisp."
    (interactive)
     (lambda ()
       (context-coloring-elisp-colorize-region-initially
        (progn
-         (string-match "\\`Eval: " (buffer-string))
+         (context-coloring-eval-expression-match)
          (1+ (match-end 0)))
        (point-max)))))
  
  
- ;;; Shell command scopification / colorization
- (defun context-coloring-apply-tokens (tokens)
-   "Process a string of TOKENS to apply context-based coloring to
- the current buffer.  Tokens are 3 integers: start, end, level.  A
- new token occurrs after every 3rd element, and the elements are
- separated by commas."
-   (let* ((tokens (mapcar #'string-to-number (split-string tokens ","))))
-     (while tokens
-       (context-coloring-colorize-region
-        (pop tokens)
-        (pop tokens)
-        (pop tokens))))
-   (context-coloring-colorize-comments-and-strings))
- (defun context-coloring-parse-array (array)
-   "Parse ARRAY as a flat JSON array of numbers and use the tokens
- to colorize the buffer."
-   (let* ((braceless (substring-no-properties (context-coloring-trim array) 1 -1)))
-     (when (> (length braceless) 0)
-       (with-silent-modifications
-         (context-coloring-apply-tokens braceless)))))
- (defvar-local context-coloring-scopifier-cancel-function nil
-   "Kills the current scopification process.")
- (defvar-local context-coloring-scopifier-process nil
-   "The single scopifier process that can be running.")
- (defun context-coloring-cancel-scopification ()
-   "Stop the currently-running scopifier from scopifying."
-   (when context-coloring-scopifier-cancel-function
-     (funcall context-coloring-scopifier-cancel-function)
-     (setq context-coloring-scopifier-cancel-function nil))
-   (when (not (null context-coloring-scopifier-process))
-     (delete-process context-coloring-scopifier-process)
-     (setq context-coloring-scopifier-process nil)))
- (defun context-coloring-shell-command (command callback)
-   "Invoke COMMAND, read its response asynchronously and invoke
- CALLBACK with its output.  Return the command process."
-   (let ((process (start-process-shell-command "context-coloring-process" nil command))
-         (output ""))
-     ;; The process may produce output in multiple chunks.  This filter
-     ;; accumulates the chunks into a message.
-     (set-process-filter
-      process
-      (lambda (_process chunk)
-        (setq output (concat output chunk))))
-     ;; When the process's message is complete, this sentinel parses it as JSON
-     ;; and applies the tokens to the buffer.
-     (set-process-sentinel
-      process
-      (lambda (_process event)
-        (when (equal "finished\n" event)
-          (funcall callback output))))
-     process))
- (defun context-coloring-scopify-shell-command (command callback)
-   "Invoke a scopifier via COMMAND, read its response
- asynchronously and invoke CALLBACK with its output."
-   ;; Prior running tokenization is implicitly obsolete if this function is
-   ;; called.
-   (context-coloring-cancel-scopification)
-   ;; Start the process.
-   (setq context-coloring-scopifier-process
-         (context-coloring-shell-command command callback)))
- (defun context-coloring-send-buffer-to-scopifier ()
-   "Give the scopifier process its input so it can begin
- scopifying."
-   (process-send-region
-    context-coloring-scopifier-process
-    (point-min) (point-max))
-   (process-send-eof
-    context-coloring-scopifier-process))
- (defun context-coloring-start-scopifier-server (command host port callback)
-   "Connect to or start a scopifier server with COMMAND, HOST and PORT.
- Invoke CALLBACK with a network stream when the server is ready
- for connections."
-   (let* ((connect
-           (lambda ()
-             (let ((stream (open-network-stream "context-coloring-stream" nil host port)))
-               (funcall callback stream)))))
-     ;; Try to connect in case a server is running, otherwise start one.
-     (condition-case nil
-         (progn
-           (funcall connect))
-       (error
-        (let ((server (start-process-shell-command
-                       "context-coloring-scopifier-server" nil
-                       (context-coloring-join
-                        (list command
-                              "--server"
-                              "--host" host
-                              "--port" (number-to-string port))
-                        " ")))
-              (output ""))
-          ;; Connect as soon as the "listening" message is printed.
-          (set-process-filter
-           server
-           (lambda (_process chunk)
-             (setq output (concat output chunk))
-             (when (string-match-p (format "^Scopifier listening at %s:%s$" host port) output)
-               (funcall connect)))))))))
- (defun context-coloring-send-buffer-to-scopifier-server (command host port callback)
-   "Send the current buffer to the scopifier server running with
- COMMAND, HOST and PORT.  Invoke CALLBACK with the server's
- response (a stringified JSON array)."
-   (context-coloring-start-scopifier-server
-    command host port
-    (lambda (process)
-      (let* ((body (buffer-substring-no-properties (point-min) (point-max)))
-             (header (concat "POST / HTTP/1.0\r\n"
-                             "Host: localhost\r\n"
-                             "Content-Type: application/x-www-form-urlencoded"
-                             "; charset=UTF8\r\n"
-                             (format "Content-Length: %d\r\n" (length body))
-                             "\r\n"))
-             (output "")
-             (active t))
-        (set-process-filter
-         process
-         (lambda (_process chunk)
-           (setq output (concat output chunk))))
-        (set-process-sentinel
-         process
-         (lambda (_process event)
-           (when (and (equal "connection broken by remote peer\n" event)
-                      active)
-             ;; Strip the response headers.
-             (string-match "\r\n\r\n" output)
-             (setq output (substring-no-properties output (match-end 0)))
-             (funcall callback output))))
-        (process-send-string process (concat header body "\r\n"))
-        (setq context-coloring-scopifier-cancel-function
-              (lambda ()
-                "Cancel this scopification."
-                (setq active nil)))))))
- (defun context-coloring-scopify-and-colorize-server (command host port &optional callback)
-   "Color the current buffer via the server started with COMMAND,
- HOST and PORT.  Invoke CALLBACK when complete."
-   (let ((buffer (current-buffer)))
-     (context-coloring-send-buffer-to-scopifier-server
-      command host port
-      (lambda (output)
-        (with-current-buffer buffer
-          (context-coloring-parse-array output))
-        (when callback (funcall callback))))))
- (defun context-coloring-scopify-and-colorize (command &optional callback)
-   "Color the current buffer via COMMAND.  Invoke CALLBACK when
- complete."
-   (let ((buffer (current-buffer)))
-     (context-coloring-scopify-shell-command
-      command
-      (lambda (output)
-        (with-current-buffer buffer
-          (context-coloring-parse-array output))
-        (setq context-coloring-scopifier-process nil)
-        (when callback (funcall callback)))))
-   (context-coloring-send-buffer-to-scopifier))
  ;;; Dispatch
  
  (defvar context-coloring-dispatch-hash-table (make-hash-table :test #'eq)
-   "Map dispatch strategy names to their corresponding property
- lists, which contain details about the strategies.")
+   "Map dispatch strategy names to their property lists.")
  
  (defvar context-coloring-mode-hash-table (make-hash-table :test #'eq)
    "Map major mode names to dispatch property lists.")
    "Define a new dispatch named SYMBOL with PROPERTIES.
  
  A \"dispatch\" is a property list describing a strategy for
- coloring a buffer.  There are three possible strategies: Parse
- and color in a single function (`:colorizer'), parse with a shell
- command that returns scope data (`:command'), or parse with a
- server that returns scope data (`:command', `:host' and `:port').
- In the latter two cases, the scope data will be used to
- automatically color the buffer.
+ coloring a buffer.
  
- PROPERTIES must include one of `:modes' or `:predicate', and one
of `:colorizer' or `:command'.
+ PROPERTIES must include one of `:modes' or `:predicate', and a
`:colorizer'.
  
  `:modes' - List of major modes this dispatch is valid for.
  
@@@ -1267,25 -1102,9 +1102,9 @@@ for any given state
  
  `:colorizer' - Function that parses and colors the buffer.
  
- `:executable' - Optional name of an executable required by
- `:command'.
- `:command' - Shell command to execute with the current buffer
- sent via stdin, and with a flat JSON array of start, end and
- level data returned via stdout.
- `:host' - Hostname of the scopifier server, e.g. \"localhost\".
- `:port' - Port number of the scopifier server, e.g. 80, 1337.
  `:delay' - Delay between buffer update and colorization, to
  override `context-coloring-default-delay'.
  
- `:version' - Minimum required version that should be printed when
- executing `:command' with a \"--version\" flag.  The version
- should be numeric, e.g. \"2\", \"19700101\", \"1.2.3\",
- \"v1.2.3\" etc.
  `:setup' - Arbitrary code to set up this dispatch when
  `context-coloring-mode' is enabled.
  
  `context-coloring-mode' is disabled."
    (let ((modes (plist-get properties :modes))
          (predicate (plist-get properties :predicate))
-         (colorizer (plist-get properties :colorizer))
-         (command (plist-get properties :command)))
-     (when (null (or modes
-                     predicate))
+         (colorizer (plist-get properties :colorizer)))
+     (when (null (or modes predicate))
        (error "No mode or predicate defined for dispatch"))
-     (when (not (or colorizer
-                    command))
-       (error "No colorizer or command defined for dispatch"))
+     (when (not colorizer)
+       (error "No colorizer defined for dispatch"))
      (puthash symbol properties context-coloring-dispatch-hash-table)
      (dolist (mode modes)
        (puthash mode properties context-coloring-mode-hash-table))
                (when (funcall predicate)
                  properties)) context-coloring-dispatch-predicates))))
  
+ (defun context-coloring-dispatch ()
+   "Determine how to color the current buffer, and color it."
+   (let* ((dispatch (context-coloring-get-current-dispatch))
+          (colorizer (plist-get dispatch :colorizer)))
+     (catch 'interrupted
+       (funcall colorizer))))
  
- ;;; Colorization
- (defvar context-coloring-colorize-hook nil
-   "Hooks to run after coloring a buffer.")
  
- (defun context-coloring-colorize (&optional callback)
-   "Color the current buffer by function context.
+ ;;; Colorization
  
- Invoke CALLBACK when complete; see `context-coloring-dispatch'."
+ (defun context-coloring-colorize ()
+   "Color the current buffer by function context."
    (interactive)
-   (context-coloring-dispatch
-    (lambda ()
-      (when callback (funcall callback))
-      (run-hooks 'context-coloring-colorize-hook))))
+   (context-coloring-update-maximum-face)
+   (context-coloring-dispatch))
  
  (defun context-coloring-colorize-with-buffer (buffer)
    "Color BUFFER."
        (context-coloring-colorize))))
  
  
- ;;; Versioning
- (defun context-coloring-parse-version (string)
-   "Extract segments of a version STRING into a list.  \"v1.0.0\"
- produces (1 0 0), \"19700101\" produces (19700101), etc."
-   (let (version)
-     (while (string-match "[0-9]+" string)
-       (setq version (append version
-                             (list (string-to-number (match-string 0 string)))))
-       (setq string (substring string (match-end 0))))
-     version))
- (defun context-coloring-check-version (expected actual)
-   "Check that version EXPECTED is less than or equal to ACTUAL."
-   (let ((expected (context-coloring-parse-version expected))
-         (actual (context-coloring-parse-version actual))
-         (continue t)
-         (acceptable t))
-     (while (and continue expected)
-       (let ((an-expected (car expected))
-             (an-actual (car actual)))
-         (cond
-          ((> an-actual an-expected)
-           (setq acceptable t)
-           (setq continue nil))
-          ((< an-actual an-expected)
-           (setq acceptable nil)
-           (setq continue nil))))
-       (setq expected (cdr expected))
-       (setq actual (cdr actual)))
-     acceptable))
- (defvar context-coloring-check-scopifier-version-hook nil
-   "Hooks to run after checking the scopifier version.")
- (defun context-coloring-check-scopifier-version (&optional callback)
-   "Asynchronously invoke CALLBACK with a predicate indicating
- whether the current scopifier version satisfies the minimum
- version number required for the current major mode."
-   (let ((dispatch (context-coloring-get-current-dispatch)))
-     (when dispatch
-       (let ((version (plist-get dispatch :version))
-             (command (plist-get dispatch :command)))
-         (context-coloring-shell-command
-          (context-coloring-join (list command "--version") " ")
-          (lambda (output)
-            (cond
-             ((context-coloring-check-version version output)
-              (when callback (funcall callback t)))
-             (t
-              (when callback (funcall callback nil))))
-            (run-hooks 'context-coloring-check-scopifier-version-hook)))))))
- ;;; Themes
- (defvar context-coloring-theme-hash-table (make-hash-table :test #'eq)
-   "Map theme names to theme properties.")
- (defun context-coloring-theme-p (theme)
-   "Return t if THEME is defined, nil otherwise."
-   (and (gethash theme context-coloring-theme-hash-table)))
- (defconst context-coloring-level-face-regexp
-   "context-coloring-level-\\([[:digit:]]+\\)-face"
-   "Extract a level from a face.")
- (defvar context-coloring-originally-set-theme-hash-table
-   (make-hash-table :test #'eq)
-   "Cache custom themes who originally set their own
- `context-coloring-level-N-face' faces.")
- (defun context-coloring-theme-originally-set-p (theme)
-   "Return t if there is a `context-coloring-level-N-face'
- originally set for THEME, nil otherwise."
-   (let (originally-set)
-     (cond
-      ;; `setq' might return a non-nil value for the sake of this `cond'.
-      ((setq
-        originally-set
-        (gethash
-         theme
-         context-coloring-originally-set-theme-hash-table))
-       (eq originally-set 'yes))
-      (t
-       (let* ((settings (get theme 'theme-settings))
-              (tail settings)
-              found)
-         (while (and tail (not found))
-           (and (eq (nth 0 (car tail)) 'theme-face)
-                (string-match
-                 context-coloring-level-face-regexp
-                 (symbol-name (nth 1 (car tail))))
-                (setq found t))
-           (setq tail (cdr tail)))
-         found)))))
- (defun context-coloring-cache-originally-set (theme originally-set)
-   "Remember if THEME had colors originally set for it.  If
- ORIGINALLY-SET is non-nil, it did, otherwise it didn't."
-   ;; Caching whether a theme was originally set is kind of dirty, but we have to
-   ;; do it to remember the past state of the theme.  There are probably some
-   ;; edge cases where caching will be an issue, but they are probably rare.
-   (puthash
-    theme
-    (if originally-set 'yes 'no)
-    context-coloring-originally-set-theme-hash-table))
- (defun context-coloring-warn-theme-originally-set (theme)
-   "Warn the user that the colors for THEME are already originally
- set."
-   (warn "Context coloring colors for theme `%s' are already defined" theme))
- (defun context-coloring-theme-highest-level (theme)
-   "Return the highest level N of a face like
- `context-coloring-level-N-face' set for THEME, or `-1' if there
- is none."
-   (let* ((settings (get theme 'theme-settings))
-          (tail settings)
-          face-string
-          number
-          (found -1))
-     (while tail
-       (and (eq (nth 0 (car tail)) 'theme-face)
-            (setq face-string (symbol-name (nth 1 (car tail))))
-            (string-match
-             context-coloring-level-face-regexp
-             face-string)
-            (setq number (string-to-number
-                          (substring face-string
-                                     (match-beginning 1)
-                                     (match-end 1))))
-            (> number found)
-            (setq found number))
-       (setq tail (cdr tail)))
-     found))
- (defun context-coloring-apply-theme (theme)
-   "Apply THEME's properties to its respective custom theme,
- which must already exist and which *should* already be enabled."
-   (let* ((properties (gethash theme context-coloring-theme-hash-table))
-          (colors (plist-get properties :colors))
-          (level -1))
-     ;; Only clobber when we have to.
-     (when (custom-theme-enabled-p theme)
-       (setq context-coloring-maximum-face (- (length colors) 1)))
-     (apply
-      #'custom-theme-set-faces
-      theme
-      (mapcar
-       (lambda (color)
-         (setq level (+ level 1))
-         `(,(context-coloring-level-face level) ((t (:foreground ,color)))))
-       colors))))
- (defun context-coloring-define-theme (theme &rest properties)
-   "Define a context theme named THEME for coloring scope levels.
- PROPERTIES is a property list specifiying the following details:
- `:aliases': List of symbols of other custom themes that these
- colors are applicable to.
- `:colors': List of colors that this context theme uses.
- `:override': If non-nil, this context theme is intentionally
- overriding colors set by a custom theme.  Don't set this non-nil
- unless there is a custom theme you want to use which sets
- `context-coloring-level-N-face' faces that you want to replace.
- `:recede': If non-nil, this context theme should not apply its
- colors if a custom theme already sets
- `context-coloring-level-N-face' faces.  This option is
- optimistic; set this non-nil if you would rather confer the duty
- of picking colors to a custom theme author (if / when he ever
- gets around to it).
- By default, context themes will always override custom themes,
- even if those custom themes set `context-coloring-level-N-face'
- faces.  If a context theme does override a custom theme, a
- warning will be raised, at which point you may want to enable the
- `:override' option, or just delete your context theme and opt to
- use your custom theme's author's colors instead.
- Context themes only work for the custom theme with the highest
- precedence, i.e. the car of `custom-enabled-themes'."
-   (let ((aliases (plist-get properties :aliases))
-         (override (plist-get properties :override))
-         (recede (plist-get properties :recede)))
-     (dolist (name (append `(,theme) aliases))
-       (puthash name properties context-coloring-theme-hash-table)
-       (when (custom-theme-p name)
-         (let ((originally-set (context-coloring-theme-originally-set-p name)))
-           (context-coloring-cache-originally-set name originally-set)
-           ;; In the particular case when you innocently define colors that a
-           ;; custom theme originally set, warn.  Arguably this only has to be
-           ;; done at enable time, but it is probably more useful to do it at
-           ;; definition time for prompter feedback.
-           (when (and originally-set
-                      (not recede)
-                      (not override))
-             (context-coloring-warn-theme-originally-set name))
-           ;; Set (or overwrite) colors.
-           (when (not (and originally-set
-                           recede))
-             (context-coloring-apply-theme name)))))))
- (defun context-coloring-enable-theme (theme)
-   "Apply THEME if its colors are not already set, else just set
- `context-coloring-maximum-face' to the correct value for THEME."
-   (let* ((properties (gethash theme context-coloring-theme-hash-table))
-          (recede (plist-get properties :recede))
-          (override (plist-get properties :override)))
-     (cond
-      (recede
-       (let ((highest-level (context-coloring-theme-highest-level theme)))
-         (cond
-          ;; This can be true whether originally set by a custom theme or by a
-          ;; context theme.
-          ((> highest-level -1)
-           (setq context-coloring-maximum-face highest-level))
-          ;; It is possible that the corresponding custom theme did not exist at
-          ;; the time of defining this context theme, and in that case the above
-          ;; condition proves the custom theme did not originally set any faces,
-          ;; so we have license to apply the context theme for the first time
-          ;; here.
-          (t
-           (context-coloring-apply-theme theme)))))
-      (t
-       (let ((originally-set (context-coloring-theme-originally-set-p theme)))
-         ;; Cache now in case the context theme was defined after the custom
-         ;; theme.
-         (context-coloring-cache-originally-set theme originally-set)
-         (when (and originally-set
-                    (not override))
-           (context-coloring-warn-theme-originally-set theme))
-         (context-coloring-apply-theme theme))))))
- (defadvice enable-theme (after context-coloring-enable-theme (theme) activate)
-   "Enable colors for context themes just-in-time."
-   (when (and (not (eq theme 'user)) ; Called internally by `enable-theme'.
-              (custom-theme-p theme) ; Guard against non-existent themes.
-              (context-coloring-theme-p theme))
-     (when (= (length custom-enabled-themes) 1)
-       ;; Cache because we can't reliably figure it out in reverse.
-       (setq context-coloring-original-maximum-face
-             context-coloring-maximum-face))
-     (context-coloring-enable-theme theme)))
- (defadvice disable-theme (after context-coloring-disable-theme (theme) activate)
-   "Update `context-coloring-maximum-face'."
-   (when (custom-theme-p theme) ; Guard against non-existent themes.
-     (let ((enabled-theme (car custom-enabled-themes)))
-       (cond
-        ((context-coloring-theme-p enabled-theme)
-         (context-coloring-enable-theme enabled-theme))
-        (t
-         ;; Assume we are back to no theme; act as if nothing ever happened.
-         ;; This is still prone to intervention, but rather extraordinarily.
-         (setq context-coloring-maximum-face
-               context-coloring-original-maximum-face))))))
- (context-coloring-define-theme
-  'ample
-  :recede t
-  :colors '("#bdbdb3"
-            "#baba36"
-            "#6aaf50"
-            "#5180b3"
-            "#ab75c3"
-            "#cd7542"
-            "#df9522"
-            "#454545"))
- (context-coloring-define-theme
-  'anti-zenburn
-  :recede t
-  :colors '("#232333"
-            "#6c1f1c"
-            "#401440"
-            "#0f2050"
-            "#205070"
-            "#336c6c"
-            "#23733c"
-            "#6b400c"
-            "#603a60"
-            "#2f4070"
-            "#235c5c"))
- (context-coloring-define-theme
-  'grandshell
-  :recede t
-  :colors '("#bebebe"
-            "#5af2ee"
-            "#b2baf6"
-            "#f09fff"
-            "#efc334"
-            "#f6df92"
-            "#acfb5a"
-            "#888888"))
- (context-coloring-define-theme
-  'leuven
-  :recede t
-  :colors '("#333333"
-            "#0000ff"
-            "#6434a3"
-            "#ba36a5"
-            "#d0372d"
-            "#036a07"
-            "#006699"
-            "#006fe0"
-            "#808080"))
- (context-coloring-define-theme
-  'monokai
-  :recede t
-  :colors '("#f8f8f2"
-            "#66d9ef"
-            "#a1efe4"
-            "#a6e22e"
-            "#e6db74"
-            "#fd971f"
-            "#f92672"
-            "#fd5ff0"
-            "#ae81ff"))
- (context-coloring-define-theme
-  'solarized
-  :recede t
-  :aliases '(solarized-light
-             solarized-dark
-             sanityinc-solarized-light
-             sanityinc-solarized-dark)
-  :colors '("#839496"
-            "#268bd2"
-            "#2aa198"
-            "#859900"
-            "#b58900"
-            "#cb4b16"
-            "#dc322f"
-            "#d33682"
-            "#6c71c4"
-            "#69b7f0"
-            "#69cabf"
-            "#b4c342"
-            "#deb542"
-            "#f2804f"
-            "#ff6e64"
-            "#f771ac"
-            "#9ea0e5"))
- (context-coloring-define-theme
-  'spacegray
-  :recede t
-  :colors '("#ffffff"
-            "#89aaeb"
-            "#c189eb"
-            "#bf616a"
-            "#dca432"
-            "#ebcb8b"
-            "#b4eb89"
-            "#89ebca"))
- (context-coloring-define-theme
-  'tango
-  :recede t
-  :colors '("#2e3436"
-            "#346604"
-            "#204a87"
-            "#5c3566"
-            "#a40000"
-            "#b35000"
-            "#c4a000"
-            "#8ae234"
-            "#8cc4ff"
-            "#ad7fa8"
-            "#ef2929"
-            "#fcaf3e"
-            "#fce94f"))
- (context-coloring-define-theme
-  'zenburn
-  :recede t
-  :colors '("#dcdccc"
-            "#93e0e3"
-            "#bfebbf"
-            "#f0dfaf"
-            "#dfaf8f"
-            "#cc9393"
-            "#dc8cc3"
-            "#94bff3"
-            "#9fc59f"
-            "#d0bf8f"
-            "#dca3a3"))
  ;;; Built-in dispatches
  
  (context-coloring-define-dispatch
-  'javascript-node
-  :modes '(js-mode js3-mode)
-  :executable "scopifier"
-  :command "scopifier"
-  :version "v1.2.1"
-  :host "localhost"
-  :port 6969)
- (context-coloring-define-dispatch
-  'javascript-js2
+  'javascript
   :modes '(js2-mode)
   :colorizer #'context-coloring-js2-colorize
   :setup
  ;; rely on this predicate instead.
  (defun context-coloring-eval-expression-predicate ()
    "Non-nil if the minibuffer is for `eval-expression'."
-   (eq this-command 'eval-expression))
+   ;; Kinda better than checking `this-command', because `this-command' changes.
+   (context-coloring-eval-expression-match))
  
  (context-coloring-define-dispatch
   'eval-expression
   :setup #'context-coloring-setup-idle-change-detection
   :teardown #'context-coloring-teardown-idle-change-detection)
  
- (defun context-coloring-dispatch (&optional callback)
-   "Determine the optimal track for scopification / coloring of
- the current buffer, then execute it.
- Invoke CALLBACK when complete.  It is invoked synchronously for
- elisp tracks, and asynchronously for shell command tracks."
-   (let* ((dispatch (context-coloring-get-current-dispatch))
-          (colorizer (plist-get dispatch :colorizer))
-          (command (plist-get dispatch :command))
-          (host (plist-get dispatch :host))
-          (port (plist-get dispatch :port))
-          interrupted-p)
-     (cond
-      (colorizer
-       (setq interrupted-p
-             (catch 'interrupted
-               (funcall colorizer)))
-       (when (and (not interrupted-p)
-                  callback)
-         (funcall callback)))
-      (command
-       (cond
-        ((and host port)
-         (context-coloring-scopify-and-colorize-server command host port callback))
-        (t
-         (context-coloring-scopify-and-colorize command callback)))))))
+ (defvar context-coloring-ignore-unavailable-predicates
+   (list
+    #'minibufferp)
+   "Cases when \"unavailable\" messages are silenced.
+ Necessary in editing states where coloring is only sometimes
+ permissible.")
+ (defun context-coloring-ignore-unavailable-message-p ()
+   "Determine if the unavailable message should be silenced."
+   (let ((predicates context-coloring-ignore-unavailable-predicates)
+         (ignore-p nil))
+     (while (and predicates
+                 (not ignore-p))
+       (setq ignore-p (funcall (pop predicates))))
+     ignore-p))
  
  
  ;;; Minor mode
@@@ -1821,11 -1221,10 +1221,10 @@@ comments and strings, is still colored 
  The entire buffer is colored initially.  Changes to the buffer
  trigger recoloring.
  
- Certain custom themes have predefined colors from their palettes
- to use for coloring.  See `context-coloring-theme-hash-table' for
- the supported themes.  If the currently-enabled custom theme is
- not among these, you can define colors for it with
- `context-coloring-define-theme', which see.
+ Define your own colors by customizing faces like
+ `context-coloring-level-N-face', where N is a number starting
+ from 0.  If no face is found on a custom theme nor the `user'
+ theme, the defaults are used.
  
  New language / major mode support can be added with
  `context-coloring-define-dispatch', which see.
@@@ -1844,46 -1243,18 +1243,18 @@@ Feature inspired by Douglas Crockford.
      (let ((dispatch (context-coloring-get-current-dispatch)))
        (cond
         (dispatch
-         (let ((command (plist-get dispatch :command))
-               (version (plist-get dispatch :version))
-               (executable (plist-get dispatch :executable))
-               (setup (plist-get dispatch :setup))
-               (colorize-initially-p t))
-           (when command
-             ;; Shell commands recolor on change, idly.
-             (cond
-              ((and executable
-                    (null (executable-find executable)))
-               (message "Executable \"%s\" not found" executable)
-               (setq colorize-initially-p nil))
-              (version
-               (context-coloring-check-scopifier-version
-                (lambda (sufficient-p)
-                  (cond
-                   (sufficient-p
-                    (context-coloring-setup-idle-change-detection)
-                    (context-coloring-colorize))
-                   (t
-                    (message "Update to the minimum version of \"%s\" (%s)"
-                             executable version)))))
-               (setq colorize-initially-p nil))
-              (t
-               (context-coloring-setup-idle-change-detection))))
+         (let ((setup (plist-get dispatch :setup)))
            (when setup
              (funcall setup))
            ;; Colorize once initially.
-           (when colorize-initially-p
-             (let ((context-coloring-parse-interruptable-p nil))
-               (context-coloring-colorize)))))
-        (t
-         (message "Context coloring is not available for this major mode")))))
+           (let ((context-coloring-parse-interruptable-p nil))
+             (context-coloring-colorize))))
+        ((not (context-coloring-ignore-unavailable-message-p))
+         (message "Context coloring is unavailable here")))))
     (t
      (let ((dispatch (context-coloring-get-current-dispatch)))
        (when dispatch
-         (let ((command (plist-get dispatch :command))
-               (teardown (plist-get dispatch :teardown)))
-           (when command
-             (context-coloring-teardown-idle-change-detection))
+         (let ((teardown (plist-get dispatch :teardown)))
            (when teardown
              (funcall teardown)))))
      (font-lock-mode)
index 39f2f801c1627624f82f624ca3e30a9a3fa723ac,f5633b86e682cd750e797b6d573c2d7a35bb67ee..f5633b86e682cd750e797b6d573c2d7a35bb67ee
@@@ -27,7 -27,7 +27,7 @@@
  
  (require 'cl-lib)
  (require 'context-coloring)
- (require 'ert-async)
+ (require 'ert)
  (require 'js2-mode)
  
  
      (buffer-string)))
  
  (defmacro context-coloring-test-with-fixture (fixture &rest body)
-   "With the relative FIXTURE, evaluate BODY in a temporary
- buffer."
+   "With relative FIXTURE, evaluate BODY in a temporary buffer."
    `(with-temp-buffer
       (progn
         (insert (context-coloring-test-read-file ,fixture))
         ,@body)))
  
- (defun context-coloring-test-with-temp-buffer-async (callback)
-   "Create a temporary buffer, and evaluate CALLBACK there.  A
- teardown callback is passed to CALLBACK for it to invoke when it
- is done."
-   (let ((previous-buffer (current-buffer))
-         (temp-buffer (generate-new-buffer " *temp*")))
-     (set-buffer temp-buffer)
-     (funcall
-      callback
-      (lambda ()
-        (and (buffer-name temp-buffer)
-             (kill-buffer temp-buffer))
-        (set-buffer previous-buffer)))))
- (defun context-coloring-test-with-fixture-async (fixture callback)
-   "With the relative FIXTURE, evaluate CALLBACK in a temporary
- buffer.  A teardown callback is passed to CALLBACK for it to
- invoke when it is done."
-   (context-coloring-test-with-temp-buffer-async
-    (lambda (done-with-temp-buffer)
-      (insert (context-coloring-test-read-file fixture))
-      (funcall
-       callback
-       (lambda ()
-         (funcall done-with-temp-buffer))))))
  
  ;;; Test defining utilities
  
                                                     &key mode
                                                     &key extension
                                                     &key no-fixture
-                                                    &key async
-                                                    &key post-colorization
                                                     &key enable-context-coloring-mode
-                                                    &key get-args
                                                     &key before-each
                                                     &key after-each)
-   "Define a deftest defmacro for tests prefixed with NAME. MODE
+   "Define a deftest defmacro for tests prefixed with NAME.  MODE
  is called to set up tests' environments.  EXTENSION denotes the
  suffix for tests' fixture files.  If NO-FIXTURE is non-nil, don't
- use a fixture.  If ASYNC is non-nil, pass a callback to the
- defined tests' bodies for them to call when they are done.  If
- POST-COLORIZATION is non-nil, the tests run after
- `context-coloring-colorize' finishes asynchronously.  If
- ENABLE-CONTEXT-COLORING-MODE is non-nil, `context-coloring-mode'
- is activated before tests.  GET-ARGS provides arguments to apply
- to BEFORE-EACH, AFTER-EACH, and each tests' body, before and
- after functions.  Functions BEFORE-EACH and AFTER-EACH run before
- the major mode is activated before each test, and after each
- test, even if an error is signaled."
+ use a fixture.  If ENABLE-CONTEXT-COLORING-MODE is non-nil,
+ `context-coloring-mode' is activated before tests.  Functions
+ BEFORE-EACH and AFTER-EACH run before the major mode is activated
+ before each test, and after each test, even if an error is
+ signaled."
    (declare (indent defun))
    (let ((macro-name (intern (format "context-coloring-test-deftest%s"
                                      (cond
                                 &key fixture
                                 &key before
                                 &key after)
-        ,(format "Define a test for `%s' suffixed with NAME.
- Function BODY makes assertions.
- %s
- Functions BEFORE and AFTER run before and after the test, even if
- an error is signaled.
- BODY is run after `context-coloring-mode' is activated, or after
- initial colorization if colorization should occur."
-                 (cadr mode)
-                 (cond
-                  (no-fixture "
- There is no fixture, unless FIXTURE is specified.")
-                  (t
-                   (format "
- The default fixture has a filename matching NAME (plus the
- filetype extension, \"%s\"), unless FIXTURE is specified to
- override it."
-                           extension))))
         (declare (indent defun))
         ;; Commas in nested backquotes are not evaluated.  Binding the variables
         ;; here is probably the cleanest workaround.
         (let ((mode ,mode)
-              (get-args ',(cond
-                           (get-args get-args)
-                           (t '(lambda () (list)))))
-              (args (make-symbol "args"))
               (before-each ',before-each)
               (after-each ',after-each)
               (test-name (intern (format ,(format "%s-%%s"
                                                   (cond
                                                    (name)
-                                                   (t "sync"))) name)))
+                                                   (t "generic"))) name)))
               (fixture (cond
                         (fixture (format "./fixtures/%s" fixture))
                         (,no-fixture "./fixtures/empty")
                         (t (format ,(format "./fixtures/%%s.%s" extension) name)))))
-          ,@(cond
-             ((or async post-colorization)
-              `((let ((post-colorization ,post-colorization))
-                  `(ert-deftest-async ,test-name (done)
-                     (let ((,args (funcall ,get-args)))
-                       (context-coloring-test-with-fixture-async
-                        ,fixture
-                        (lambda (done-with-fixture)
-                          (when ,before-each (apply ,before-each ,args))
-                          (,mode)
-                          (when ,before (apply ,before ,args))
-                          (cond
-                           (,post-colorization
-                            (context-coloring-colorize
-                             (lambda ()
-                               (unwind-protect
-                                   (progn
-                                     (apply ,body ,args))
-                                 (when ,after (apply ,after ,args))
-                                 (when ,after-each (apply ,after-each ,args))
-                                 (funcall done-with-fixture))
-                               (funcall done))))
-                           (t
-                            ;; Leave error handling up to the user.
-                            (apply ,body (append
-                                          (list (lambda ()
-                                                  (when ,after (apply ,after ,args))
-                                                  (when ,after-each (apply ,after-each ,args))
-                                                  (funcall done-with-fixture)
-                                                  (funcall done)))
-                                          ,args)))))))))))
-             (t
-              `((let ((enable-context-coloring-mode ,enable-context-coloring-mode))
-                  `(ert-deftest ,test-name ()
-                     (let ((,args (funcall ,get-args)))
-                       (context-coloring-test-with-fixture
-                        ,fixture
-                        (when ,before-each (apply ,before-each ,args))
-                        (,mode)
-                        (when ,before (apply ,before ,args))
-                        (when ,enable-context-coloring-mode (context-coloring-mode))
-                        (unwind-protect
-                            (progn
-                              (apply ,body ,args))
-                          (when ,after (apply ,after ,args))
-                          (when ,after-each (apply ,after-each ,args))))))))))))))
+          ,@`((let ((enable-context-coloring-mode ,enable-context-coloring-mode))
+                `(ert-deftest ,test-name ()
+                   (context-coloring-test-with-fixture
+                    ,fixture
+                    (when ,before-each (funcall ,before-each))
+                    (,mode)
+                    (when ,before (funcall ,before))
+                    (when ,enable-context-coloring-mode (context-coloring-mode))
+                    (unwind-protect
+                        (progn
+                          (funcall ,body))
+                      (when ,after (funcall ,after))
+                      (when ,after-each (funcall ,after-each)))))))))))
  
  (context-coloring-test-define-deftest nil
    :mode #'fundamental-mode
    :no-fixture t)
  
- (context-coloring-test-define-deftest async
-   :mode #'fundamental-mode
-   :no-fixture t
-   :async t)
- (context-coloring-test-define-deftest js
-   :mode #'js-mode
-   :extension "js"
-   :post-colorization t)
- (context-coloring-test-define-deftest js2
+ (context-coloring-test-define-deftest javascript
    :mode #'js2-mode
    :extension "js"
    :enable-context-coloring-mode t
                   (setq js2-mode-show-parse-errors nil)
                   (setq js2-mode-show-strict-warnings nil)))
  
- (defmacro context-coloring-test-deftest-js-js2 (&rest args)
-   "Simultaneously define the same test for js and js2 (with
- ARGS)."
-   (declare (indent defun))
-   `(progn
-      (context-coloring-test-deftest-js ,@args)
-      (context-coloring-test-deftest-js2 ,@args)))
  (context-coloring-test-define-deftest emacs-lisp
    :mode #'emacs-lisp-mode
    :extension "el"
    :mode #'fundamental-mode
    :no-fixture t)
  
- (context-coloring-test-define-deftest define-theme
-   :mode #'fundamental-mode
-   :no-fixture t
-   :get-args (lambda ()
-               (list (context-coloring-test-get-next-theme)))
-   :after-each (lambda (theme)
-                 (setq context-coloring-maximum-face 7)
-                 (setq context-coloring-original-maximum-face
-                       context-coloring-maximum-face)
-                 (disable-theme theme)
-                 (context-coloring-test-kill-buffer "*Warnings*")))
  
  ;;; Assertion functions
  
               "but it did")
              buffer expected)))))))
  
- (defun context-coloring-test-assert-no-message (buffer)
-   "Assert that BUFFER has no message."
-   (when (get-buffer buffer)
-     (ert-fail (format (concat "Expected buffer `%s' to have no messages, "
-                               "but it did: `%s'")
-                       buffer
-                       (with-current-buffer buffer
-                         (buffer-string))))))
  (defun context-coloring-test-assert-error (body error-message)
    "Assert that BODY signals ERROR-MESSAGE."
    (let ((error-signaled-p nil))
  
  ;;; Miscellaneous tests
  
- (defun context-coloring-test-assert-trimmed (result expected)
-   "Assert that RESULT is trimmed like EXPECTED."
-   (when (not (string-equal result expected))
-     (ert-fail "Expected string to be trimmed, but it wasn't.")))
- (context-coloring-test-deftest trim
-   (lambda ()
-     (context-coloring-test-assert-trimmed (context-coloring-trim "") "")
-     (context-coloring-test-assert-trimmed (context-coloring-trim " ") "")
-     (context-coloring-test-assert-trimmed (context-coloring-trim "a") "a")
-     (context-coloring-test-assert-trimmed (context-coloring-trim " a") "a")
-     (context-coloring-test-assert-trimmed (context-coloring-trim "a ") "a")
-     (context-coloring-test-assert-trimmed (context-coloring-trim " a ") "a")))
- (context-coloring-test-deftest-async mode-startup
-   (lambda (done)
-     (js-mode)
-     (add-hook
-      'context-coloring-colorize-hook
-      (lambda ()
-        ;; If this runs we are implicitly successful; this test only confirms
-        ;; that colorization occurs on mode startup.
-        (funcall done)))
-     (context-coloring-mode))
-   :after (lambda ()
-            ;; TODO: This won't run if there is a timeout.  Will probably have to
-            ;; roll our own `ert-deftest-async'.
-            (setq context-coloring-colorize-hook nil)))
  (defmacro context-coloring-test-define-derived-mode (name)
    "Define a derived mode exclusively for any test with NAME."
    (let ((name (intern (format "context-coloring-test-%s-mode" name))))
      `(define-derived-mode ,name fundamental-mode "Testing")))
  
+ (defvar context-coloring-test-caused-p nil
+   "If non-nil, coloring was caused.")
+ (defmacro context-coloring-test-assert-causes-coloring (&rest body)
+   "Assert that BODY causes coloring."
+   `(progn
+      ;; Gross, but I want this to pass on 24.3.
+      (ad-add-advice #'context-coloring-colorize
+                     '(assert-causes-coloring
+                       nil t
+                       (advice . (lambda ()
+                                   (setq context-coloring-test-caused-p t))))
+                     'after
+                     0)
+      (ad-activate #'context-coloring-colorize)
+      ,@body
+      (when (not context-coloring-test-caused-p)
+        (ert-fail "Expected to have colorized, but it didn't."))))
+ (defun context-coloring-test-cleanup-assert-causes-coloring ()
+   "Undo `context-coloring-test-assert-causes-coloring'."
+   (ad-unadvise #'context-coloring-colorize)
+   (setq context-coloring-test-caused-p nil))
+ (context-coloring-test-define-derived-mode mode-startup)
+ (context-coloring-test-deftest mode-startup
+   (lambda ()
+     (context-coloring-define-dispatch
+      'mode-startup
+      :modes '(context-coloring-test-mode-startup-mode)
+      :colorizer #'ignore)
+     (context-coloring-test-mode-startup-mode)
+     (context-coloring-test-assert-causes-coloring
+      (context-coloring-mode)))
+   :after (lambda ()
+            (context-coloring-test-cleanup-assert-causes-coloring)))
  (context-coloring-test-define-derived-mode change-detection)
  
- ;; Simply cannot figure out how to trigger an idle timer; would much rather test
- ;; that.  But (current-idle-time) always returns nil in these tests.
- (context-coloring-test-deftest-async change-detection
-   (lambda (done)
+ (context-coloring-test-deftest change-detection
+   (lambda ()
      (context-coloring-define-dispatch
       'idle-change
       :modes '(context-coloring-test-change-detection-mode)
-      :executable "node"
-      :command "node test/binaries/noop")
+      :colorizer #'ignore
+      :setup #'context-coloring-setup-idle-change-detection
+      :teardown #'context-coloring-teardown-idle-change-detection)
      (context-coloring-test-change-detection-mode)
-     (add-hook
-      'context-coloring-colorize-hook
-      (lambda ()
-        (setq context-coloring-colorize-hook nil)
-        (add-hook
-         'context-coloring-colorize-hook
-         (lambda ()
-           (funcall done)))
-        (insert " ")
-        (set-window-buffer (selected-window) (current-buffer))
-        (context-coloring-maybe-colorize-with-buffer (current-buffer))))
-     (context-coloring-mode))
+     (context-coloring-mode)
+     (context-coloring-test-assert-causes-coloring
+      (insert " ")
+      ;; Simply cannot figure out how to trigger an idle timer; would much rather
+      ;; test that.  But (current-idle-time) always returns nil in these tests.
+      (context-coloring-maybe-colorize-with-buffer (current-buffer))))
    :after (lambda ()
-            (setq context-coloring-colorize-hook nil)))
- (context-coloring-test-deftest check-version
-   (lambda ()
-     (when (not (context-coloring-check-version "2.1.3" "3.0.1"))
-       (ert-fail "Expected version 3.0.1 to satisfy 2.1.3, but it didn't."))
-     (when (context-coloring-check-version "3.0.1" "2.1.3")
-       (ert-fail "Expected version 2.1.3 not to satisfy 3.0.1, but it did."))))
+            (context-coloring-test-cleanup-assert-causes-coloring)))
  
  (context-coloring-test-deftest unsupported-mode
    (lambda ()
      (context-coloring-mode)
      (context-coloring-test-assert-message
-      "Context coloring is not available for this major mode"
+      "Context coloring is unavailable here"
       "*Messages*")))
  
  (context-coloring-test-deftest derived-mode
      (lisp-interaction-mode)
      (context-coloring-mode)
      (context-coloring-test-assert-not-message
-      "Context coloring is not available for this major mode"
+      "Context coloring is unavailable here"
       "*Messages*")))
  
+ (context-coloring-test-deftest unavailable-message-ignored
+   (lambda ()
+     (minibuffer-with-setup-hook
+         (lambda ()
+           (context-coloring-mode)
+           (context-coloring-test-assert-not-message
+            "Context coloring is unavailable here"
+            "*Messages*"))
+       (execute-kbd-macro
+        (vconcat
+         [?\C-u]
+         [?\M-!])))))
  (context-coloring-test-define-derived-mode define-dispatch-error)
  
  (context-coloring-test-deftest define-dispatch-error
         (context-coloring-define-dispatch
          'define-dispatch-no-strategy
          :modes '(context-coloring-test-define-dispatch-error-mode)))
-      "No colorizer or command defined for dispatch")))
- (context-coloring-test-define-derived-mode missing-executable)
- (context-coloring-test-deftest missing-executable
-   (lambda ()
-     (context-coloring-define-dispatch
-      'scopifier
-      :modes '(context-coloring-test-missing-executable-mode)
-      :command ""
-      :executable "__should_not_exist__")
-     (context-coloring-test-missing-executable-mode)
-     (context-coloring-mode)))
- (context-coloring-test-define-derived-mode unsupported-version)
- (context-coloring-test-deftest-async unsupported-version
-   (lambda (done)
-     (context-coloring-define-dispatch
-      'outta-date
-      :modes '(context-coloring-test-unsupported-version-mode)
-      :executable "node"
-      :command "node test/binaries/outta-date"
-      :version "v2.1.3")
-     (context-coloring-test-unsupported-version-mode)
-     (add-hook
-      'context-coloring-check-scopifier-version-hook
-      (lambda ()
-        (unwind-protect
-            (progn
-              ;; Normally the executable would be something like "outta-date"
-              ;; rather than "node".
-              (context-coloring-test-assert-message
-               "Update to the minimum version of \"node\" (v2.1.3)"
-               "*Messages*"))
-          (funcall done))))
-     (context-coloring-mode))
-   :after (lambda ()
-            (setq context-coloring-check-scopifier-version-hook nil)))
+      "No colorizer defined for dispatch")))
  
  (context-coloring-test-define-derived-mode disable-mode)
  
- (context-coloring-test-deftest-async disable-mode
-   (lambda (done)
+ (context-coloring-test-deftest disable-mode
+   (lambda ()
      (let (torn-down)
        (context-coloring-define-dispatch
         'disable-mode
         :modes '(context-coloring-test-disable-mode-mode)
-        :executable "node"
-        :command "node test/binaries/noop"
+        :colorizer #'ignore
         :teardown (lambda ()
                     (setq torn-down t)))
-       (unwind-protect
-           (progn
-             (context-coloring-test-disable-mode-mode)
-             (context-coloring-mode)
-             (context-coloring-mode -1)
-             (when (not torn-down)
-               (ert-fail "Expected teardown function to have been called, but it wasn't.")))
-         (funcall done)))))
- ;;; Theme tests
- (defvar context-coloring-test-theme-index 0
-   "Unique index for unique theme names.")
- (defun context-coloring-test-get-next-theme ()
-   "Return a unique symbol for a throwaway theme."
-   (prog1
-       (intern (format "context-coloring-test-theme-%s"
-                       context-coloring-test-theme-index))
-     (setq context-coloring-test-theme-index
-           (+ context-coloring-test-theme-index 1))))
- (defun context-coloring-test-assert-face (level foreground &optional negate)
-   "Assert that a face for LEVEL exists and that its `:foreground'
- is FOREGROUND, or the inverse if NEGATE is non-nil."
-   (let* ((face (context-coloring-level-face level))
-          actual-foreground)
-     (when (not (or negate
-                    face))
-       (ert-fail (format (concat "Expected face for level `%s' to exist; "
-                                 "but it didn't")
-                         level)))
-     (setq actual-foreground (face-attribute face :foreground))
-     (when (funcall (if negate #'identity #'not)
-                    (string-equal foreground actual-foreground))
-       (ert-fail (format (concat "Expected face for level `%s' "
-                                 "%sto have foreground `%s'; "
-                                 "but it %s.")
-                         level
-                         (if negate "not " "") foreground
-                         (if negate
-                             "did" (format "was `%s'" actual-foreground)))))))
- (defun context-coloring-test-assert-not-face (&rest arguments)
-   "Assert that LEVEL does not have a face with `:foreground'
- FOREGROUND.  Apply ARGUMENTS to
- `context-coloring-test-assert-face', see that function."
-   (apply #'context-coloring-test-assert-face
-          (append arguments '(t))))
- (defun context-coloring-test-assert-theme-originally-set-p
-     (settings &optional negate)
-   "Assert that `context-coloring-theme-originally-set-p' will
- return t for a theme with SETTINGS, or the inverse if NEGATE is
- non-nil."
-   (let ((theme (context-coloring-test-get-next-theme)))
-     (put theme 'theme-settings settings)
-     (when (funcall (if negate #'identity #'not)
-                    (context-coloring-theme-originally-set-p theme))
-       (ert-fail (format (concat "Expected theme `%s' with settings `%s' "
-                                 "%sto be considered to have defined a level, "
-                                 "but it %s.")
-                         theme settings
-                         (if negate "not " "")
-                         (if negate "was" "wasn't"))))))
- (defun context-coloring-test-assert-not-theme-originally-set-p (&rest arguments)
-   "Assert that `context-coloring-theme-originally-set-p' does not
- return t for a theme with SETTINGS.  Apply ARGUMENTS to
- `context-coloring-test-assert-theme-originally-set-p', see that
- function."
-   (apply #'context-coloring-test-assert-theme-originally-set-p
-          (append arguments '(t))))
- (context-coloring-test-deftest theme-originally-set-p
-   (lambda ()
-     (context-coloring-test-assert-theme-originally-set-p
-      '((theme-face context-coloring-level-0-face)))
-     (context-coloring-test-assert-theme-originally-set-p
-      '((theme-face face)
-        (theme-face context-coloring-level-0-face)))
-     (context-coloring-test-assert-theme-originally-set-p
-      '((theme-face context-coloring-level-0-face)
-        (theme-face face)))
-     (context-coloring-test-assert-not-theme-originally-set-p
-      '((theme-face face)))))
- (defun context-coloring-test-assert-theme-settings-highest-level
-     (settings expected-level)
-   "Assert that a theme with SETTINGS has the highest level
- EXPECTED-LEVEL."
-   (let ((theme (context-coloring-test-get-next-theme)))
-     (put theme 'theme-settings settings)
-     (context-coloring-test-assert-theme-highest-level theme expected-level)))
- (defun context-coloring-test-assert-theme-highest-level
-     (theme expected-level &optional negate)
-   "Assert that THEME has the highest level EXPECTED-LEVEL, or the
- inverse if NEGATE is non-nil."
-   (let ((highest-level (context-coloring-theme-highest-level theme)))
-     (when (funcall (if negate #'identity #'not) (eq highest-level expected-level))
-       (ert-fail (format (concat "Expected theme with settings `%s' "
-                                 "%sto have a highest level of `%s', "
-                                 "but it %s.")
-                         (get theme 'theme-settings)
-                         (if negate "not " "") expected-level
-                         (if negate "did" (format "was %s" highest-level)))))))
- (defun context-coloring-test-assert-theme-not-highest-level (&rest arguments)
-   "Assert that THEME's highest level is not EXPECTED-LEVEL.
- Apply ARGUMENTS to
- `context-coloring-test-assert-theme-highest-level', see that
- function."
-   (apply #'context-coloring-test-assert-theme-highest-level
-          (append arguments '(t))))
- (context-coloring-test-deftest theme-highest-level
+       (context-coloring-test-disable-mode-mode)
+       (context-coloring-mode)
+       (context-coloring-mode -1)
+       (when (not torn-down)
+         (ert-fail "Expected teardown function to have been called, but it wasn't.")))))
+ (defun context-coloring-test-assert-maximum-face (expected)
+   "Assert that `context-coloring-maximum-face' is EXPECTED."
+   (when (not (= context-coloring-maximum-face expected))
+     (ert-fail (format "Expected maximum face to be %s, but it was %s"
+                       expected context-coloring-maximum-face))))
+ (deftheme context-coloring-test-custom-theme)
+ (context-coloring-test-define-derived-mode custom-theme)
+ (context-coloring-test-deftest custom-theme
    (lambda ()
-     (context-coloring-test-assert-theme-settings-highest-level
-      '((theme-face foo))
-      -1)
-     (context-coloring-test-assert-theme-settings-highest-level
-      '((theme-face context-coloring-level-0-face))
-      0)
-     (context-coloring-test-assert-theme-settings-highest-level
-      '((theme-face context-coloring-level-1-face))
-      1)
-     (context-coloring-test-assert-theme-settings-highest-level
-      '((theme-face context-coloring-level-1-face)
-        (theme-face context-coloring-level-0-face))
-      1)
-     (context-coloring-test-assert-theme-settings-highest-level
-      '((theme-face context-coloring-level-0-face)
-        (theme-face context-coloring-level-1-face))
-      1)))
- (defun context-coloring-test-kill-buffer (buffer)
-   "Kill BUFFER if it exists."
-   (when (get-buffer buffer) (kill-buffer buffer)))
- (defun context-coloring-test-deftheme (theme)
-   "Dynamically define theme THEME."
-   (eval (macroexpand `(deftheme ,theme))))
- (context-coloring-test-deftest-define-theme additive
-   (lambda (theme)
-     (context-coloring-test-deftheme theme)
-     (context-coloring-define-theme
-      theme
-      :colors '("#aaaaaa"
-                "#bbbbbb"))
-     (context-coloring-test-assert-no-message "*Warnings*")
-     (enable-theme theme)
-     (context-coloring-test-assert-no-message "*Warnings*")
-     (context-coloring-test-assert-face 0 "#aaaaaa")
-     (context-coloring-test-assert-face 1 "#bbbbbb")))
- (defun context-coloring-test-assert-defined-warning (theme)
-   "Assert that a warning about colors already being defined for
- theme THEME is signaled."
-   (context-coloring-test-assert-message
-    (format (concat "Warning (emacs): Context coloring colors for theme "
-                    "`%s' are already defined")
-            theme)
-    "*Warnings*"))
- (context-coloring-test-deftest-define-theme unintentional-override
-   (lambda (theme)
-     (context-coloring-test-deftheme theme)
-     (custom-theme-set-faces
-      theme
-      '(context-coloring-level-0-face ((t (:foreground "#aaaaaa"))))
-      '(context-coloring-level-1-face ((t (:foreground "#bbbbbb")))))
-     (context-coloring-define-theme
-      theme
-      :colors '("#cccccc"
-                "#dddddd"))
-     (context-coloring-test-assert-defined-warning theme)
-     (context-coloring-test-kill-buffer "*Warnings*")
-     (enable-theme theme)
-     (context-coloring-test-assert-defined-warning theme)
-     (context-coloring-test-assert-face 0 "#cccccc")
-     (context-coloring-test-assert-face 1 "#dddddd")))
- (context-coloring-test-deftest-define-theme intentional-override
-   (lambda (theme)
-     (context-coloring-test-deftheme theme)
      (custom-theme-set-faces
-      theme
-      '(context-coloring-level-0-face ((t (:foreground "#aaaaaa"))))
-      '(context-coloring-level-1-face ((t (:foreground "#bbbbbb")))))
-     (context-coloring-define-theme
-      theme
-      :override t
-      :colors '("#cccccc"
-                "#dddddd"))
-     (context-coloring-test-assert-no-message "*Warnings*")
-     (enable-theme theme)
-     (context-coloring-test-assert-no-message "*Warnings*")
-     (context-coloring-test-assert-face 0 "#cccccc")
-     (context-coloring-test-assert-face 1 "#dddddd")))
- (context-coloring-test-deftest-define-theme pre-recede
-   (lambda (theme)
-     (context-coloring-define-theme
-      theme
-      :recede t
-      :colors '("#aaaaaa"
-                "#bbbbbb"))
-     (context-coloring-test-deftheme theme)
-     (custom-theme-set-faces
-      theme
-      '(context-coloring-level-0-face ((t (:foreground "#cccccc"))))
-      '(context-coloring-level-1-face ((t (:foreground "#dddddd")))))
-     (enable-theme theme)
-     (context-coloring-test-assert-no-message "*Warnings*")
-     (context-coloring-test-assert-face 0 "#cccccc")
-     (context-coloring-test-assert-face 1 "#dddddd")))
- (context-coloring-test-deftest-define-theme pre-recede-delayed-application
-   (lambda (theme)
-     (context-coloring-define-theme
-      theme
-      :recede t
-      :colors '("#aaaaaa"
-                "#bbbbbb"))
-     (context-coloring-test-deftheme theme)
-     (enable-theme theme)
-     (context-coloring-test-assert-no-message "*Warnings*")
-     (context-coloring-test-assert-face 0 "#aaaaaa")
-     (context-coloring-test-assert-face 1 "#bbbbbb")))
- (context-coloring-test-deftest-define-theme post-recede
-   (lambda (theme)
-     (context-coloring-test-deftheme theme)
-     (custom-theme-set-faces
-      theme
-      '(context-coloring-level-0-face ((t (:foreground "#aaaaaa"))))
-      '(context-coloring-level-1-face ((t (:foreground "#bbbbbb")))))
-     (context-coloring-define-theme
-      theme
-      :recede t
-      :colors '("#cccccc"
-                "#dddddd"))
-     (context-coloring-test-assert-no-message "*Warnings*")
-     (context-coloring-test-assert-face 0 "#aaaaaa")
-     (context-coloring-test-assert-face 1 "#bbbbbb")
-     (enable-theme theme)
-     (context-coloring-test-assert-no-message "*Warnings*")
-     (context-coloring-test-assert-face 0 "#aaaaaa")
-     (context-coloring-test-assert-face 1 "#bbbbbb")))
- (context-coloring-test-deftest-define-theme recede-not-defined
-   (lambda (theme)
-     (context-coloring-test-deftheme theme)
-     (custom-theme-set-faces
-      theme
-      '(foo-face ((t (:foreground "#ffffff")))))
-     (context-coloring-define-theme
-      theme
-      :recede t
-      :colors '("#aaaaaa"
-                "#bbbbbb"))
-     (context-coloring-test-assert-no-message "*Warnings*")
-     (context-coloring-test-assert-face 0 "#aaaaaa")
-     (context-coloring-test-assert-face 1 "#bbbbbb")
-     (enable-theme theme)
-     (context-coloring-test-assert-no-message "*Warnings*")
-     (context-coloring-test-assert-face 0 "#aaaaaa")
-     (context-coloring-test-assert-face 1 "#bbbbbb")))
- (context-coloring-test-deftest-define-theme unintentional-obstinance
-   (lambda (theme)
-     (context-coloring-define-theme
-      theme
-      :colors '("#aaaaaa"
-                "#bbbbbb"))
-     (context-coloring-test-deftheme theme)
-     (custom-theme-set-faces
-      theme
-      '(context-coloring-level-0-face ((t (:foreground "#cccccc"))))
-      '(context-coloring-level-1-face ((t (:foreground "#dddddd")))))
-     (enable-theme theme)
-     (context-coloring-test-assert-defined-warning theme)
-     (context-coloring-test-assert-face 0 "#aaaaaa")
-     (context-coloring-test-assert-face 1 "#bbbbbb")))
- (context-coloring-test-deftest-define-theme intentional-obstinance
-   (lambda (theme)
-     (context-coloring-define-theme
-      theme
-      :override t
-      :colors '("#aaaaaa"
-                "#bbbbbb"))
-     (context-coloring-test-deftheme theme)
-     (custom-theme-set-faces
-      theme
-      '(context-coloring-level-0-face ((t (:foreground "#cccccc"))))
-      '(context-coloring-level-1-face ((t (:foreground "#dddddd")))))
-     (enable-theme theme)
-     (context-coloring-test-assert-no-message "*Warnings*")
-     (context-coloring-test-assert-face 0 "#aaaaaa")
-     (context-coloring-test-assert-face 1 "#bbbbbb")))
- (defun context-coloring-test-assert-maximum-face (maximum &optional negate)
-   "Assert that `context-coloring-maximum-face' is MAXIMUM, or the
- inverse if NEGATE is non-nil."
-   (when (funcall (if negate #'identity #'not)
-                  (eq context-coloring-maximum-face maximum))
-     (ert-fail (format (concat "Expected `context-coloring-maximum-face' "
-                               "%sto be `%s', "
-                               "but it %s.")
-                       (if negate "not " "") maximum
-                       (if negate
-                           "was"
-                         (format "was `%s'" context-coloring-maximum-face))))))
- (defun context-coloring-test-assert-not-maximum-face (&rest arguments)
-   "Assert that `context-coloring-maximum-face' is not MAXIMUM.
- Apply ARGUMENTS to `context-coloring-test-assert-maximum-face',
- see that function."
-   (apply #'context-coloring-test-assert-maximum-face
-          (append arguments '(t))))
- (context-coloring-test-deftest-define-theme disable-cascade
-   (lambda (theme)
-     (let ((maximum-face-value 9999))
-       (setq context-coloring-maximum-face maximum-face-value)
-       (context-coloring-test-deftheme theme)
-       (context-coloring-define-theme
-        theme
-        :colors '("#aaaaaa"
-                  "#bbbbbb"))
-       (let ((second-theme (context-coloring-test-get-next-theme)))
-         (context-coloring-test-deftheme second-theme)
-         (context-coloring-define-theme
-          second-theme
-          :colors '("#cccccc"
-                    "#dddddd"
-                    "#eeeeee"))
-         (let ((third-theme (context-coloring-test-get-next-theme)))
-           (context-coloring-test-deftheme third-theme)
-           (context-coloring-define-theme
-            third-theme
-            :colors '("#111111"
-                      "#222222"
-                      "#333333"
-                      "#444444"))
-           (enable-theme theme)
-           (enable-theme second-theme)
-           (enable-theme third-theme)
-           (disable-theme third-theme)
-           (context-coloring-test-assert-face 0 "#cccccc")
-           (context-coloring-test-assert-face 1 "#dddddd")
-           (context-coloring-test-assert-face 2 "#eeeeee")
-           (context-coloring-test-assert-maximum-face 2))
-         (disable-theme second-theme)
-         (context-coloring-test-assert-face 0 "#aaaaaa")
-         (context-coloring-test-assert-face 1 "#bbbbbb")
-         (context-coloring-test-assert-maximum-face 1))
-       (disable-theme theme)
-       (context-coloring-test-assert-not-face 0 "#aaaaaa")
-       (context-coloring-test-assert-not-face 1 "#bbbbbb")
-       (context-coloring-test-assert-maximum-face
-        maximum-face-value))))
+      'context-coloring-test-custom-theme
+      '(context-coloring-level-0-face ((t :foreground "#aaaaaa")))
+      '(context-coloring-level-1-face ((t :foreground "#bbbbbb"))))
+     (custom-set-faces
+      '(context-coloring-level-0-face ((t :foreground "#aaaaaa"))))
+     (enable-theme 'context-coloring-test-custom-theme)
+     (context-coloring-define-dispatch
+      'theme
+      :modes '(context-coloring-test-custom-theme-mode)
+      :colorizer #'ignore)
+     (context-coloring-test-custom-theme-mode)
+     (context-coloring-colorize)
+     (context-coloring-test-assert-maximum-face 1)
+     ;; This theme should now be ignored in favor of the `user' theme.
+     (custom-theme-reset-faces
+      'context-coloring-test-custom-theme
+      '(context-coloring-level-0-face nil)
+      '(context-coloring-level-1-face nil))
+     (context-coloring-colorize)
+     ;; Maximum face for `user'.
+     (context-coloring-test-assert-maximum-face 0)
+     ;; Now `user' should be ignored too.
+     (custom-reset-faces
+      '(context-coloring-level-0-face nil))
+     (context-coloring-colorize)
+     ;; Expect the package's defaults.
+     (context-coloring-test-assert-maximum-face
+      context-coloring-default-maximum-face))
+   :after (lambda ()
+            (custom-reset-faces
+             '(context-coloring-level-0-face nil))
+            (disable-theme 'context-coloring-test-custom-theme)))
  
  
  ;;; Coloring tests
@@@ -957,7 -480,7 +480,7 @@@ other non-letters are guaranteed to alw
          (forward-char)))
        (setq index (1+ index)))))
  
- (context-coloring-test-deftest-js-js2 function-scopes
+ (context-coloring-test-deftest-javascript function-scopes
    (lambda ()
      (context-coloring-test-assert-coloring "
  000 0 0 11111111 11 110
      22222222 122 22
  1")))
  
- (context-coloring-test-deftest-js-js2 global
+ (context-coloring-test-deftest-javascript global
    (lambda ()
      (context-coloring-test-assert-coloring "
  (xxxxxxxx () {
      111 1 1 00000001xxx11
  }());")))
  
- (context-coloring-test-deftest-js2 block-scopes
+ (context-coloring-test-deftest-javascript block-scopes
    (lambda ()
      (context-coloring-test-assert-coloring "
  (xxxxxxxx () {
      2
  }());"))
    :before (lambda ()
-             (setq context-coloring-js-block-scopes t))
+             (setq context-coloring-javascript-block-scopes t))
    :after (lambda ()
-            (setq context-coloring-js-block-scopes nil)))
+            (setq context-coloring-javascript-block-scopes nil)))
  
- (context-coloring-test-deftest-js-js2 catch
+ (context-coloring-test-deftest-javascript catch
    (lambda ()
      (context-coloring-test-assert-coloring "
  (xxxxxxxx () {
      2
  }());")))
  
- (context-coloring-test-deftest-js-js2 key-names
+ (context-coloring-test-deftest-javascript key-names
    (lambda ()
      (context-coloring-test-assert-coloring "
  (xxxxxxxx () {
      11
  }());")))
  
- (context-coloring-test-deftest-js-js2 property-lookup
+ (context-coloring-test-deftest-javascript property-lookup
    (lambda ()
      (context-coloring-test-assert-coloring "
  (xxxxxxxx () {
      00000011111111111
  }());")))
  
- (context-coloring-test-deftest-js-js2 key-values
+ (context-coloring-test-deftest-javascript key-values
    (lambda ()
      (context-coloring-test-assert-coloring "
  (xxxxxxxx () {
      }());
  }());")))
  
- (context-coloring-test-deftest-js-js2 syntactic-comments-and-strings
+ (context-coloring-test-deftest-javascript syntactic-comments-and-strings
    (lambda ()
      (context-coloring-test-assert-coloring "
  0000 00
@@@ -1039,7 -562,7 +562,7 @@@ ccccccccc
  ssssssssssss0"))
    :fixture "comments-and-strings.js")
  
- (context-coloring-test-deftest-js-js2 syntactic-comments
+ (context-coloring-test-deftest-javascript syntactic-comments
    (lambda ()
      (context-coloring-test-assert-coloring "
  0000 00
@@@ -1052,7 -575,7 +575,7 @@@ ccccccccc
    :after (lambda ()
             (setq context-coloring-syntactic-strings t)))
  
- (context-coloring-test-deftest-js-js2 syntactic-strings
+ (context-coloring-test-deftest-javascript syntactic-strings
    (lambda ()
      (context-coloring-test-assert-coloring "
  0000 00
@@@ -1065,7 -588,7 +588,7 @@@ ssssssssssss0")
    :after (lambda ()
             (setq context-coloring-syntactic-comments t)))
  
- (context-coloring-test-deftest-js2 unterminated-comment
+ (context-coloring-test-deftest-javascript unterminated-comment
    ;; As long as `add-text-properties' doesn't signal an error, this test passes.
    (lambda ()))