Skip to content
Newer
Older
100644 232 lines (187 sloc) 8.94 KB
33215cd @ghoseb Emacs config Redux
authored Sep 12, 2011
1 ;;; rainbow-delimiters.el --- Colorize nested delimiters: () [] {}
2
3 ;; Copyright (C) 2010 Jeremy Rayman
4 ;; Copyright (C) 2009 Mark Triggs
5
6 ;; Author: Mark Triggs <mst@dishevelled.net>, additions by
7 ;; Jeremy Rayman, and help from Alex Osborne <ato@meshy.org>
8
9 ;; This program is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
13
14 ;; This program is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
21
22 ;;; Installation:
23
24 ;; Place rainbow-delimiters.el on your emacs load-path.
25
26 ;; (require 'rainbow-delimiters)
27 ;; M-x rainbow-delimiters-mode
28
29 ;; NOTE: The colors in this file were picked on a wide-gamut display,
30 ;; meaning they will look terrible on a standard-gamut display. You
31 ;; will want to change the colors to subtler ones of your liking.
32 ;; Change the variable `*rainbow-delimiters-faces*'
33
34 ;;; Commentary:
35
36 ;; This is a "rainbow parentheses" mode which includes support for
37 ;; parens "()", brackets "[]", and braces "{}". It conveys nesting
38 ;; depth by using a new color from *rainbow-delimiters-faces* for each
39 ;; for each nested level. It correctly colorizes statements of the
40 ;; same depth - if two statements are the same level, they will be the
41 ;; same color. The user can change the variable
42 ;; `*rainbow-delimiter-faces*' to set their own color choices.
43 ;; Emacs customize dialog support is forthcoming.
44
45 ;; Each set of delimiters "()[]{}" is colored independently from one
46 ;; another. This means that color chosen is based on the nesting depth
47 ;; _solely of that type of delimiter_. Parens, brackets, and braces
48 ;; all maintain their colors depth, meaning even a bracket nested
49 ;; within several levels of parentheses will start with the topmost
50 ;; (lightest) color, and each nested bracket will then move to the
51 ;; next color.
52
53 ;; Thanks to Mark Triggs and Alex Osborne, who did the heavy lifting
54 ;; in this code. They made proper use of overlays and the mode
55 ;; colorizes the buffer fast in most scenarios. This is a fork of
56 ;; their work to add several new features. The original
57 ;; rainbow-parens.el written by these authors is available at:
58 ;; http://dishevelled.net/elisp/rainbow-parens.el
59
60 ;; Bug reports about this code should be sent to Jeremy Rayman
61 ;; <jeremy.rayman.public@gmail.com>. Please do not send bug reports to
62 ;; the maintainers of rainbow-parens.el unless the bug is present in
63 ;; their original version. Thank you.
64
65 ;;; TODO:
66 ;; - Add customize-interface for changing delimiter colors
67 ;; - Use a separate *rainbow-______-face* for each type
68 ;; of delimiter to allow independent color choices for each one
69 ;; - Improve performance on very delimiter-heavy code (performance is
70 ;; already good for most files including most lisp files)
71 ;; - Add <> support with a toggle to colorize nested tags (XML, HTML)
72 ;; vs colorizing nested angle brackets like we do with the other
73 ;; types of delimiter.
74
75 ;;; Code:
76
77 (require 'paredit)
78 (require 'cl)
79
80 ;;; TODO: Customize interface:
81 ;; (defgroup rainbow-delimiters nil
82 ;; "Color each nested set of delimiters differently to visually communicate nesting level.") ; should rainbow-delimiters belong to a :group?
83
84 (defun rainbow-delimiters-face-from-colour (colour)
85 (let ((face (make-face (intern (concat "rainbow-delimiters-" colour "-face")))))
86 (set-face-foreground face colour)
87 face))
88
89 (defvar *rainbow-delimiters-faces*
90 `[,(rainbow-delimiters-face-from-colour "dark gray")
91 ,(rainbow-delimiters-face-from-colour "green")
92 ,(rainbow-delimiters-face-from-colour "gold")
93 ,(rainbow-delimiters-face-from-colour "turquoise")
94 ,(rainbow-delimiters-face-from-colour "orange")
95 ,(rainbow-delimiters-face-from-colour "slate blue")
96 ,(rainbow-delimiters-face-from-colour "yellow")
97 ,(rainbow-delimiters-face-from-colour "light blue")
98 ,(rainbow-delimiters-face-from-colour "#7f7f7f")
99 ,(rainbow-delimiters-face-from-colour "light gray")
100 ])
101
102
103 (defun rainbow-delimiters-this-paren-nesting ()
104 (let ((point (point))
105 (depth 0))
106 (while (ignore-errors
107 (setq point (scan-lists point -1 1)))
108 (when (= (char-after point) 40)
109 (setq depth (1+ depth))))
110 depth))
111
112 (defun rainbow-delimiters-this-bracket-nesting ()
113 (let ((point (point))
114 (depth 0))
115 (while (ignore-errors
116 (setq point (scan-lists point -1 1)))
117 (when (= (char-after point) 91)
118 (setq depth (1+ depth))))
119 depth))
120
121 (defun rainbow-delimiters-this-brace-nesting ()
122 (let ((point (point))
123 (depth 0))
124 (while (ignore-errors
125 (setq point (scan-lists point -1 1)))
126 (when (= (char-after point) 123)
127 (setq depth (1+ depth))))
128 depth))
129
130
131 (defun rainbow-delimiters-face-for-depth (n)
132 (aref *rainbow-delimiters-faces*
133 (mod n (length *rainbow-delimiters-faces*))))
134
135
136 (defun rainbow-delimiters-apply (point face)
137 (let* ((os (overlays-at point))
138 (o (or (some (lambda (o)
139 (and (eq (overlay-get o 'type) 'rainbow-delimiter)
140 o))
141 os)
142 (make-overlay point (1+ point) nil t nil))))
143 (overlay-put o 'type 'rainbow-delimiter)
144 (overlay-put o 'face face)
145 (overlay-put o 'evaporate t)))
146
147
148
149 (defun rainbow-delimiters-boring-delimiter-p ()
150 (or (paredit-in-string-p)
151 (paredit-in-comment-p)))
152
153
154 (defun rainbow-delimiters-skip-boring (bound)
155 (while (and (< (point) bound)
156 (rainbow-delimiters-boring-delimiter-p))
157 (forward-char 1)))
158
159
160 (defun rainbow-delimiters-fontify (beg end)
161 (save-excursion
162 (goto-char beg)
163 (rainbow-delimiters-skip-boring end)
164 (let* ((paren-depth (rainbow-delimiters-this-paren-nesting))
165 (bracket-depth (rainbow-delimiters-this-bracket-nesting))
166 (brace-depth (rainbow-delimiters-this-brace-nesting)))
167 (while (< (point) end)
168 (rainbow-delimiters-skip-boring end)
169 (cond ((= (char-after (point)) 91) ; [
170 (rainbow-delimiters-apply (point)
171 (rainbow-delimiters-face-for-depth bracket-depth))
172 (setq bracket-depth (1+ bracket-depth)))
173 ((= (char-after (point)) 93) ; ]
174 (setq bracket-depth (1- bracket-depth))
175 (rainbow-delimiters-apply (point)
176 (rainbow-delimiters-face-for-depth bracket-depth)))
177 ((= (char-after (point)) 123) ; {
178 (rainbow-delimiters-apply (point)
179 (rainbow-delimiters-face-for-depth brace-depth))
180 (setq brace-depth (1+ brace-depth)))
181 ((= (char-after (point)) 125) ; }
182 (setq brace-depth (1- brace-depth))
183 (rainbow-delimiters-apply (point)
184 (rainbow-delimiters-face-for-depth brace-depth)))
185 ; < 60
186 ; > 62
187 )
188 (forward-char 1)))))
189
190
191 (defun rainbow-delimiters-unfontify (beg end)
192 (mapc #'(lambda (o)
193 (when (eq (overlay-get o 'type) 'rainbow-delimiter)
194 (delete-overlay o)))
195 (overlays-in beg end)))
196
197
198 (define-minor-mode rainbow-delimiters-mode
199 "Color each nested set of delimiters differently to visually communicate nesting level. Supports (), [], {}."
200
201 nil " R" nil
202 (cond ((not rainbow-delimiters-mode)
203 (jit-lock-unregister 'rainbow-delimiters-fontify)
204 (rainbow-delimiters-unfontify (point-min) (point-max)))
205 (t (jit-lock-register 'rainbow-delimiters-fontify))))
206
207
208 (provide 'rainbow-delimiters)
209
210 ;;; Other possible delimiter colors to use: (wide-gamut)
211 ;; ,(rainbow-delimiters-face-from-colour "#7f7f7f")
212 ;; ,(rainbow-delimiters-face-from-colour "#7f7f91")
213 ;; ,(rainbow-delimiters-face-from-colour "#7f7fa1")
214 ;; ,(rainbow-delimiters-face-from-colour "#95aabc")
215 ;; ,(rainbow-delimiters-face-from-colour "#9d9d9d")
216 ;; ,(rainbow-delimiters-face-from-colour "#9d9d9d")
217 ;; ,(rainbow-delimiters-face-from-colour "#8d929b")
218 ;; ,(rainbow-delimiters-face-from-colour "#7f8f9d")
219 ;; ,(rainbow-delimiters-face-from-colour "#73818c")
220 ;; ,(rainbow-delimiters-face-from-colour "#91b3d0")
221 ;; ,(rainbow-delimiters-face-from-colour "#91b3d0")
222 ;; ,(rainbow-delimiters-face-from-colour "#91b3d0")
223 ;; ,(rainbow-delimiters-face-from-colour "#7ea7c9")
224 ;; ,(rainbow-delimiters-face-from-colour "#6b9ac2")
225 ;; ,(rainbow-delimiters-face-from-colour "gray100")
226 ;; ,(rainbow-delimiters-face-from-colour "gray85")
227 ;; ,(rainbow-delimiters-face-from-colour "gray70")
228 ;; ,(rainbow-delimiters-face-from-colour "#6093be")
229 ;; ,(rainbow-delimiters-face-from-colour "#588dba")
230
231 ;;; rainbow-delimiters.el ends here
Something went wrong with that request. Please try again.