├── README.md
├── doc
├── demo.el
├── demo.png
└── lisp-extra-font-lock-screenshot-setup.el
├── lisp-extra-font-lock.el
└── test
├── files
├── basics.el
├── basics.el.faceup
├── demo.el
├── demo.el.faceup
├── exclude.el
├── exclude.el.faceup
├── hash-quote.el
└── hash-quote.el.faceup
├── lisp-extra-font-lock-test-files.el
└── lisp-extra-font-lock-test-setup.el
/README.md:
--------------------------------------------------------------------------------
1 | # lisp-extra-font-lock - Highlight bound variables and quoted exprs
2 |
3 | *Author:* Anders Lindgren
4 | *Version:* 0.0.6
5 | *URL:* [https://github.com/Lindydancer/lisp-extra-font-lock](https://github.com/Lindydancer/lisp-extra-font-lock)
6 |
7 | This package highlight the location where local variables is
8 | created (bound, for example by `let`) as well as quoted and
9 | backquoted constant expressions.
10 |
11 | ## Example
12 |
13 | Below, `^` is used indicate highlighted normal variables and
14 | constant expressions. `*` is used to show highlighting of special
15 | variables (i.e. those defined by `defvar`) and of the backquote and
16 | comma operators.
17 |
18 | (defun my-function (next)
19 | ^^^^ <- Parameters
20 | (let ((numbers '(one two three))
21 | ^^^^^^^ ^^^^^^^^^^^^^^^ <- Var bound by `let` and quoted expr.
22 | (buffer-read-only t))
23 | **************** <- Special variable (different color)
24 | `(,@numbers and ,next)))
25 | *^** ^^^ * ^ <- Backquote and comma
26 |
27 | ### Screenshot
28 |
29 | 
30 |
31 | ## What is highlighted
32 |
33 | * Parameters in functions and lambdas
34 | * Variables bound by specal constructs like `let`, `dolist`,
35 | `condition-case`, and `pcase-let`
36 | * Normal variables and variables declared as globals using `defvar`
37 | are highlighted in different colors, as a warning
38 | * Quoted expressions
39 | * Backquoted expressions. Subexpressions using the "," or ",@" are
40 | not highlighted (as they are evaluted and thus not constant).
41 | Also, the backquote and the comma operators themselves are
42 | highlighted using a bright color as a warning.
43 | * Hash-quoted symbols.
44 |
45 | ## Installation
46 |
47 | Place this package in a directory in the load-path. To activate it,
48 | use *customize* or place the following lines in a suitable init
49 | file:
50 |
51 | (require 'lisp-extra-font-lock)
52 | (lisp-extra-font-lock-global-mode 1)
53 |
54 | ## Customization
55 |
56 | You can modify the following lists to add more functions that are
57 | recognized:
58 |
59 | * `lisp-extra-font-lock-let-functions` -- List of function with the
60 | same syntax as `let`
61 | * `lisp-extra-font-lock-defun-functions` -- List of function with
62 | the same syntax as `defun`
63 | * `lisp-extra-font-lock-lambda-functions` -- List of function with
64 | the same syntax as `lambda`
65 | * `lisp-extra-font-lock-dolist-functions` -- List of function with
66 | the same syntax as `dolist`
67 | * `lisp-extra-font-lock-bind-first-functions` -- List of function
68 | that bind their first argument, like `condition-case`.
69 | * `lisp-extra-font-lock-loop-functions` -- List of functions with
70 | the same syntax as `cl-loop`.
71 |
72 | The following faces are used when highlighting. You can either
73 | redefine the face (e.g. using a theme), or you can rebind the
74 | corresponding variable.
75 |
76 | * Local variables are highlighted using the standard face
77 | `font-lock-variable-name-face`
78 | * Special (global) variables that are rebound are highlighted using
79 | the face bound to the variable
80 | `lisp-extra-font-lock-special-variable-name-face` (by default
81 | `lisp-extra-font-lock-special-variable-name`, which inherits from
82 | `font-lock-warning-face`)
83 | * Quoted expressions use the face bound to the variable
84 | `lisp-extra-font-lock-quoted-face` (by default
85 | `lisp-extra-font-lock-quoted`, which inherits from
86 | `font-lock-constant-face`)
87 | * The backquote and comma operators use the face bound to the
88 | variable `lisp-extra-font-lock-backquote-face` (by default
89 | `lisp-extra-font-lock-backquote`, which inherits from
90 | `font-lock-warning-face`).
91 | * Named arguments to `cl-loop` are highlighted using
92 | `font-lock-builtin-face`.
93 |
94 | ### Example
95 |
96 | To set the face used to highlight quoted expressions to a gray
97 | color, you can use:
98 |
99 | (custom-set-faces
100 | '(lisp-extra-font-lock-quoted ((t :foreground "grey50"))))
101 |
102 |
103 | ---
104 | Converted from `lisp-extra-font-lock.el` by [*el2markdown*](https://github.com/Lindydancer/el2markdown).
105 |
--------------------------------------------------------------------------------
/doc/demo.el:
--------------------------------------------------------------------------------
1 | ;;; demo.el --- Demonstration program for `lisp-extra-font-lock'.
2 |
3 | ;; The package `lisp-extra-font-lock' highlights variables bound by
4 | ;; `defun', `lambda', `let', `dolist', etc. It also highlight quoted
5 | ;; and backquoted expressions -- excluding any comma operator
6 | ;; expressions.
7 |
8 | (defun my-function (next) ; <- Parameters
9 | (let ((numbers '(one two three)) ; <- `let' and quoted expr
10 | (buffer-read-only t)) ; <- Special variable
11 | `(,@numbers and ,next))) ; <- Backquote and comma
12 |
13 | ;; (my-function 'four) => (one two three and four)
14 |
15 | ;;; demo.el ends here
16 |
--------------------------------------------------------------------------------
/doc/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lindydancer/lisp-extra-font-lock/4605eccbe1a7fcbd3cacf5b71249435413b4db4f/doc/demo.png
--------------------------------------------------------------------------------
/doc/lisp-extra-font-lock-screenshot-setup.el:
--------------------------------------------------------------------------------
1 | ;; lisp-extra-font-lock-screenshot-setup.el --- prepare Emacs for screenshot.
2 |
3 | ;; Usage:
4 | ;;
5 | ;; emacs -q -l lisp-extra-font-lock-screenshot-setup.el
6 | ;;
7 | ;; Take screenshot. OS X: Cmd-Shift-4 SPC click on window.
8 |
9 | (setq inhibit-startup-screen t)
10 |
11 | (blink-cursor-mode -1)
12 |
13 | (defvar lisp-extra-font-lock-screenshot-dir
14 | (or (and load-file-name
15 | (file-name-directory load-file-name))
16 | default-directory))
17 |
18 | (load (concat lisp-extra-font-lock-screenshot-dir
19 | "../lisp-extra-font-lock.el"))
20 | (lisp-extra-font-lock-global-mode 1)
21 | (find-file (concat lisp-extra-font-lock-screenshot-dir "demo.el"))
22 |
23 | (set-frame-size (selected-frame) 80 20)
24 |
25 | (message "")
26 |
27 | ;; lisp-extra-font-lock-screenshot-setup.el ends here
28 |
--------------------------------------------------------------------------------
/lisp-extra-font-lock.el:
--------------------------------------------------------------------------------
1 | ;;; lisp-extra-font-lock.el --- Highlight bound variables and quoted exprs.
2 |
3 | ;; Copyright (C) 2014-2018 Anders Lindgren
4 |
5 | ;; Author: Anders Lindgren
6 | ;; Keywords: languages, faces
7 | ;; Created: 2014-11-22
8 | ;; Version: 0.0.6
9 | ;; URL: https://github.com/Lindydancer/lisp-extra-font-lock
10 |
11 | ;; This program is free software: you can redistribute it and/or modify
12 | ;; it under the terms of the GNU General Public License as published by
13 | ;; the Free Software Foundation, either version 3 of the License, or
14 | ;; (at your option) any later version.
15 | ;;
16 | ;; This program is distributed in the hope that it will be useful,
17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | ;; GNU General Public License for more details.
20 | ;;
21 | ;; You should have received a copy of the GNU General Public License
22 | ;; along with this program. If not, see .
23 |
24 | ;;; Commentary:
25 |
26 | ;; This package highlight the location where local variables is
27 | ;; created (bound, for example by `let') as well as quoted and
28 | ;; backquoted constant expressions.
29 |
30 | ;; Example:
31 | ;;
32 | ;; Below, `^' is used indicate highlighted normal variables and
33 | ;; constant expressions. `*' is used to show highlighting of special
34 | ;; variables (i.e. those defined by `defvar') and of the backquote and
35 | ;; comma operators.
36 | ;;
37 | ;; (defun my-function (next)
38 | ;; ^^^^ <- Parameters
39 | ;; (let ((numbers '(one two three))
40 | ;; ^^^^^^^ ^^^^^^^^^^^^^^^ <- Var bound by `let' and quoted expr.
41 | ;; (buffer-read-only t))
42 | ;; **************** <- Special variable (different color)
43 | ;; `(,@numbers and ,next)))
44 | ;; *^** ^^^ * ^ <- Backquote and comma
45 | ;;
46 | ;; Screenshot:
47 | ;;
48 | ;; 
49 |
50 | ;; What is highlighted:
51 | ;;
52 | ;; * Parameters in functions and lambdas
53 | ;;
54 | ;; * Variables bound by specal constructs like `let', `dolist',
55 | ;; `condition-case', and `pcase-let'
56 | ;;
57 | ;; * Normal variables and variables declared as globals using `defvar'
58 | ;; are highlighted in different colors, as a warning
59 | ;;
60 | ;; * Quoted expressions
61 | ;;
62 | ;; * Backquoted expressions. Subexpressions using the "," or ",@" are
63 | ;; not highlighted (as they are evaluted and thus not constant).
64 | ;; Also, the backquote and the comma operators themselves are
65 | ;; highlighted using a bright color as a warning.
66 | ;;
67 | ;; * Hash-quoted symbols.
68 |
69 | ;; Installation:
70 | ;;
71 | ;; Place this package in a directory in the load-path. To activate it,
72 | ;; use *customize* or place the following lines in a suitable init
73 | ;; file:
74 | ;;
75 | ;; (require 'lisp-extra-font-lock)
76 | ;; (lisp-extra-font-lock-global-mode 1)
77 |
78 | ;; Customization:
79 | ;;
80 | ;; You can modify the following lists to add more functions that are
81 | ;; recognized:
82 | ;;
83 | ;; * `lisp-extra-font-lock-let-functions' -- List of function with the
84 | ;; same syntax as `let'
85 | ;;
86 | ;; * `lisp-extra-font-lock-defun-functions' -- List of function with
87 | ;; the same syntax as `defun'
88 | ;;
89 | ;; * `lisp-extra-font-lock-lambda-functions' -- List of function with
90 | ;; the same syntax as `lambda'
91 | ;;
92 | ;; * `lisp-extra-font-lock-dolist-functions' -- List of function with
93 | ;; the same syntax as `dolist'
94 | ;;
95 | ;; * `lisp-extra-font-lock-bind-first-functions' -- List of function
96 | ;; that bind their first argument, like `condition-case'.
97 | ;;
98 | ;; * `lisp-extra-font-lock-loop-functions' -- List of functions with
99 | ;; the same syntax as `cl-loop'.
100 | ;;
101 | ;; The following faces are used when highlighting. You can either
102 | ;; redefine the face (e.g. using a theme), or you can rebind the
103 | ;; corresponding variable.
104 | ;;
105 | ;; * Local variables are highlighted using the standard face
106 | ;; `font-lock-variable-name-face'
107 | ;;
108 | ;; * Special (global) variables that are rebound are highlighted using
109 | ;; the face bound to the variable
110 | ;; `lisp-extra-font-lock-special-variable-name-face' (by default
111 | ;; `lisp-extra-font-lock-special-variable-name', which inherits from
112 | ;; `font-lock-warning-face')
113 | ;;
114 | ;; * Quoted expressions use the face bound to the variable
115 | ;; `lisp-extra-font-lock-quoted-face' (by default
116 | ;; `lisp-extra-font-lock-quoted', which inherits from
117 | ;; `font-lock-constant-face')
118 | ;;
119 | ;; * The backquote and comma operators use the face bound to the
120 | ;; variable `lisp-extra-font-lock-backquote-face' (by default
121 | ;; `lisp-extra-font-lock-backquote', which inherits from
122 | ;; `font-lock-warning-face').
123 | ;;
124 | ;; * Named arguments to `cl-loop' are highlighted using
125 | ;; `font-lock-builtin-face'.
126 | ;;
127 | ;; Example:
128 | ;;
129 | ;; To set the face used to highlight quoted expressions to a gray
130 | ;; color, you can use:
131 | ;;
132 | ;; (custom-set-faces
133 | ;; '(lisp-extra-font-lock-quoted ((t :foreground "grey50"))))
134 |
135 | ;;; Code:
136 |
137 | ;; ------------------------------
138 | ;; Customizable variables
139 | ;;
140 |
141 |
142 | (defgroup lisp-extra-font-lock nil
143 | "Highlight bound variables and quoted expressions in lisp."
144 | :group 'faces)
145 |
146 |
147 | ;;;###autoload
148 | (defcustom lisp-extra-font-lock-modes '(emacs-lisp-mode lisp-mode)
149 | "List of modes where Lisp Extra Font Lock Global mode should be enabled."
150 | :type '(repeat symbol)
151 | :group 'lisp-extra-font-lock)
152 |
153 |
154 | ;; ----------
155 | ;; Faces and corresponding variable.
156 | ;;
157 |
158 | (defface lisp-extra-font-lock-backquote
159 | '((t :inherit font-lock-warning-face))
160 | "The default face used to highlight backquotes and the comma operator."
161 | :group 'lisp-extra-font-lock)
162 |
163 |
164 | (defcustom lisp-extra-font-lock-backquote-face 'lisp-extra-font-lock-backquote
165 | "The face used to highlight backquotes and the comma operator.
166 | To disable this highlighting, set this to nil."
167 | :type '(choice (const nil)
168 | face)
169 | :group 'lisp-extra-font-lock)
170 |
171 |
172 | (defface lisp-extra-font-lock-quoted
173 | '((t :inherit font-lock-constant-face))
174 | "The default face used to highlight quoted expressions."
175 | :group 'lisp-extra-font-lock)
176 |
177 |
178 | (defcustom lisp-extra-font-lock-quoted-face 'lisp-extra-font-lock-quoted
179 | "The face used to highlight quoted expressions.
180 | To disable this highlighting, set this to nil."
181 | :type '(choice (const nil)
182 | face)
183 | :group 'lisp-extra-font-lock)
184 |
185 |
186 | (defface lisp-extra-font-lock-quoted-function
187 | '((t :inherit font-lock-function-name-face))
188 | "The default face used to highlight #'-quoted function symbols."
189 | :group 'lisp-extra-font-lock)
190 |
191 |
192 | (defcustom lisp-extra-font-lock-quoted-function-face
193 | 'lisp-extra-font-lock-quoted-function
194 | "The face used to highlight #'-quoted function symbols.
195 | To disable this highlighting, set this to nil."
196 | :type '(choice (const nil)
197 | face)
198 | :group 'lisp-extra-font-lock)
199 |
200 |
201 | (defface lisp-extra-font-lock-special-variable-name
202 | '((t :inherit font-lock-warning-face))
203 | "The default face used to highlight special variables bound by `let'."
204 | :group 'lisp-extra-font-lock)
205 |
206 |
207 | (defcustom lisp-extra-font-lock-special-variable-name-face
208 | 'lisp-extra-font-lock-special-variable-name
209 | "The face used to highlight special variables bound by `let'.
210 |
211 | A special variable is a global variable defined by `defvar'. See
212 | `special-variable-p' for details.
213 |
214 | To disable this highlighting, set this to nil. To highlight
215 | special variables like plain variables, set this to
216 | `font-lock-variable-name-face'."
217 | :type '(choice (const nil)
218 | face)
219 | :group 'lisp-extra-font-lock)
220 |
221 |
222 | ;; ----------
223 | ;; Function lists
224 | ;;
225 |
226 | (defcustom lisp-extra-font-lock-let-functions
227 | '("let"
228 | "let*"
229 | "letf"
230 | "letf*"
231 | "lexical-let"
232 | "lexical-let*"
233 | "multiple-value-bind"
234 | "pcase-let" ; Highlights entire UPAT:s.
235 | "pcase-let*"
236 | "cl-letf"
237 | "cl-letf*"
238 | "cl-multiple-value-bind")
239 | "List of function using same syntax as `let' to bind variables."
240 | :type '(repeat string)
241 | :group 'lisp-extra-font-lock)
242 |
243 |
244 | (defcustom lisp-extra-font-lock-defun-functions
245 | '("defun"
246 | "defun*"
247 | "defmacro"
248 | "defmacro*"
249 | "defsubst"
250 | "cl-defun"
251 | "cl-defmacro"
252 | "cl-defsubst")
253 | "List of function using same syntax as `defun' to bind variables."
254 | :type '(repeat string)
255 | :group 'lisp-extra-font-lock)
256 |
257 |
258 | (defcustom lisp-extra-font-lock-lambda-functions
259 | '("lambda")
260 | "List of function using same syntax as `lambda' to bind variables."
261 | :type '(repeat string)
262 | :group 'lisp-extra-font-lock)
263 |
264 |
265 | (defcustom lisp-extra-font-lock-dolist-functions
266 | '("dolist"
267 | "dotimes"
268 | "cl-dolist"
269 | "cl-dotimes")
270 | "List of function using same syntax as `dolist' to bind variables."
271 | :type '(repeat string)
272 | :group 'lisp-extra-font-lock)
273 |
274 |
275 | (defcustom lisp-extra-font-lock-bind-first-functions
276 | '("condition-case")
277 | "List of function that bind their first argument."
278 | :type '(repeat string)
279 | :group 'lisp-extra-font-lock)
280 |
281 |
282 | (defcustom lisp-extra-font-lock-loop-functions
283 | '("loop"
284 | "cl-loop")
285 | "List of functions using same syntax as `loop' to bind variables.."
286 | :type '(repeat string)
287 | :group 'lisp-extra-font-lock)
288 |
289 |
290 | ;; ------------------------------
291 | ;; The modes
292 | ;;
293 |
294 | ;;;###autoload
295 | (define-minor-mode lisp-extra-font-lock-mode
296 | "Minor mode that highlights bound variables and quoted expressions in lisp."
297 | :group 'lisp-extra-font-lock
298 | (if lisp-extra-font-lock-mode
299 | (lisp-extra-font-lock-add-keywords)
300 | (lisp-extra-font-lock-remove-keywords))
301 | ;; As of Emacs 24.4, `font-lock-fontify-buffer' is not legal to
302 | ;; call, instead `font-lock-flush' should be used.
303 | (if (fboundp 'font-lock-flush)
304 | (font-lock-flush)
305 | (when font-lock-mode
306 | (with-no-warnings
307 | (font-lock-fontify-buffer)))))
308 |
309 |
310 | ;;;###autoload
311 | (define-global-minor-mode lisp-extra-font-lock-global-mode
312 | lisp-extra-font-lock-mode
313 | (lambda ()
314 | (when (apply 'derived-mode-p lisp-extra-font-lock-modes)
315 | (lisp-extra-font-lock-mode 1)))
316 | :group 'lisp-extra-font-lock)
317 |
318 |
319 | (defun lisp-extra-font-lock-variable-face-form (name)
320 | "A form suitable for a font-lock face expression.
321 |
322 | NAME is a form that should evalute to the name of the symbol, as a string."
323 | `(if (ignore-errors (let ((symbol (intern-soft ,name)))
324 | (and symbol
325 | (special-variable-p symbol))))
326 | lisp-extra-font-lock-special-variable-name-face
327 | font-lock-variable-name-face))
328 |
329 | (defun lisp-extra-font-lock-keywords ()
330 | "Font-lock keywords used by `lisp-extra-font-lock'.
331 | The keywords highlight variable bindings and quoted expressions."
332 | `(;; Function and lambda parameters
333 | (,(concat "("
334 | "\\(?:"
335 | (regexp-opt lisp-extra-font-lock-defun-functions)
336 | "[ \t\n]+\\_<\\(?:\\sw\\|\\s_\\)+\\_>"
337 | "\\|"
338 | (regexp-opt lisp-extra-font-lock-lambda-functions)
339 | "\\)"
340 | "[ \t\n]+(")
341 | (lisp-extra-font-lock-match-argument-list
342 | ;; Pre-match form
343 | (progn
344 | (goto-char (match-end 0))
345 | ;; Search limit
346 | (save-excursion
347 | (backward-char) ; Position point before "(".
348 | (lisp-extra-font-lock-end-position)))
349 | ;; Post-match form
350 | nil
351 | (0 ,(lisp-extra-font-lock-variable-face-form '(match-string 0))
352 | nil t)))
353 | ;; Variables bound by `let'.
354 | (,(concat "("
355 | (regexp-opt lisp-extra-font-lock-let-functions)
356 | "[ \t]+(")
357 | (lisp-extra-font-lock-match-let
358 | ;; Pre-match form
359 | (progn
360 | (goto-char (match-end 0))
361 | ;; Search limit
362 | (save-excursion
363 | (backward-char) ; Position point before "(".
364 | (lisp-extra-font-lock-end-position)))
365 | ;; Post-match form
366 | (goto-char (match-end 0))
367 | (0 ,(lisp-extra-font-lock-variable-face-form '(match-string 0)))))
368 | ;; Variables bound by `cl-dolist' etc.
369 | (,(concat "("
370 | (regexp-opt lisp-extra-font-lock-dolist-functions)
371 | "[ \t]+(\\(\\(?:\\sw\\|\\s_\\)+\\)\\_>")
372 | (1 ,(lisp-extra-font-lock-variable-face-form '(match-string 1))))
373 | ;; Bind first argument like `condition-case'.
374 | (,(concat "("
375 | (regexp-opt lisp-extra-font-lock-bind-first-functions)
376 | "[ \t]+\\_<\\(\\(?:\\sw\\|\\s_\\)+\\)\\_>")
377 | (1 (and (not (string= (match-string 1) "nil"))
378 | ,(lisp-extra-font-lock-variable-face-form '(match-string 1)))))
379 | ;; Bind variables and named arguments to `cl-loop'.
380 | (,(concat "("
381 | (regexp-opt lisp-extra-font-lock-loop-functions)
382 | "\\_>")
383 | (lisp-extra-font-lock-match-loop-keywords
384 | ;; Pre-match form. Value of expression is limit for submatcher.
385 | (progn
386 | (goto-char (match-end 0))
387 | (save-excursion
388 | (goto-char (match-beginning 0))
389 | (lisp-extra-font-lock-end-position)))
390 | ;; Post-match form.
391 | (goto-char (match-end 0))
392 | (1 font-lock-builtin-face)
393 | (2 ,(lisp-extra-font-lock-variable-face-form '(match-string 2)) nil t)))
394 | (;; Quote and backquote.
395 | ;;
396 | ;; Matcher: Set match-data 1 if backquote.
397 | lisp-extra-font-lock-match-quote-and-backquote
398 | (1 lisp-extra-font-lock-backquote-face nil t)
399 | (;; Submatcher, match part of quoted expression or comma.
400 | lisp-extra-font-lock-match-quoted-content
401 | ;; Pre-match form. Value of expression is limit for submatcher.
402 | (progn
403 | (goto-char (match-end 0))
404 | ;; Search limit
405 | (lisp-extra-font-lock-end-position))
406 | ;; Post-match form
407 | (goto-char (match-end 0))
408 | ;; Highlight rules for submatcher.
409 | (1 lisp-extra-font-lock-quoted-face append)
410 | (2 lisp-extra-font-lock-backquote-face nil t)))
411 | ;; Function read syntax
412 | ("#'\\(\\(?:\\sw\\|\\s_\\)+\\)\\_>"
413 | 1 lisp-extra-font-lock-quoted-function-face)))
414 |
415 |
416 | (defvar lisp-extra-font-lock--installed-keywords nil)
417 |
418 | (defun lisp-extra-font-lock-add-keywords ()
419 | "Add extra font-lock keywords to lisp."
420 | (set (make-local-variable 'font-lock-multiline) t)
421 | (when (local-variable-p 'lisp-extra-font-lock--installed-keywords)
422 | (font-lock-remove-keywords nil lisp-extra-font-lock--installed-keywords))
423 | (let ((keywords (lisp-extra-font-lock-keywords)))
424 | (set (make-local-variable 'lisp-extra-font-lock--installed-keywords)
425 | keywords)
426 | (font-lock-add-keywords nil keywords 'append)))
427 |
428 |
429 | (defun lisp-extra-font-lock-remove-keywords ()
430 | "Remove font-lock keywords for extra lisp highlithing."
431 | (font-lock-remove-keywords nil lisp-extra-font-lock--installed-keywords))
432 |
433 |
434 | ;; ----------------------------------------
435 | ;; Matcher functions
436 | ;;
437 |
438 | (defun lisp-extra-font-lock-end-position ()
439 | "Suitable end position of expression after point.
440 | If expression is open-ended, the beginning of the next top-level
441 | form is used, or `point-max' if none is found."
442 | (save-match-data
443 | (save-excursion
444 | (or (condition-case nil
445 | (progn
446 | (forward-sexp)
447 | (point))
448 | (error nil))
449 | (and (re-search-forward "^(" nil t)
450 | (match-beginning 0))
451 | (point-max)))))
452 |
453 | (defun lisp-extra-font-lock-match-argument-list (limit)
454 | (forward-comment (buffer-size))
455 | (and (< (point) limit)
456 | (let ((res (looking-at "\\_<\\(?:\\sw\\|\\s_\\)+\\_>")))
457 | (when res
458 | (goto-char (match-end 0)))
459 | res)))
460 |
461 |
462 | (defun lisp-extra-font-lock-match-let (limit)
463 | "Match next variable introduced by `let'-like constructs."
464 | (forward-comment (buffer-size))
465 | (let ((p (point)))
466 | (cond ((eq (following-char) ?\( )
467 | ;; Match "(var initial-valoue)"
468 | (forward-char)
469 | (forward-comment (buffer-size))
470 | (and
471 | (< (point) limit)
472 | (let ((res (looking-at "\\(?:\\sw\\|\\s_\\)+\\_>")))
473 | (when res
474 | (goto-char p)
475 | (condition-case nil
476 | (forward-sexp)
477 | (error (goto-char limit))))
478 | res)))
479 | ((looking-at "\\(?:\\sw\\|\\s_\\)+\\_>")
480 | ;; Match "var"
481 | (goto-char (match-end 0))
482 | (<= (point) limit))
483 | (t
484 | nil))))
485 |
486 |
487 | (defun lisp-extra-font-lock-is-in-comment-or-string (pos)
488 | "Return non-nil if POS is in a comment, string, constant, or reader macro.
489 |
490 | This assumes that Font Lock is active and has fontified comments
491 | and strings."
492 | (or (nth 8 (save-excursion
493 | (syntax-ppss pos))) ; In comment or string.
494 | ;; Plain character constant ?.
495 | (eq (char-before pos) ??)
496 | ;; Escaped character constant ?\.
497 | (and (eq (char-before pos) ?\\)
498 | (eq (char-before (- pos 1)) ??))
499 | ;; Reader macro like #'.
500 | (eq (char-before pos) ?#)))
501 |
502 |
503 | (defun lisp-extra-font-lock-match-quote-and-backquote (limit)
504 | "Search for quote and backquote in in code.
505 | Set match data 1 if character matched is backquote."
506 | (let (res)
507 | (while
508 | (progn (setq res (re-search-forward "\\(?:\\(`\\)\\|'\\)" limit t))
509 | (and res
510 | (lisp-extra-font-lock-is-in-comment-or-string
511 | (match-beginning 0)))))
512 | res))
513 |
514 |
515 | (defun lisp-extra-font-lock-match-quoted-content (limit)
516 | "Match next part of a quoted content.
517 |
518 | Match up to next comma operator or quoted subexpression, or to
519 | the end of the quoted expression."
520 | (and (< (point) limit)
521 | (let ((p (point))
522 | res)
523 | (while
524 | (progn
525 | (setq res (re-search-forward "\\(,@?\\|[`']\\)" limit t))
526 | (and res
527 | (lisp-extra-font-lock-is-in-comment-or-string
528 | (match-beginning 0)))))
529 | (if res
530 | ;; Match up to next quoted subpart or comma operator.
531 | (let ((is-comma (eq (char-after (match-beginning 0)) ?,)))
532 | (set-match-data (list
533 | ;; Match data 0: Full match.
534 | p (match-end 0)
535 | ;; Match data 1: Part of the quoted expression
536 | p
537 | (match-beginning 0)
538 | ;; Match data 2; Comma operator (if present)
539 | (and is-comma (match-beginning 0))
540 | (and is-comma (match-end 0))))
541 | (condition-case nil
542 | (forward-sexp)
543 | (error (goto-char limit))))
544 | ;; Match to the end of the quoted expression.
545 | (set-match-data (list p limit
546 | p limit))
547 | (goto-char limit))
548 | t)))
549 |
550 | (defvar lisp-extra-font-lock-loop-keywords
551 | '("=" "above" "across" "across-ref" "always" "and" "append" "as"
552 | "being" "below" "buffer" "buffers" "by"
553 | "collect" "collecting" "concat" "count"
554 | "do" "doing" "downfrom" "downto"
555 | "each" "element" "elements" "else" "end"
556 | "extent" "extents" "external-symbol" "external-symbols"
557 | "finally" "frames" "from"
558 | "hash-key" "hash-keys" "hash-value" "hash-values"
559 | "if" "in" "in-ref" "initially" "interval" "intervals"
560 | "key-binding" "key-bindings" "key-code" "key-codes" "key-seq" "key-seqs"
561 | "maximize" "minimize"
562 | "named" "nconc" "nconcing" "never"
563 | "of" "of-ref" "on" "overlay" "overlays"
564 | "present-symbol" "present-symbols" "property"
565 | "repeat" "return"
566 | "screen" "screens" "sum" "symbol" "symbols"
567 | "the" "then" "thereis" "to"
568 | "unless" "until" "upfrom" "upto" "using"
569 | "vconcat"
570 | "when" "while" "windows")
571 | "List of `cl-loop' named parameters, excluding variable binding ones.")
572 |
573 | (defvar lisp-extra-font-lock-loop-keywords-with-var '("for"
574 | "index"
575 | "into"
576 | "with")
577 | "List of `cl-loop' named variable binding parameters.")
578 |
579 |
580 | ;; Match named loop keywords, and (optionally) any bound variables.
581 | ;;
582 | ;; Note, does not support "destructuring", i.e. binding several
583 | ;; variables using pattern matching. If this is used, the entire
584 | ;; expression is highlighted as a variable.
585 | (defun lisp-extra-font-lock-match-loop-keywords (limit)
586 | "Match named keyword of `loop' and highlight variable arguments."
587 | (while
588 | (progn
589 | (forward-comment (buffer-size))
590 | (and (< (point) limit)
591 | (not (looking-at
592 | (concat
593 | "\\_<"
594 | "\\("
595 | (regexp-opt (append
596 | lisp-extra-font-lock-loop-keywords-with-var
597 | lisp-extra-font-lock-loop-keywords))
598 | "\\)"
599 | "\\_>")))))
600 | (condition-case nil
601 | (forward-sexp)
602 | (error (goto-char limit))))
603 | (if (not (< (point) limit))
604 | nil
605 | (goto-char (match-end 0))
606 | (when (member (match-string 1) lisp-extra-font-lock-loop-keywords-with-var)
607 | (forward-comment (buffer-size))
608 | (let ((var-start (point)))
609 | (when (condition-case nil
610 | (progn
611 | (forward-sexp)
612 | t)
613 | (error nil))
614 | (set-match-data (list
615 | (match-beginning 0)
616 | (point)
617 | (match-beginning 1)
618 | (match-end 1)
619 | var-start
620 | (point))))))
621 | t))
622 |
623 | (provide 'lisp-extra-font-lock)
624 |
625 | ;;; lisp-extra-font-lock.el ends here.
626 |
--------------------------------------------------------------------------------
/test/files/basics.el:
--------------------------------------------------------------------------------
1 | ;; A plain function.
2 | (defun my-function1 (arg)
3 | (let ((tmp 'value))
4 | nil))
5 |
6 | ;; &optional should not be affected, but subsequent arguments should
7 | ;; be highlighted.
8 | (defun my-function2 (arg &optional arg2)
9 | nil)
10 |
11 | ;; Reserved words should be highlighted.
12 | (defun my-function3 (arg mode-name)
13 | (let ((major-mode 'what)
14 | (my-major-mode 'better))
15 | nil))
16 |
17 | ;; `dolist'.
18 | (defun my-dlist ()
19 | (dolist (arg '(1 2 3))
20 | nil))
21 |
22 | ;; `loop'.
23 | (defun my-loop (my-list)
24 | (cl-loop for (key . value) in my-list
25 | collect key
26 | collect value))
27 |
--------------------------------------------------------------------------------
/test/files/basics.el.faceup:
--------------------------------------------------------------------------------
1 | «m:;; »«x:A plain function.
2 | »(«k:defun» «f:my-function1» («v:arg»)
3 | («k:let» ((«v:tmp» '«:lisp-extra-font-lock-quoted:value»))
4 | nil))
5 |
6 | «m:;; »«x:&optional should not be affected, but subsequent arguments should
7 | »«m:;; »«x:be highlighted.
8 | »(«k:defun» «f:my-function2» («v:arg» «t:&optional» «v:arg2»)
9 | nil)
10 |
11 | «m:;; »«x:Reserved words should be highlighted.
12 | »(«k:defun» «f:my-function3» («v:arg» «:lisp-extra-font-lock-special-variable-name:mode-name»)
13 | («k:let» ((«:lisp-extra-font-lock-special-variable-name:major-mode» '«:lisp-extra-font-lock-quoted:what»)
14 | («v:my-major-mode» '«:lisp-extra-font-lock-quoted:better»))
15 | nil))
16 |
17 | «m:;; »«x:`«c:dolist»'.
18 | »(«k:defun» «f:my-dlist» ()
19 | («k:dolist» («v:arg» '«:lisp-extra-font-lock-quoted:(1 2 3)»)
20 | nil))
21 |
22 | «m:;; »«x:`«c:loop»'.
23 | »(«k:defun» «f:my-loop» («v:my-list»)
24 | («k:cl-loop» «b:for» «v:(key . value)» «b:in» my-list
25 | «b:collect» key
26 | «b:collect» value))
27 |
--------------------------------------------------------------------------------
/test/files/demo.el:
--------------------------------------------------------------------------------
1 | ;;; demo.el --- Demonstration program for `lisp-extra-font-lock'.
2 |
3 | ;; The package `lisp-extra-font-lock' highlights variables bound by
4 | ;; `defun', `lambda', `let', `dolist', etc. It also highlight quoted
5 | ;; and backquoted expressions -- excluding any comma operator
6 | ;; expressions.
7 |
8 | (defun my-function (next) ; <- Parameters
9 | (let ((numbers '(one two three)) ; <- `let' and quoted expr
10 | (buffer-read-only t)) ; <- Special variable
11 | `(,@numbers and ,next))) ; <- Backquote and comma
12 |
13 | ;; (my-function 'four) => (one two three and four)
14 |
15 | ;;; demo.el ends here
16 |
--------------------------------------------------------------------------------
/test/files/demo.el.faceup:
--------------------------------------------------------------------------------
1 | «m:;;; »«x:demo.el --- Demonstration program for `«c:lisp-extra-font-lock»'.
2 | »
3 | «m:;; »«x:The package `«c:lisp-extra-font-lock»' highlights variables bound by
4 | »«m:;; »«x:`«c:defun»', `«c:lambda»', `«c:let»', `«c:dolist»', etc. It also highlight quoted
5 | »«m:;; »«x:and backquoted expressions -- excluding any comma operator
6 | »«m:;; »«x:expressions.
7 | »
8 | («k:defun» «f:my-function» («v:next») «m:; »«x:<- Parameters
9 | » («k:let» ((«v:numbers» '«:lisp-extra-font-lock-quoted:(one two three)») «m:; »«x:<- `«c:let»' and quoted expr
10 | » («:lisp-extra-font-lock-special-variable-name:buffer-read-only» t)) «m:; »«x:<- Special variable
11 | » «:lisp-extra-font-lock-backquote:`»«:lisp-extra-font-lock-quoted:(»«:lisp-extra-font-lock-backquote:,@»numbers«:lisp-extra-font-lock-quoted: and »«:lisp-extra-font-lock-backquote:,»next«:lisp-extra-font-lock-quoted:)»)) «m:; »«x:<- Backquote and comma
12 | »
13 | «m:;; »«x:(my-function 'four) => (one two three and four)
14 | »
15 | «m:;;; »«x:demo.el ends here
16 | »
--------------------------------------------------------------------------------
/test/files/exclude.el:
--------------------------------------------------------------------------------
1 | ;; Don't highlight quotes in certain contexts.
2 |
3 | ;; Don't highlight 'no in a comment.
4 |
5 | "Don't highlight 'no in a string."
6 |
7 | ;; Not in a character constant:
8 |
9 | (setq exclude-quote (cons ?' 'yes))
10 |
11 | ;; Not in an escapted character constant:
12 |
13 | (setq exclude-quote (cons ?\' 'yes))
14 |
15 | ;; exclude.el ends here.
16 |
--------------------------------------------------------------------------------
/test/files/exclude.el.faceup:
--------------------------------------------------------------------------------
1 | «m:;; »«x:Don't highlight quotes in certain contexts.
2 | »
3 | «m:;; »«x:Don't highlight 'no in a comment.
4 | »
5 | «s:"Don't highlight 'no in a string."»
6 |
7 | «m:;; »«x:Not in a character constant:
8 | »
9 | («k:setq» exclude-quote (cons ?' '«:lisp-extra-font-lock-quoted:yes»))
10 |
11 | «m:;; »«x:Not in an escapted character constant:
12 | »
13 | («k:setq» exclude-quote (cons ?\' '«:lisp-extra-font-lock-quoted:yes»))
14 |
15 | «m:;; »«x:exclude.el ends here.
16 | »
--------------------------------------------------------------------------------
/test/files/hash-quote.el:
--------------------------------------------------------------------------------
1 | ;; A #' should not trigger the normal quoting system.
2 |
3 | ;; Special case for hash-quoted symbols.
4 | #'symbol
5 |
6 | ;; Ensure the lambda isn't highlighted as a constant.
7 | (mapcar #'(lambda (x) (+ x 1)) '(1 2 3 4))
8 |
9 | ;; Embedded hash-quoted lambda.
10 | '(alpha #'(lambda (x)))
11 |
--------------------------------------------------------------------------------
/test/files/hash-quote.el.faceup:
--------------------------------------------------------------------------------
1 | «m:;; »«x:A #' should not trigger the normal quoting system.
2 | »
3 | «m:;; »«x:Special case for hash-quoted symbols.
4 | »#'«:lisp-extra-font-lock-quoted-function:symbol»
5 |
6 | «m:;; »«x:Ensure the lambda isn't highlighted as a constant.
7 | »(mapcar #'(lambda («v:x») (+ x 1)) '«:lisp-extra-font-lock-quoted:(1 2 3 4)»)
8 |
9 | «m:;; »«x:Embedded hash-quoted lambda.
10 | »'«:lisp-extra-font-lock-quoted:(alpha #'(lambda («v:x»)))»
11 |
--------------------------------------------------------------------------------
/test/lisp-extra-font-lock-test-files.el:
--------------------------------------------------------------------------------
1 | ;;; lisp-extra-font-lock-test-files.el --- Test for lisp-extra-font-lock.
2 |
3 | ;; Copyright (C) 2016 Anders Lindgren
4 |
5 | ;; Author: Anders Lindgren
6 | ;; Keywords: faces languages
7 |
8 | ;; This program is free software: you can redistribute it and/or modify
9 | ;; it under the terms of the GNU General Public License as published by
10 | ;; the Free Software Foundation, either version 3 of the License, or
11 | ;; (at your option) any later version.
12 |
13 | ;; This program is distributed in the hope that it will be useful,
14 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | ;; GNU General Public License for more details.
17 |
18 | ;; You should have received a copy of the GNU General Public License
19 | ;; along with this program. If not, see .
20 |
21 | ;;; Commentary:
22 |
23 | ;; Regression test of `lisp-extra-font-lock', a package providing
24 | ;; additional font-lock rules for lisp languages. This module verifies
25 | ;; fontification of a number of files. This is done by keeing a text
26 | ;; representation of the fontification using `faceup' markup, in
27 | ;; addition to the original files.
28 | ;;
29 | ;; The actual check is performed using `ert', with font-lock test
30 | ;; function provided by `faceup'.
31 |
32 | ;;; Code:
33 |
34 | (require 'faceup)
35 |
36 | (defvar lisp-extra-font-lock-test-dir (faceup-this-file-directory))
37 |
38 | (defun lisp-extra-font-lock-test-file (file)
39 | "Test that FILE is fontified as the .faceup file describes.
40 |
41 | FILE is interpreted as relative to this source directory."
42 | (faceup-test-font-lock-file '(emacs-lisp-mode
43 | lisp-extra-font-lock-mode)
44 | (concat
45 | lisp-extra-font-lock-test-dir
46 | file)))
47 | (faceup-defexplainer lisp-extra-font-lock-test-file)
48 |
49 |
50 | (ert-deftest lisp-extra-font-lock-test-files ()
51 | (should (lisp-extra-font-lock-test-file "files/basics.el"))
52 | (should (lisp-extra-font-lock-test-file "files/demo.el"))
53 | (should (lisp-extra-font-lock-test-file "files/hash-quote.el"))
54 | (should (lisp-extra-font-lock-test-file "files/exclude.el")))
55 |
56 | (provide 'lisp-extra-font-lock-test-files)
57 |
58 | ;; lisp-extra-font-lock-test-files.el ends here.
59 |
--------------------------------------------------------------------------------
/test/lisp-extra-font-lock-test-setup.el:
--------------------------------------------------------------------------------
1 | ;;; lisp-extra-font-lock-test-setup.el --- Setup and execute all tests.
2 |
3 | ;;; Commentary:
4 |
5 | ;; This package sets up a suitable enviroment for testing
6 | ;; lisp-extra-font-lock, and executes the tests.
7 | ;;
8 | ;; Usage:
9 | ;;
10 | ;; emacs -q -l lisp-extra-font-lock-test-setup.el
11 | ;;
12 | ;; Note that this package assumes that some packages are located in
13 | ;; specific locations.
14 | ;;
15 | ;; Note that different Emacs versions highlight things slightly
16 | ;; differently. The corresponding .faceup file was generated using
17 | ;; Emacs 24.3.
18 |
19 | ;;; Code:
20 |
21 | (setq inhibit-startup-screen t)
22 | (prefer-coding-system 'utf-8)
23 |
24 | (defvar lisp-extra-font-lock-test-setup-dir
25 | (if load-file-name
26 | (file-name-directory load-file-name)
27 | default-directory))
28 |
29 | (dolist (dir '("." ".." "../../faceup"))
30 | (add-to-list 'load-path (concat lisp-extra-font-lock-test-setup-dir dir)))
31 |
32 | ;; Emacs 25.1 contains a bug which prevents if from highlighting
33 | ;; "lambda" as a keyword, this may cause false errors.
34 | ;;
35 | ;; See http://debbugs.gnu.org/cgi/bugreport.cgi?bug=23465
36 | (when (and (eq emacs-major-version 25)
37 | (eq emacs-minor-version 1))
38 | (font-lock-add-keywords 'emacs-lisp-mode
39 | '(("\\_" (0 font-lock-keyword-face)))))
40 |
41 | (require 'lisp-extra-font-lock)
42 | (require 'lisp-extra-font-lock-test-files)
43 |
44 | (ert t)
45 |
46 | ;;; lisp-extra-font-lock-test-setup.el ends here
47 |
--------------------------------------------------------------------------------