summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Whitton <spwhitton@spwhitton.name>2016-05-11 11:56:54 -0300
committerSean Whitton <spwhitton@spwhitton.name>2016-05-11 11:56:54 -0300
commit883fcc703b6e912ee45480be86547a2f471a73ad (patch)
tree56a641b9db272482dda90399feb4a36c04d050ce
Import rainbow-delimiters_2.1.3.orig.tar.xz
[dgit import orig rainbow-delimiters_2.1.3.orig.tar.xz]
-rw-r--r--.gitignore1
-rw-r--r--.travis.yml19
-rw-r--r--README.md75
-rw-r--r--rainbow-delimiters-test.el286
-rw-r--r--rainbow-delimiters.el292
5 files changed, 673 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c531d98
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.elc
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..6f413e7
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,19 @@
+language: emacs-lisp
+env:
+ - EMACS=emacs23
+ - EMACS=emacs24
+ - EMACS=emacs-snapshot
+before_install:
+ - sudo add-apt-repository -y ppa:cassou/emacs
+ - sudo add-apt-repository -y ppa:ubuntu-elisp/ppa
+ - sudo apt-get update -y -q
+ - sudo apt-get install -y $EMACS-nox
+install:
+ - if [ "$EMACS" = "emacs23" ]; then
+ curl -O 'https://raw.githubusercontent.com/ohler/ert/c619b56c5bc6a866e33787489545b87d79973205/lisp/emacs-lisp/ert.el';
+ fi
+script:
+ - $EMACS -Q -batch --eval '(setq byte-compile-error-on-warn t)' -f batch-byte-compile rainbow-delimiters.el
+ - $EMACS -Q -batch -l rainbow-delimiters-test.el -f ert-run-tests-batch-and-exit
+notifications:
+ email: false
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3f1fb58
--- /dev/null
+++ b/README.md
@@ -0,0 +1,75 @@
+[![MELPA](http://melpa.org/packages/rainbow-delimiters-badge.svg)](http://melpa.org/#/rainbow-delimiters)
+[![MELPA Stable](http://stable.melpa.org/packages/rainbow-delimiters-badge.svg)](http://stable.melpa.org/#/rainbow-delimiters)
+[![Build status](https://travis-ci.org/Fanael/rainbow-delimiters.svg?branch=master)](https://travis-ci.org/Fanael/rainbow-delimiters)
+
+# rainbow-delimiters
+
+`rainbow-delimiters` is a "rainbow parentheses"-like mode which highlights
+delimiters such as parentheses, brackets or braces according to their depth.
+Each successive level is highlighted in a different color. This makes it easy to
+spot matching delimiters, orient yourself in the code, and tell which statements
+are at a given depth.
+
+Great care has been taken to make this mode fast. You shouldn't see any change
+in scrolling or editing speed when it's on even when working in delimiter-rich
+languages like Clojure or Emacs Lisp. It can be used with any language.
+
+You can customize the colors `rainbow-delimiters` uses. The default colors are
+intentionally subtle; they are unobtrusive enough to make the mode worth looking
+at even if you usually don't like rainbow parentheses modes. A number of major
+color themes such as Zenburn and Solarized have added their own faces for the
+mode.
+
+This is the official github repository for `rainbow-delimiters`.
+
+The latest **release** of `rainbow-delimiters` is always found at
+https://github.com/Fanael/rainbow-delimiters/tree/master
+
+## Installation
+
+The recommended way is to use [MELPA](http://melpa.org/) or
+[MELPA Stable](http://stable.melpa.org/). If either is in your
+`package-archives`, do
+
+ M-x package-install RET rainbow-delimiters RET
+
+Otherwise, open `rainbow-delimiters.el` in Emacs and use
+
+ M-x package-install-from-buffer
+
+Any other methods of installation are unsupported.
+
+## Usage
+
+To toggle the mode in the current buffer:
+
+ M-x rainbow-delimiters-mode
+
+To start the mode automatically in `foo-mode`, add the following to your init
+file:
+
+ (add-hook 'foo-mode-hook #'rainbow-delimiters-mode)
+
+To start the mode automatically in most programming modes (Emacs 24 and above):
+
+ (add-hook 'prog-mode-hook #'rainbow-delimiters-mode)
+
+### Global mode
+
+There's no `global-rainbow-delimiters-mode` anymore. It used to exist, but it
+was impossible to keep it from breaking some major modes. It's *strongly
+recommended* to use major mode hooks instead, as shown above. There's nothing
+stopping you from defining `global-rainbow-delimiters-mode` yourself, but if it
+breaks something, you're on your own.
+
+## Customization
+
+To customize various options, including the color theme:
+
+ M-x customize-group rainbow-delimiters
+
+You can specify custom colors by customizing following faces:
+ * Faces take the form `rainbow-delimiters-depth-N-face`, with N being the
+ depth. Depth begins at 1, the outermost color. Faces exist for depths 1-9.
+ * The unmatched delimiter face: `rainbow-delimiters-unmatched-face`.
+ * The mismatched delimiter face: `rainbow-delimiters-mismatched-face`.
diff --git a/rainbow-delimiters-test.el b/rainbow-delimiters-test.el
new file mode 100644
index 0000000..4683a9e
--- /dev/null
+++ b/rainbow-delimiters-test.el
@@ -0,0 +1,286 @@
+;;; rainbow-delimiters-test.el --- rainbow-delimiters test suite
+
+;; Author: Fanael Linithien <fanael4@gmail.com>
+;; URL: https://github.com/Fanael/rainbow-delimiters
+
+;; This file is NOT part of GNU Emacs.
+
+;; Copyright (c) 2014-2015, Fanael Linithien
+;; All rights reserved.
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following conditions are
+;; met:
+;;
+;; * Redistributions of source code must retain the above copyright
+;; notice, this list of conditions and the following disclaimer.
+;; * Redistributions in binary form must reproduce the above copyright
+;; notice, this list of conditions and the following disclaimer in the
+;; documentation and/or other materials provided with the distribution.
+;;
+;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+;; IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+;; TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+;; PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+;; OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+;; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+;; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+;; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+;; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+;;; Commentary:
+
+;; `rainbow-delimiters' test suite.
+
+;;; Code:
+
+(unless noninteractive
+ (error "This file should only be used noninteractively"))
+
+(push (file-name-directory load-file-name) load-path)
+(setq font-lock-verbose nil)
+
+(require 'rainbow-delimiters)
+(require 'ert)
+
+(defmacro with-temp-buffer-in-mode (mode &rest body)
+ (declare (indent defun) (debug t))
+ `(with-temp-buffer
+ (funcall ,mode)
+ (font-lock-mode)
+ (rainbow-delimiters-mode)
+ ,@body))
+
+(defmacro with-string (strdecl &rest body)
+ (declare (indent defun) (debug t))
+ `(let ((,(car strdecl) ,(cadr strdecl)))
+ (insert ,(car strdecl))
+ (fontify-buffer)
+ ,@body))
+
+(defun fontify-buffer ()
+ (if (fboundp 'font-lock-ensure)
+ (font-lock-ensure)
+ (with-no-warnings (font-lock-fontify-buffer))))
+
+(defun fontify-without-rainbow-delimiters (mode text)
+ (with-temp-buffer
+ (funcall mode)
+ (insert text)
+ (fontify-buffer)
+ (buffer-string)))
+
+(defun should-do-nothing (mode str)
+ (with-temp-buffer-in-mode mode
+ (with-string (str str)
+ (should (ert-equal-including-properties
+ (buffer-string)
+ (fontify-without-rainbow-delimiters mode str))))))
+
+(ert-deftest can-enable-mode ()
+ (with-temp-buffer
+ (rainbow-delimiters-mode 1)
+ (should rainbow-delimiters-mode)))
+
+(ert-deftest can-disable-mode ()
+ (with-temp-buffer
+ (rainbow-delimiters-mode 1)
+ (rainbow-delimiters-mode 0)
+ (should-not rainbow-delimiters-mode)))
+
+(defmacro highlights-matching-delim-test (name opening closing)
+ `(ert-deftest ,(intern (format "highlights-matching-%s" name)) ()
+ (with-temp-buffer-in-mode 'text-mode
+ (with-string (str ,(format "%cfoo%c" opening closing))
+ (should (ert-equal-including-properties
+ (buffer-string)
+ (progn
+ (add-text-properties 0 1 '(face (rainbow-delimiters-depth-1-face)) str)
+ (add-text-properties 4 5 '(face (rainbow-delimiters-depth-1-face)) str)
+ str)))))))
+
+(highlights-matching-delim-test "parens" ?\( ?\))
+(highlights-matching-delim-test "brackets" ?\[ ?\])
+(highlights-matching-delim-test "braces" ?\{ ?\})
+
+(defmacro highlights-matching-nested-delim-test (name opening closing)
+ `(ert-deftest ,(intern (format "highlights-nested-matching-%s" name)) ()
+ (with-temp-buffer-in-mode 'text-mode
+ (with-string (str ,(format "%sfoo%s" (make-string 4 opening) (make-string 4 closing)))
+ (should (ert-equal-including-properties
+ (buffer-string)
+ (progn
+ (add-text-properties 0 1 '(face (rainbow-delimiters-depth-1-face)) str)
+ (add-text-properties 1 2 '(face (rainbow-delimiters-depth-2-face)) str)
+ (add-text-properties 2 3 '(face (rainbow-delimiters-depth-3-face)) str)
+ (add-text-properties 3 4 '(face (rainbow-delimiters-depth-4-face)) str)
+ (add-text-properties 7 8 '(face (rainbow-delimiters-depth-4-face)) str)
+ (add-text-properties 8 9 '(face (rainbow-delimiters-depth-3-face)) str)
+ (add-text-properties 9 10 '(face (rainbow-delimiters-depth-2-face)) str)
+ (add-text-properties 10 11 '(face (rainbow-delimiters-depth-1-face)) str)
+ str)))))))
+
+(highlights-matching-nested-delim-test "parens" ?\( ?\))
+(highlights-matching-nested-delim-test "brackets" ?\[ ?\])
+(highlights-matching-nested-delim-test "braces" ?\{ ?\})
+
+(ert-deftest highlights-mixed-matching-delimiters ()
+ (with-temp-buffer-in-mode 'text-mode
+ (with-string (str "([{(foo)}])")
+ (should (ert-equal-including-properties
+ (buffer-string)
+ #("([{(foo)}])"
+ 0 1 (face (rainbow-delimiters-depth-1-face))
+ 1 2 (face (rainbow-delimiters-depth-2-face))
+ 2 3 (face (rainbow-delimiters-depth-3-face))
+ 3 4 (face (rainbow-delimiters-depth-4-face))
+ 7 8 (face (rainbow-delimiters-depth-4-face))
+ 8 9 (face (rainbow-delimiters-depth-3-face))
+ 9 10 (face (rainbow-delimiters-depth-2-face))
+ 10 11 (face (rainbow-delimiters-depth-1-face))))))))
+
+(ert-deftest highlights-all-delimiters ()
+ (with-temp-buffer-in-mode 'c++-mode
+ (with-string (str "foo<int> x;")
+ (should (ert-equal-including-properties
+ (progn
+ (remove-list-of-text-properties
+ (point-min) (point-max) '(category c-type syntax-table))
+ (buffer-string))
+ #("foo<int> x;"
+ 0 3 (face font-lock-type-face)
+ 3 4 (face (rainbow-delimiters-depth-1-face))
+ 4 7 (face font-lock-type-face)
+ 7 8 (face (rainbow-delimiters-depth-1-face))
+ 9 10 (face font-lock-variable-name-face)))))))
+
+(ert-deftest doesnt-higlight-nondelimiters-1 ()
+ (should-do-nothing 'text-mode "foo"))
+
+(ert-deftest doesnt-higlight-nondelimiters-2 ()
+ (should-do-nothing 'emacs-lisp-mode "{foo}"))
+
+(ert-deftest doesnt-highlight-in-comments-1 ()
+ (should-do-nothing 'emacs-lisp-mode "; ()[]"))
+
+(ert-deftest doesnt-highlight-in-comments-2 ()
+ (should-do-nothing 'pascal-mode "(* foo *)"))
+
+(ert-deftest doesnt-highlight-in-strings ()
+ (should-do-nothing 'emacs-lisp-mode "\"()\""))
+
+(ert-deftest highlights-unmatched ()
+ (with-temp-buffer-in-mode 'emacs-lisp-mode
+ (with-string (str ")")
+ (should (ert-equal-including-properties
+ (buffer-string)
+ #(")"
+ 0 1 (face (rainbow-delimiters-unmatched-face))))))))
+
+(ert-deftest highlights-mismatched ()
+ (with-temp-buffer-in-mode 'emacs-lisp-mode
+ (with-string (str "(]")
+ (should (ert-equal-including-properties
+ (buffer-string)
+ #("(]"
+ 0 1 (face (rainbow-delimiters-depth-1-face))
+ 1 2 (face (rainbow-delimiters-mismatched-face))))))))
+
+(ert-deftest doesnt-highlight-escaped-delimiters ()
+ (with-temp-buffer-in-mode 'emacs-lisp-mode
+ (with-string (str "(bar ?\\( (foo?))")
+ (should (ert-equal-including-properties
+ (buffer-string)
+ #("(bar ?\\( (foo?))"
+ 0 1
+ (face (rainbow-delimiters-depth-1-face))
+ 9 10
+ (face (rainbow-delimiters-depth-2-face))
+ 14 15
+ (face (rainbow-delimiters-depth-2-face))
+ 15 16
+ (face (rainbow-delimiters-depth-1-face))))))))
+
+(ert-deftest cycles-faces ()
+ (let ((rainbow-delimiters-max-face-count 2))
+ (with-temp-buffer-in-mode 'text-mode
+ (with-string (str "(((())))")
+ (should (ert-equal-including-properties
+ (buffer-string)
+ #("(((())))"
+ 0 1 (face (rainbow-delimiters-depth-1-face))
+ 1 2 (face (rainbow-delimiters-depth-2-face))
+ 2 3 (face (rainbow-delimiters-depth-1-face))
+ 3 4 (face (rainbow-delimiters-depth-2-face))
+ 4 5 (face (rainbow-delimiters-depth-2-face))
+ 5 6 (face (rainbow-delimiters-depth-1-face))
+ 6 7 (face (rainbow-delimiters-depth-2-face))
+ 7 8 (face (rainbow-delimiters-depth-1-face)))))))))
+
+(ert-deftest doesnt-cycle-outermost-only-faces ()
+ (let ((rainbow-delimiters-outermost-only-face-count 2)
+ (rainbow-delimiters-max-face-count 3))
+ (with-temp-buffer-in-mode 'text-mode
+ (with-string (str "(((())))")
+ (should (ert-equal-including-properties
+ (buffer-string)
+ #("(((())))"
+ 0 1 (face (rainbow-delimiters-depth-1-face))
+ 1 2 (face (rainbow-delimiters-depth-2-face))
+ 2 3 (face (rainbow-delimiters-depth-3-face))
+ 3 4 (face (rainbow-delimiters-depth-3-face))
+ 4 5 (face (rainbow-delimiters-depth-3-face))
+ 5 6 (face (rainbow-delimiters-depth-3-face))
+ 6 7 (face (rainbow-delimiters-depth-2-face))
+ 7 8 (face (rainbow-delimiters-depth-1-face)))))))))
+
+(ert-deftest highlights-already-highlighted ()
+ (with-temp-buffer-in-mode 'diff-mode
+ (with-string (str "+ foo ()\n")
+ (should (ert-equal-including-properties
+ (buffer-string)
+ #("+ foo ()\n"
+ 0 1 (face diff-indicator-added)
+ 1 6 (face diff-added)
+ 6 7 (face (rainbow-delimiters-depth-1-face diff-added))
+ 7 8 (face (rainbow-delimiters-depth-1-face diff-added))
+ 8 9 (face diff-added)))))))
+
+(ert-deftest can-customize-face-picker ()
+ (let ((rainbow-delimiters-pick-face-function
+ (lambda (_depth _match _loc)
+ 'font-lock-keyword-face)))
+ (with-temp-buffer-in-mode 'emacs-lisp-mode
+ (with-string (str "(())")
+ (should (ert-equal-including-properties
+ (buffer-string)
+ #("(())"
+ 0 1 (face (font-lock-keyword-face))
+ 1 2 (face (font-lock-keyword-face))
+ 2 3 (face (font-lock-keyword-face))
+ 3 4 (face (font-lock-keyword-face)))))))))
+
+(ert-deftest face-picker-can-disable-highlighting ()
+ (let ((rainbow-delimiters-pick-face-function
+ (lambda (depth match loc)
+ (unless (memq (char-after loc) '(?\( ?\)))
+ (rainbow-delimiters-default-pick-face depth match loc)))))
+ (should-do-nothing 'text-mode "(((())))")))
+
+(ert-deftest delimiters-disabled-by-face-picker-contribute-to-depth ()
+ (let ((rainbow-delimiters-pick-face-function
+ (lambda (depth match loc)
+ (unless (memq (char-after loc) '(?\( ?\)))
+ (rainbow-delimiters-default-pick-face depth match loc)))))
+ (with-temp-buffer-in-mode 'text-mode
+ (with-string (str "([])")
+ (should (ert-equal-including-properties
+ (buffer-string)
+ #("([])"
+ 1 2 (face (rainbow-delimiters-depth-2-face))
+ 2 3 (face (rainbow-delimiters-depth-2-face)))))))))
+
+(provide 'rainbow-delimiters-test)
+;;; rainbow-delimiters-test.el ends here
diff --git a/rainbow-delimiters.el b/rainbow-delimiters.el
new file mode 100644
index 0000000..5f30e7c
--- /dev/null
+++ b/rainbow-delimiters.el
@@ -0,0 +1,292 @@
+;;; rainbow-delimiters.el --- Highlight brackets according to their depth -*- lexical-binding: t -*-
+
+;; Copyright (C)
+;; 2010-2013 Jeremy Rayman
+;; 2013-2016 Fanael Linithien
+;; Author: Jeremy Rayman <opensource@jeremyrayman.com>
+;; Fanael Linithien <fanael4@gmail.com>
+;; Maintainer: Fanael Linithien <fanael4@gmail.com>
+;; Created: 2010-09-02
+;; Version: 2.1.3
+;; Keywords: faces, convenience, lisp, tools
+;; Homepage: https://github.com/Fanael/rainbow-delimiters
+
+;; Note: despite `lexical-binding', there's no Emacs 24 dependency.
+;; This is merely an optimization for Emacs 24+, the code is supposed to work
+;; with *both* dynamic and lexical binding.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Installation:
+
+;; The recommended way is to use MELPA (http://melpa.org/) or MELPA Stable
+;; (http://stable.melpa.org/). If either is in your `package-archives', do
+;; M-x package-install RET rainbow-delimiters RET
+;; Otherwise, open `rainbow-delimiters.el' in Emacs and use
+;; M-x package-install-from-buffer
+;; Any other methods of installation are unsupported.
+
+;;; Commentary:
+;;
+;; Rainbow-delimiters is a "rainbow parentheses"-like mode which highlights
+;; parentheses, brackets, and braces according to their depth. Each
+;; successive level is highlighted in a different color. This makes it easy
+;; to spot matching delimiters, orient yourself in the code, and tell which
+;; statements are at a given level.
+;;
+;; Great care has been taken to make this mode fast. You shouldn't see
+;; any discernible change in scrolling or editing speed while using it,
+;; even in delimiter-rich languages like Clojure, Lisp, and Scheme.
+;;
+;; Usage:
+;;
+;; To toggle the mode in the current buffer:
+;; M-x rainbow-delimiters-mode
+;; To start the mode automatically in `foo-mode', add the following to your init
+;; file:
+;; (add-hook 'foo-mode-hook #'rainbow-delimiters-mode)
+;; To start the mode automatically in most programming modes (Emacs 24 and
+;; above):
+;; (add-hook 'prog-mode-hook #'rainbow-delimiters-mode)
+;;
+;; Customization:
+;;
+;; To customize various options, including the color theme:
+;; M-x customize-group rainbow-delimiters
+;;
+;; You can specify custom colors by customizing following faces:
+;; - Faces take the form `rainbow-delimiters-depth-N-face', with N being the
+;; depth. Depth begins at 1, the outermost color. Faces exist for depths 1-9.
+;; - The unmatched delimiter face: `rainbow-delimiters-unmatched-face'.
+;; - The mismatched delimiter face: `rainbow-delimiters-mismatched-face'.
+
+;;; Code:
+
+(defgroup rainbow-delimiters nil
+ "Highlight nested parentheses, brackets, and braces according to their depth."
+ :prefix "rainbow-delimiters-"
+ :link '(url-link :tag "Website for rainbow-delimiters"
+ "https://github.com/Fanael/rainbow-delimiters")
+ :group 'applications)
+
+(defgroup rainbow-delimiters-faces nil
+ "Faces for successively nested pairs of delimiters.
+
+When depth exceeds innermost defined face, colors cycle back through."
+ :group 'rainbow-delimiters
+ :group 'faces
+ :link '(custom-group-link "rainbow-delimiters")
+ :prefix "rainbow-delimiters-")
+
+(defcustom rainbow-delimiters-pick-face-function
+ #'rainbow-delimiters-default-pick-face
+ "The function used to pick a face used to highlight a delimiter.
+The function should take three arguments (DEPTH MATCH LOC), where:
+ - DEPTH is the delimiter depth; when zero or negative, it's an unmatched
+ delimiter.
+ - MATCH is nil iff the delimiter is a mismatched closing delimiter.
+ - LOC is the location of the delimiter.
+The function should return a value suitable to use as a value of the `face' text
+property, or nil, in which case the delimiter is not highlighted.
+The function should not move the point or mark or change the match data."
+ :tag "Pick face function"
+ :type 'function
+ :group 'rainbow-delimiters)
+
+(defface rainbow-delimiters-unmatched-face
+ '((((background light)) (:foreground "#88090B"))
+ (((background dark)) (:foreground "#88090B")))
+ "Face to highlight unmatched closing delimiters in."
+ :group 'rainbow-delimiters-faces)
+
+(defface rainbow-delimiters-mismatched-face
+ '((t :inherit rainbow-delimiters-unmatched-face))
+ "Face to highlight mismatched closing delimiters in."
+ :group 'rainbow-delimiters-faces)
+
+(eval-when-compile
+ (defmacro rainbow-delimiters--define-depth-faces ()
+ (let ((faces '())
+ (light-colors ["#707183" "#7388d6" "#909183" "#709870" "#907373"
+ "#6276ba" "#858580" "#80a880" "#887070"])
+ (dark-colors ["grey55" "#93a8c6" "#b0b1a3" "#97b098" "#aebed8"
+ "#b0b0b3" "#90a890" "#a2b6da" "#9cb6ad"]))
+ (dotimes (i 9)
+ (push `(defface ,(intern (format "rainbow-delimiters-depth-%d-face" (1+ i)))
+ '((((class color) (background light)) :foreground ,(aref light-colors i))
+ (((class color) (background dark)) :foreground ,(aref dark-colors i)))
+ ,(format "Nested delimiter face, depth %d." (1+ i))
+ :group 'rainbow-delimiters-faces)
+ faces))
+ `(progn ,@faces))))
+(rainbow-delimiters--define-depth-faces)
+
+(defcustom rainbow-delimiters-max-face-count 9
+ "Number of faces defined for highlighting delimiter levels.
+
+Determines depth at which to cycle through faces again.
+
+It's safe to change this variable provided that for all integers from 1 to the
+new value inclusive, a face `rainbow-delimiters-depth-N-face' is defined."
+ :type 'integer
+ :group 'rainbow-delimiters)
+
+(defcustom rainbow-delimiters-outermost-only-face-count 0
+ "Number of faces to be used only for N outermost delimiter levels.
+
+This should be smaller than `rainbow-delimiters-max-face-count'."
+ :type 'integer
+ :group 'rainbow-delimiters)
+
+
+(defun rainbow-delimiters-default-pick-face (depth match _loc)
+ "Return a face name appropriate for nesting depth DEPTH.
+DEPTH and MATCH are as in `rainbow-delimiters-pick-face-function'.
+
+The returned value is either `rainbow-delimiters-unmatched-face',
+`rainbow-delimiters-mismatched-face', or one of the
+`rainbow-delimiters-depth-N-face' faces, obeying
+`rainbow-delimiters-max-face-count' and
+`rainbow-delimiters-outermost-only-face-count'."
+ (cond
+ ((<= depth 0)
+ 'rainbow-delimiters-unmatched-face)
+ ((not match)
+ 'rainbow-delimiters-mismatched-face)
+ (t
+ (intern-soft
+ (concat "rainbow-delimiters-depth-"
+ (number-to-string
+ (if (<= depth rainbow-delimiters-max-face-count)
+ ;; Our nesting depth has a face defined for it.
+ depth
+ ;; Deeper than # of defined faces; cycle back through to
+ ;; `rainbow-delimiters-outermost-only-face-count' + 1.
+ ;; Return face # that corresponds to current nesting level.
+ (+ 1 rainbow-delimiters-outermost-only-face-count
+ (mod (- depth rainbow-delimiters-max-face-count 1)
+ (- rainbow-delimiters-max-face-count
+ rainbow-delimiters-outermost-only-face-count)))))
+ "-face")))))
+
+(defun rainbow-delimiters--apply-color (loc depth match)
+ "Highlight a single delimiter at LOC according to DEPTH.
+
+LOC is the location of the character to add text properties to.
+DEPTH is the nested depth at LOC, which determines the face to use.
+MATCH is nil iff it's a mismatched closing delimiter."
+ (let ((face (funcall rainbow-delimiters-pick-face-function depth match loc)))
+ (when face
+ (font-lock-prepend-text-property loc (1+ loc) 'face face))))
+
+(defun rainbow-delimiters--char-ineligible-p (loc ppss delim-syntax-code)
+ "Return t if char at LOC should not be highlighted.
+PPSS is the `parse-partial-sexp' state at LOC.
+DELIM-SYNTAX-CODE is the `car' of a raw syntax descriptor at LOC.
+
+Returns t if char at loc meets one of the following conditions:
+- Inside a string.
+- Inside a comment.
+- Is an escaped char, e.g. ?\)"
+ (or
+ (nth 3 ppss) ; inside string?
+ (nth 4 ppss) ; inside comment?
+ (nth 5 ppss) ; escaped according to the syntax table?
+ ;; Note: no need to consider single-char openers, they're already handled
+ ;; by looking at ppss.
+ (cond
+ ;; Two character opener, LOC at the first character?
+ ((/= 0 (logand #x10000 delim-syntax-code))
+ (/= 0 (logand #x20000 (or (car (syntax-after (1+ loc))) 0))))
+ ;; Two character opener, LOC at the second character?
+ ((/= 0 (logand #x20000 delim-syntax-code))
+ (/= 0 (logand #x10000 (or (car (syntax-after (1- loc))) 0))))
+ (t
+ nil))))
+
+;; Main function called by font-lock.
+(defun rainbow-delimiters--propertize (end)
+ "Highlight delimiters in region between point and END.
+
+Used by font-lock for dynamic highlighting."
+ (let* ((last-ppss-pos (point))
+ (ppss (syntax-ppss)))
+ (while (> end (progn (skip-syntax-forward "^()" end)
+ (point)))
+ (let* ((delim-pos (point))
+ (delim-syntax (syntax-after delim-pos)))
+ (setq ppss (parse-partial-sexp last-ppss-pos delim-pos nil nil ppss))
+ (setq last-ppss-pos delim-pos)
+ ;; `skip-syntax-forward' leaves the point at the delimiter, move past
+ ;; it.
+ (forward-char)
+ (let ((delim-syntax-code (car delim-syntax)))
+ (cond
+ ((rainbow-delimiters--char-ineligible-p delim-pos ppss delim-syntax-code)
+ nil)
+ ((= 4 (logand #xFFFF delim-syntax-code))
+ ;; The (1+ ...) is needed because `parse-partial-sexp' returns the
+ ;; depth at the opening delimiter, not in the block being started.
+ (rainbow-delimiters--apply-color delim-pos (1+ (nth 0 ppss)) t))
+ (t
+ ;; Not an opening delimiter, so it's a closing delimiter.
+ (let ((matches-p (eq (cdr delim-syntax) (char-after (nth 1 ppss)))))
+ (rainbow-delimiters--apply-color delim-pos (nth 0 ppss) matches-p))))))))
+ ;; We already fontified the delimiters, tell font-lock there's nothing more
+ ;; to do.
+ nil)
+
+;; NB: no face defined here because we apply the faces ourselves instead of
+;; leaving that to font-lock.
+(defconst rainbow-delimiters--font-lock-keywords
+ '(rainbow-delimiters--propertize))
+
+;;;###autoload
+(define-minor-mode rainbow-delimiters-mode
+ "Highlight nested parentheses, brackets, and braces according to their depth."
+ nil "" nil ; No modeline lighter - it's already obvious when the mode is on.
+ (font-lock-remove-keywords nil rainbow-delimiters--font-lock-keywords)
+ (when rainbow-delimiters-mode
+ (font-lock-add-keywords nil rainbow-delimiters--font-lock-keywords 'append)
+ (set (make-local-variable 'jit-lock-contextually) t)
+ (when (or (bound-and-true-p syntax-begin-function)
+ (bound-and-true-p font-lock-beginning-of-syntax-function))
+ ;; We're going to modify `syntax-begin-function', so flush the cache to
+ ;; avoid getting cached values that used the old value.
+ (syntax-ppss-flush-cache 0))
+ ;; `syntax-begin-function' may break the assumption we rely on that
+ ;; `syntax-ppss' is exactly equivalent to `parse-partial-sexp' from
+ ;; `point-min'. Just don't use it, the performance hit should be negligible.
+ (when (boundp 'syntax-begin-function)
+ (set (make-local-variable 'syntax-begin-function) nil))
+ ;; Obsolete equivalent of `syntax-begin-function'.
+ (when (boundp 'font-lock-beginning-of-syntax-function)
+ (set (make-local-variable 'font-lock-beginning-of-syntax-function) nil)))
+ (when font-lock-mode
+ (if (fboundp 'font-lock-flush)
+ (font-lock-flush)
+ (with-no-warnings (font-lock-fontify-buffer)))))
+
+;;;###autoload
+(defun rainbow-delimiters-mode-enable ()
+ "Enable `rainbow-delimiters-mode'."
+ (rainbow-delimiters-mode 1))
+
+;;;###autoload
+(defun rainbow-delimiters-mode-disable ()
+ "Disable `rainbow-delimiters-mode'."
+ (rainbow-delimiters-mode 0))
+
+(provide 'rainbow-delimiters)
+;;; rainbow-delimiters.el ends here