Commit | Line | Data |
---|---|---|
030f4a35 | 1 | ;; Electric Font Lock Mode |
799761f0 | 2 | ;; Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. |
030f4a35 | 3 | |
799761f0 | 4 | ;; Author: jwz, then rms and sm <simon@gnu.ai.mit.edu> |
030f4a35 RS |
5 | ;; Maintainer: FSF |
6 | ;; Keywords: languages, faces | |
7 | ||
8 | ;; This file is part of GNU Emacs. | |
9 | ||
10 | ;; GNU Emacs is free software; you can redistribute it and/or modify | |
11 | ;; it under the terms of the GNU General Public License as published by | |
12 | ;; the Free Software Foundation; either version 2, or (at your option) | |
13 | ;; any later version. | |
14 | ||
15 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | ;; GNU General Public License for more details. | |
19 | ||
20 | ;; You should have received a copy of the GNU General Public License | |
21 | ;; along with GNU Emacs; see the file COPYING. If not, write to | |
22 | ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
23 | ||
030f4a35 RS |
24 | ;;; Commentary: |
25 | ||
b89e1134 SM |
26 | ;; Font Lock mode is a minor mode that causes your comments to be displayed in |
27 | ;; one face, strings in another, reserved words in another, and so on. | |
030f4a35 RS |
28 | ;; |
29 | ;; Comments will be displayed in `font-lock-comment-face'. | |
30 | ;; Strings will be displayed in `font-lock-string-face'. | |
a1eb1cf1 | 31 | ;; Regexps are used to display selected patterns in other faces. |
030f4a35 RS |
32 | ;; |
33 | ;; To make the text you type be fontified, use M-x font-lock-mode. | |
b89e1134 | 34 | ;; When this minor mode is on, the faces of the current line are |
030f4a35 RS |
35 | ;; updated with every insertion or deletion. |
36 | ;; | |
b89e1134 | 37 | ;; To turn Font Lock mode on automatically, add this to your .emacs file: |
030f4a35 | 38 | ;; |
b89e1134 | 39 | ;; (add-hook 'emacs-lisp-mode-hook 'turn-on-font-lock) |
030f4a35 | 40 | ;; |
b89e1134 | 41 | ;; On a Sparc2, `font-lock-fontify-buffer' takes about 10 seconds for a 120k |
a1eb1cf1 RS |
42 | ;; file of C code using the default configuration, and about 25 seconds using |
43 | ;; the more extensive configuration, though times also depend on file contents. | |
44 | ;; You can speed this up substantially by removing some of the patterns that | |
45 | ;; are highlighted by default. Fontifying Lisp code is significantly faster, | |
46 | ;; because Lisp has a more regular syntax than C, so the expressions don't have | |
47 | ;; to be as hairy. | |
48 | ;; | |
b89e1134 SM |
49 | ;; If you add patterns for a new mode, say foo.el's `foo-mode', say in which |
50 | ;; you don't want syntactic fontification to occur, you can make Font Lock mode | |
51 | ;; use your regexps when turning on Font Lock by adding to `foo-mode-hook': | |
52 | ;; | |
53 | ;; (add-hook 'foo-mode-hook | |
54 | ;; '(lambda () (make-local-variable 'font-lock-defaults) | |
55 | ;; (setq font-lock-defaults '(foo-font-lock-keywords t)))) | |
56 | ;; | |
a1eb1cf1 RS |
57 | ;; Nasty regexps of the form "bar\\(\\|lo\\)\\|f\\(oo\\|u\\(\\|bar\\)\\)\\|lo" |
58 | ;; are made thusly: (make-regexp '("foo" "fu" "fubar" "bar" "barlo" "lo")) for | |
59 | ;; efficiency. See /pub/gnu/emacs/elisp-archive/functions/make-regexp.el.Z on | |
60 | ;; archive.cis.ohio-state.edu for this and other functions. | |
61 | \f | |
030f4a35 RS |
62 | ;;; Code: |
63 | ||
a1eb1cf1 RS |
64 | (defvar font-lock-comment-face 'font-lock-comment-face |
65 | "Face to use for comments.") | |
030f4a35 | 66 | |
a1eb1cf1 RS |
67 | (defvar font-lock-string-face 'font-lock-string-face |
68 | "Face to use for strings.") | |
030f4a35 | 69 | |
a1eb1cf1 | 70 | (defvar font-lock-function-name-face 'font-lock-function-name-face |
030f4a35 RS |
71 | "Face to use for function names.") |
72 | ||
a1eb1cf1 RS |
73 | (defvar font-lock-variable-name-face 'font-lock-variable-name-face |
74 | "Face to use for variable names.") | |
75 | ||
76 | (defvar font-lock-keyword-face 'font-lock-keyword-face | |
030f4a35 RS |
77 | "Face to use for keywords.") |
78 | ||
a1eb1cf1 | 79 | (defvar font-lock-type-face 'font-lock-type-face |
030f4a35 RS |
80 | "Face to use for data types.") |
81 | ||
a1eb1cf1 RS |
82 | (defvar font-lock-reference-face 'font-lock-reference-face |
83 | "Face to use for references.") | |
84 | ||
030f4a35 RS |
85 | (make-variable-buffer-local 'font-lock-keywords) |
86 | (defvar font-lock-keywords nil | |
d46c21ec SM |
87 | "*A list of the keywords to highlight. |
88 | Each element should be of the form: | |
a1eb1cf1 | 89 | |
826b2925 SM |
90 | MATCHER |
91 | (MATCHER . MATCH) | |
92 | (MATCHER . FACENAME) | |
93 | (MATCHER . HIGHLIGHT) | |
94 | (MATCHER HIGHLIGHT ...) | |
a1eb1cf1 RS |
95 | |
96 | where HIGHLIGHT should be of the form (MATCH FACENAME OVERRIDE LAXMATCH). | |
826b2925 SM |
97 | MATCHER can be either the regexp to search for, or the function name to call to |
98 | make the search (called with one argument, the limit of the search). MATCH is | |
99 | the subexpression of MATCHER to be highlighted. FACENAME is an expression | |
100 | whose value is the face name to use. FACENAME's default attributes may be | |
101 | defined in `font-lock-face-attributes'. | |
a1eb1cf1 RS |
102 | |
103 | OVERRIDE and LAXMATCH are flags. If OVERRIDE is t, existing fontification may | |
104 | be overriden. If `keep', only parts not already fontified are highlighted. | |
826b2925 | 105 | If LAXMATCH is non-nil, no error is signalled if there is no MATCH in MATCHER. |
a1eb1cf1 RS |
106 | |
107 | These regular expressions should not match text which spans lines. While | |
108 | \\[font-lock-fontify-buffer] handles multi-line patterns correctly, updating | |
109 | when you edit the buffer does not, since it considers text one line at a time. | |
110 | ||
111 | Be careful composing regexps for this list; | |
112 | the wrong pattern can dramatically slow things down!") | |
030f4a35 | 113 | |
b89e1134 SM |
114 | (defvar font-lock-defaults nil |
115 | "If set by a major mode, should be the defaults for Font Lock mode. | |
116 | The value should look like the `cdr' of an item in `font-lock-defaults-alist'.") | |
117 | ||
118 | (defvar font-lock-defaults-alist | |
d46c21ec SM |
119 | (let ( |
120 | ;; For C and Lisp modes we use `beginning-of-defun', rather than nil, | |
121 | ;; for SYNTAX-BEGIN. Thus the calculation of the cache is faster but | |
122 | ;; not infallible, so we risk mis-fontification. --sm | |
fb512de9 SM |
123 | (c-mode-defaults |
124 | '((c-font-lock-keywords c-font-lock-keywords-1 c-font-lock-keywords-2) | |
d46c21ec | 125 | nil nil ((?\_ . "w")) beginning-of-defun)) |
fb512de9 SM |
126 | (c++-mode-defaults |
127 | '((c++-font-lock-keywords c++-font-lock-keywords-1 | |
128 | c++-font-lock-keywords-2) | |
d46c21ec | 129 | nil nil ((?\_ . "w")) beginning-of-defun)) |
fb512de9 SM |
130 | (lisp-mode-defaults |
131 | '((lisp-font-lock-keywords lisp-font-lock-keywords-1 | |
132 | lisp-font-lock-keywords-2) | |
d46c21ec SM |
133 | nil nil ((?\: . "w") (?\- . "w") (?\* . "w")) |
134 | beginning-of-defun)) | |
135 | (scheme-mode-defaults | |
136 | '(scheme-font-lock-keywords | |
137 | nil nil ((?\: . "w") (?\- . "w") (?\* . "w") (?\/ . "w")) | |
138 | beginning-of-defun)) | |
139 | ;; For TeX modes we could use `backward-paragraph' for the same reason. | |
140 | (tex-mode-defaults '(tex-font-lock-keywords nil nil ((?\$ . "\"")))) | |
141 | ) | |
826b2925 | 142 | (list |
d46c21ec SM |
143 | (cons 'bibtex-mode tex-mode-defaults) |
144 | (cons 'c++-c-mode c-mode-defaults) | |
145 | (cons 'c++-mode c++-mode-defaults) | |
146 | (cons 'c-mode c-mode-defaults) | |
147 | (cons 'emacs-lisp-mode lisp-mode-defaults) | |
148 | (cons 'inferior-scheme-mode scheme-mode-defaults) | |
149 | (cons 'latex-mode tex-mode-defaults) | |
150 | (cons 'lisp-mode lisp-mode-defaults) | |
151 | (cons 'lisp-interaction-mode lisp-mode-defaults) | |
152 | (cons 'plain-tex-mode tex-mode-defaults) | |
153 | (cons 'scheme-mode scheme-mode-defaults) | |
154 | (cons 'scheme-interaction-mode scheme-mode-defaults) | |
155 | (cons 'slitex-mode tex-mode-defaults) | |
156 | (cons 'tex-mode tex-mode-defaults))) | |
b89e1134 SM |
157 | "*Alist of default major mode and Font Lock defaults. |
158 | Each item should be a list of the form: | |
d46c21ec SM |
159 | |
160 | (MAJOR-MODE . (KEYWORDS KEYWORDS-ONLY CASE-FOLD SYNTAX-ALIST SYNTAX-BEGIN)) | |
161 | ||
162 | where MAJOR-MODE is a symbol, and KEYWORDS may be a symbol or a list of | |
163 | symbols. If KEYWORDS-ONLY is non-nil, syntactic fontification (strings and | |
fb512de9 | 164 | comments) is not performed. If CASE-FOLD is non-nil, the case of the keywords |
d46c21ec SM |
165 | is ignored when fontifying. If SYNTAX-ALIST is non-nil, it should be a list of |
166 | cons pairs of the form (CHAR . STRING) used to set the local Font Lock syntax | |
167 | table for keyword and syntactic fontification. (See `modify-syntax-entry'.) | |
168 | ||
169 | SYNTAX-BEGIN should be a function, it is called with no args to move outside of | |
170 | a syntactic block for syntactic fontification. Typical values are nil | |
171 | \(equivalent to `beginning-of-buffer'), `beginning-of-line' (i.e., the start of | |
172 | the line is known to be outside a syntactic block), or `beginning-of-defun' for | |
173 | programming modes or `backward-paragraph' for textual modes (i.e., the | |
174 | mode-dependent function is known to move outside a syntactic block). | |
175 | ||
176 | These item elements are used by Font Lock mode to set the variables | |
177 | `font-lock-keywords', `font-lock-no-comments', | |
178 | `font-lock-keywords-case-fold-search', `font-lock-syntax-table' and | |
179 | `font-lock-beginning-of-syntax-function', respectively.") | |
180 | ||
181 | (defvar font-lock-no-comments nil | |
182 | "*Non-nil means Font Lock should not fontify comments or strings. | |
183 | This is normally set via `font-lock-defaults'.") | |
b89e1134 | 184 | |
030f4a35 | 185 | (defvar font-lock-keywords-case-fold-search nil |
d46c21ec SM |
186 | "*Non-nil means the patterns in `font-lock-keywords' are case-insensitive. |
187 | This is normally set via `font-lock-defaults'.") | |
030f4a35 | 188 | |
b056da51 | 189 | (defvar font-lock-syntax-table nil |
799761f0 | 190 | "Non-nil means use this syntax table for fontifying. |
d46c21ec SM |
191 | If this is nil, the major mode's syntax table is used. |
192 | This is normally set via `font-lock-defaults'.") | |
193 | ||
194 | (defvar font-lock-beginning-of-syntax-function nil | |
195 | "*Non-nil means use this function to move outside of a syntactic block. | |
196 | If this is nil, `beginning-of-buffer' is used. | |
197 | This is normally set via `font-lock-defaults'.") | |
b056da51 | 198 | |
030f4a35 RS |
199 | (defvar font-lock-verbose t |
200 | "*Non-nil means `font-lock-fontify-buffer' should print status messages.") | |
201 | ||
799761f0 SM |
202 | ;;;###autoload |
203 | (defvar font-lock-maximum-decoration nil | |
d46c21ec | 204 | "*If non-nil, the maximum decoration for fontifying. |
fb512de9 SM |
205 | If nil, use the default decoration (typically the minimum available). |
206 | If t, use the maximum decoration available. | |
207 | If a number, use that level of decoration (or if not available the maximum).") | |
826b2925 | 208 | |
d46c21ec | 209 | ;;;###autoload |
826b2925 SM |
210 | (defvar font-lock-maximum-size |
211 | (if font-lock-maximum-decoration (* 150 1024) (* 300 1024)) | |
d46c21ec | 212 | "*If non-nil, the maximum size for buffers for fontifying. |
826b2925 SM |
213 | Only buffers less than this can be fontified when Font Lock mode is turned on. |
214 | If nil, means size is irrelevant.") | |
799761f0 | 215 | |
60b691e2 | 216 | ;;;###autoload |
030f4a35 RS |
217 | (defvar font-lock-mode-hook nil |
218 | "Function or functions to run on entry to Font Lock mode.") | |
a1eb1cf1 RS |
219 | \f |
220 | ;; Colour etc. support. | |
221 | ||
b89e1134 | 222 | (defvar font-lock-display-type nil |
a1eb1cf1 RS |
223 | "A symbol indicating the display Emacs is running under. |
224 | The symbol should be one of `color', `grayscale' or `mono'. | |
225 | If Emacs guesses this display attribute wrongly, either set this variable in | |
b89e1134 | 226 | your `~/.emacs' or set the resource `Emacs.displayType' in your `~/.Xdefaults'. |
a1eb1cf1 RS |
227 | See also `font-lock-background-mode' and `font-lock-face-attributes'.") |
228 | ||
b89e1134 | 229 | (defvar font-lock-background-mode nil |
a1eb1cf1 RS |
230 | "A symbol indicating the Emacs background brightness. |
231 | The symbol should be one of `light' or `dark'. | |
232 | If Emacs guesses this frame attribute wrongly, either set this variable in | |
b89e1134 SM |
233 | your `~/.emacs' or set the resource `Emacs.backgroundMode' in your |
234 | `~/.Xdefaults'. | |
a1eb1cf1 RS |
235 | See also `font-lock-display-type' and `font-lock-face-attributes'.") |
236 | ||
b89e1134 | 237 | (defvar font-lock-face-attributes nil |
a1eb1cf1 RS |
238 | "A list of default attributes to use for face attributes. |
239 | Each element of the list should be of the form | |
240 | ||
241 | (FACE FOREGROUND BACKGROUND BOLD-P ITALIC-P UNDERLINE-P) | |
242 | ||
243 | where FACE should be one of the face symbols `font-lock-comment-face', | |
244 | `font-lock-string-face', `font-lock-keyword-face', `font-lock-type-face', | |
245 | `font-lock-function-name-face', `font-lock-variable-name-face', and | |
246 | `font-lock-reference-face'. A form for each of these face symbols should be | |
247 | provided in the list, but other face symbols and attributes may be given and | |
248 | used in highlighting. See `font-lock-keywords'. | |
249 | ||
250 | Subsequent element items should be the attributes for the corresponding | |
251 | Font Lock mode faces. Attributes FOREGROUND and BACKGROUND should be strings | |
252 | \(default if nil), while BOLD-P, ITALIC-P, and UNDERLINE-P should specify the | |
253 | corresponding face attributes (yes if non-nil). | |
254 | ||
255 | Emacs uses default attributes based on display type and background brightness. | |
256 | See variables `font-lock-display-type' and `font-lock-background-mode'. | |
257 | ||
258 | Resources can be used to over-ride these face attributes. For example, the | |
259 | resource `Emacs.font-lock-comment-face.attributeUnderline' can be used to | |
260 | specify the UNDERLINE-P attribute for face `font-lock-comment-face'.") | |
261 | ||
8862b0db | 262 | (defun font-lock-make-faces (&optional override) |
b89e1134 SM |
263 | "Make faces from `font-lock-face-attributes'. |
264 | A default list is used if this is nil. | |
8862b0db | 265 | If optional OVERRIDE is non-nil, faces that already exist are reset. |
b89e1134 SM |
266 | See `font-lock-make-face' and `list-faces-display'." |
267 | ;; We don't need to `setq' any of these variables, but the user can see what | |
268 | ;; is being used if we do. | |
269 | (if (null font-lock-display-type) | |
270 | (setq font-lock-display-type | |
271 | (let ((display-resource (x-get-resource ".displayType" | |
272 | "DisplayType"))) | |
273 | (cond (display-resource (intern (downcase display-resource))) | |
274 | ((x-display-color-p) 'color) | |
275 | ((x-display-grayscale-p) 'grayscale) | |
276 | (t 'mono))))) | |
277 | (if (null font-lock-background-mode) | |
278 | (setq font-lock-background-mode | |
279 | (let ((bg-resource (x-get-resource ".backgroundMode" | |
280 | "BackgroundMode")) | |
281 | (params (frame-parameters))) | |
282 | (cond (bg-resource (intern (downcase bg-resource))) | |
61392e7b RS |
283 | ((< (apply '+ (x-color-values |
284 | (cdr (assq 'background-color params)))) | |
285 | (/ (apply '+ (x-color-values "white")) 3)) | |
b89e1134 SM |
286 | 'dark) |
287 | (t 'light))))) | |
288 | (if (null font-lock-face-attributes) | |
289 | (setq font-lock-face-attributes | |
290 | (let ((light-bg (eq font-lock-background-mode 'light))) | |
291 | (cond ((memq font-lock-display-type '(mono monochrome)) | |
292 | ;; Emacs 19.25's font-lock defaults: | |
293 | ;;'((font-lock-comment-face nil nil nil t nil) | |
294 | ;; (font-lock-string-face nil nil nil nil t) | |
295 | ;; (font-lock-keyword-face nil nil t nil nil) | |
296 | ;; (font-lock-function-name-face nil nil t t nil) | |
297 | ;; (font-lock-type-face nil nil nil t nil)) | |
298 | (list '(font-lock-comment-face nil nil t t nil) | |
299 | '(font-lock-string-face nil nil nil t nil) | |
300 | '(font-lock-keyword-face nil nil t nil nil) | |
301 | (list | |
302 | 'font-lock-function-name-face | |
303 | (cdr (assq 'background-color (frame-parameters))) | |
304 | (cdr (assq 'foreground-color (frame-parameters))) | |
305 | t nil nil) | |
306 | '(font-lock-variable-name-face nil nil t t nil) | |
307 | '(font-lock-type-face nil nil t nil t) | |
308 | '(font-lock-reference-face nil nil t nil t))) | |
309 | ((memq font-lock-display-type '(grayscale greyscale | |
310 | grayshade greyshade)) | |
311 | (list | |
312 | (list 'font-lock-comment-face | |
4d8765a2 | 313 | nil (if light-bg "Gray80" "DimGray") t t nil) |
b89e1134 | 314 | (list 'font-lock-string-face |
4d8765a2 | 315 | nil (if light-bg "Gray50" "LightGray") nil t nil) |
b89e1134 | 316 | (list 'font-lock-keyword-face |
4d8765a2 | 317 | nil (if light-bg "Gray90" "DimGray") t nil nil) |
b89e1134 SM |
318 | (list 'font-lock-function-name-face |
319 | (cdr (assq 'background-color (frame-parameters))) | |
320 | (cdr (assq 'foreground-color (frame-parameters))) | |
321 | t nil nil) | |
322 | (list 'font-lock-variable-name-face | |
4d8765a2 | 323 | nil (if light-bg "Gray90" "DimGray") t t nil) |
b89e1134 | 324 | (list 'font-lock-type-face |
4d8765a2 | 325 | nil (if light-bg "Gray80" "DimGray") t nil t) |
0caef3e3 | 326 | (list 'font-lock-reference-face |
4d8765a2 | 327 | nil (if light-bg "LightGray" "Gray50") t nil t))) |
b89e1134 SM |
328 | (light-bg ; light colour background |
329 | '((font-lock-comment-face "Firebrick") | |
330 | (font-lock-string-face "RosyBrown") | |
331 | (font-lock-keyword-face "Purple") | |
332 | (font-lock-function-name-face "Blue") | |
333 | (font-lock-variable-name-face "DarkGoldenrod") | |
334 | (font-lock-type-face "DarkOliveGreen") | |
335 | (font-lock-reference-face "CadetBlue"))) | |
336 | (t ; dark colour background | |
337 | '((font-lock-comment-face "OrangeRed") | |
338 | (font-lock-string-face "LightSalmon") | |
339 | (font-lock-keyword-face "LightSteelBlue") | |
340 | (font-lock-function-name-face "LightSkyBlue") | |
341 | (font-lock-variable-name-face "LightGoldenrod") | |
342 | (font-lock-type-face "PaleGreen") | |
343 | (font-lock-reference-face "Aquamarine"))))))) | |
8862b0db | 344 | ;; Now make the faces if we have to. |
d46c21ec SM |
345 | (mapcar (function |
346 | (lambda (face-attributes) | |
8862b0db | 347 | (let ((face (nth 0 face-attributes))) |
d46c21ec SM |
348 | (cond (override |
349 | ;; We can stomp all over it anyway. Get outta my face! | |
350 | (font-lock-make-face face-attributes)) | |
351 | ((and (boundp face) (facep (symbol-value face))) | |
352 | ;; The variable exists and is already bound to a face. | |
353 | nil) | |
354 | ((facep face) | |
355 | ;; We already have a face so we bind the variable to it. | |
356 | (set face face)) | |
357 | (t | |
358 | ;; No variable or no face. | |
359 | (font-lock-make-face face-attributes)))))) | |
8862b0db | 360 | font-lock-face-attributes)) |
b89e1134 | 361 | |
a1eb1cf1 RS |
362 | (defun font-lock-make-face (face-attributes) |
363 | "Make a face from FACE-ATTRIBUTES. | |
364 | FACE-ATTRIBUTES should be like an element `font-lock-face-attributes', so that | |
365 | the face name is the first item in the list. A variable with the same name as | |
366 | the face is also set; its value is the face name." | |
367 | (let* ((face (nth 0 face-attributes)) | |
368 | (face-name (symbol-name face)) | |
369 | (set-p (function (lambda (face-name resource) | |
370 | (x-get-resource (concat face-name ".attribute" resource) | |
371 | (concat "Face.Attribute" resource))))) | |
372 | (on-p (function (lambda (face-name resource) | |
373 | (let ((set (funcall set-p face-name resource))) | |
374 | (and set (member (downcase set) '("on" "true")))))))) | |
375 | (make-face face) | |
376 | ;; Set attributes not set from X resources (and therefore `make-face'). | |
377 | (or (funcall set-p face-name "Foreground") | |
378 | (condition-case nil | |
379 | (set-face-foreground face (nth 1 face-attributes)) | |
380 | (error nil))) | |
381 | (or (funcall set-p face-name "Background") | |
382 | (condition-case nil | |
383 | (set-face-background face (nth 2 face-attributes)) | |
384 | (error nil))) | |
385 | (if (funcall set-p face-name "Bold") | |
386 | (and (funcall on-p face-name "Bold") (make-face-bold face nil t)) | |
387 | (and (nth 3 face-attributes) (make-face-bold face nil t))) | |
388 | (if (funcall set-p face-name "Italic") | |
389 | (and (funcall on-p face-name "Italic") (make-face-italic face nil t)) | |
390 | (and (nth 4 face-attributes) (make-face-italic face nil t))) | |
391 | (or (funcall set-p face-name "Underline") | |
392 | (set-face-underline-p face (nth 5 face-attributes))) | |
393 | (set face face))) | |
394 | \f | |
395 | ;; Fontification. | |
030f4a35 | 396 | |
a1eb1cf1 RS |
397 | ;; These variables record, for each buffer, the parse state at a particular |
398 | ;; position, always the start of a line. Used to make font-lock-fontify-region | |
399 | ;; faster. | |
030f4a35 RS |
400 | (defvar font-lock-cache-position nil) |
401 | (defvar font-lock-cache-state nil) | |
402 | (make-variable-buffer-local 'font-lock-cache-position) | |
403 | (make-variable-buffer-local 'font-lock-cache-state) | |
404 | ||
a1eb1cf1 | 405 | (defun font-lock-fontify-region (start end &optional loudly) |
030f4a35 RS |
406 | "Put proper face on each string and comment between START and END." |
407 | (save-excursion | |
a1eb1cf1 RS |
408 | (save-restriction |
409 | (widen) | |
410 | (goto-char start) | |
411 | (beginning-of-line) | |
412 | (if loudly (message "Fontifying %s... (syntactically...)" (buffer-name))) | |
d46c21ec SM |
413 | (let ((inhibit-read-only t) (buffer-undo-list t) |
414 | buffer-file-name buffer-file-truename | |
a1eb1cf1 | 415 | (modified (buffer-modified-p)) |
826b2925 | 416 | (old-syntax (syntax-table)) |
799761f0 SM |
417 | (synstart (if comment-start-skip |
418 | (concat "\\s\"\\|" comment-start-skip) | |
419 | "\\s\"")) | |
420 | (comstart (if comment-start-skip | |
421 | (concat "\\s<\\|" comment-start-skip) | |
422 | "\\s<")) | |
a1eb1cf1 RS |
423 | (startline (point)) |
424 | state prev prevstate) | |
826b2925 SM |
425 | (unwind-protect |
426 | (progn | |
d46c21ec SM |
427 | ;; |
428 | ;; Use the fontification syntax table, if any. | |
826b2925 SM |
429 | (if font-lock-syntax-table |
430 | (set-syntax-table font-lock-syntax-table)) | |
d46c21ec SM |
431 | ;; |
432 | ;; Find the state at the `beginning-of-line' before `start'. | |
826b2925 | 433 | (if (eq startline font-lock-cache-position) |
d46c21ec | 434 | ;; Use the cache for the state of `startline'. |
826b2925 | 435 | (setq state font-lock-cache-state) |
d46c21ec SM |
436 | ;; Find the state of `startline'. |
437 | (if (null font-lock-beginning-of-syntax-function) | |
438 | ;; Use the state at the previous cache position, if any, or | |
439 | ;; otherwise calculate from `point-min'. | |
440 | (if (or (null font-lock-cache-position) | |
441 | (< startline font-lock-cache-position)) | |
442 | (setq state (parse-partial-sexp | |
443 | (point-min) startline)) | |
444 | (setq state (parse-partial-sexp | |
445 | font-lock-cache-position startline | |
446 | nil nil font-lock-cache-state))) | |
447 | ;; Call the function to move outside any syntactic block. | |
448 | (funcall font-lock-beginning-of-syntax-function) | |
449 | (setq state (parse-partial-sexp (point) startline))) | |
450 | ;; Cache the state and position of `startline'. | |
826b2925 | 451 | (setq font-lock-cache-state state |
d46c21ec SM |
452 | font-lock-cache-position startline)) |
453 | ;; | |
454 | ;; Now find the state at `start' based on that of `startline'. | |
455 | (setq state (parse-partial-sexp startline start nil nil state)) | |
456 | ;; | |
826b2925 | 457 | ;; If the region starts inside a string, show the extent of it. |
a1eb1cf1 | 458 | (if (nth 3 state) |
826b2925 | 459 | (let ((beg (point))) |
a1eb1cf1 | 460 | (while (and (re-search-forward "\\s\"" end 'move) |
826b2925 | 461 | (nth 3 (parse-partial-sexp beg (point) nil nil |
b89e1134 | 462 | state)))) |
a1eb1cf1 | 463 | (put-text-property beg (point) 'face font-lock-string-face) |
826b2925 SM |
464 | (setq state (parse-partial-sexp beg (point) |
465 | nil nil state)))) | |
d46c21ec | 466 | ;; |
826b2925 SM |
467 | ;; Likewise for a comment. |
468 | (if (or (nth 4 state) (nth 7 state)) | |
469 | (let ((beg (point))) | |
470 | (save-restriction | |
471 | (narrow-to-region (point-min) end) | |
472 | (condition-case nil | |
473 | (progn | |
474 | (re-search-backward comstart (point-min) 'move) | |
475 | (forward-comment 1) | |
476 | ;; forward-comment skips all whitespace, | |
477 | ;; so go back to the real end of the comment. | |
478 | (skip-chars-backward " \t")) | |
479 | (error (goto-char end)))) | |
480 | (put-text-property beg (point) 'face | |
481 | font-lock-comment-face) | |
482 | (setq state (parse-partial-sexp beg (point) | |
483 | nil nil state)))) | |
d46c21ec SM |
484 | ;; |
485 | ;; Find each interesting place between here and `end'. | |
826b2925 SM |
486 | (while (and (< (point) end) |
487 | (setq prev (point) prevstate state) | |
488 | (re-search-forward synstart end t) | |
489 | (progn | |
490 | ;; Clear out the fonts of what we skip over. | |
491 | (remove-text-properties prev (point) '(face nil)) | |
492 | ;; Verify the state at that place | |
493 | ;; so we don't get fooled by \" or \;. | |
494 | (setq state (parse-partial-sexp prev (point) | |
495 | nil nil state)))) | |
496 | (let ((here (point))) | |
497 | (if (or (nth 4 state) (nth 7 state)) | |
d46c21ec | 498 | ;; |
826b2925 SM |
499 | ;; We found a real comment start. |
500 | (let ((beg (match-beginning 0))) | |
501 | (goto-char beg) | |
502 | (save-restriction | |
503 | (narrow-to-region (point-min) end) | |
504 | (condition-case nil | |
505 | (progn | |
506 | (forward-comment 1) | |
507 | ;; forward-comment skips all whitespace, | |
508 | ;; so go back to the real end of the comment. | |
509 | (skip-chars-backward " \t")) | |
510 | (error (goto-char end)))) | |
511 | (put-text-property beg (point) 'face | |
512 | font-lock-comment-face) | |
513 | (setq state (parse-partial-sexp here (point) | |
514 | nil nil state))) | |
515 | (if (nth 3 state) | |
d46c21ec SM |
516 | ;; |
517 | ;; We found a real string start. | |
826b2925 SM |
518 | (let ((beg (match-beginning 0))) |
519 | (while (and (re-search-forward "\\s\"" end 'move) | |
520 | (nth 3 (parse-partial-sexp | |
521 | here (point) nil nil state)))) | |
522 | (put-text-property beg (point) 'face | |
523 | font-lock-string-face) | |
524 | (setq state (parse-partial-sexp here (point) | |
525 | nil nil state)))))) | |
d46c21ec SM |
526 | ;; |
527 | ;; Make sure `prev' is non-nil after the loop | |
826b2925 SM |
528 | ;; only if it was set on the very last iteration. |
529 | (setq prev nil))) | |
d46c21ec SM |
530 | ;; |
531 | ;; Clean up. | |
bda60941 SM |
532 | (set-syntax-table old-syntax) |
533 | (and prev | |
534 | (remove-text-properties prev end '(face nil))) | |
535 | (and (buffer-modified-p) | |
536 | (not modified) | |
537 | (set-buffer-modified-p nil))))))) | |
030f4a35 | 538 | |
030f4a35 | 539 | (defun font-lock-unfontify-region (beg end) |
313d590c | 540 | (let ((modified (buffer-modified-p)) |
d46c21ec SM |
541 | (buffer-undo-list t) (inhibit-read-only t) |
542 | buffer-file-name buffer-file-truename) | |
313d590c | 543 | (remove-text-properties beg end '(face nil)) |
826b2925 SM |
544 | (and (buffer-modified-p) |
545 | (not modified) | |
546 | (set-buffer-modified-p nil)))) | |
030f4a35 RS |
547 | |
548 | ;; Called when any modification is made to buffer text. | |
549 | (defun font-lock-after-change-function (beg end old-len) | |
550 | (save-excursion | |
551 | (save-match-data | |
030f4a35 RS |
552 | ;; Discard the cache info if text before it has changed. |
553 | (and font-lock-cache-position | |
554 | (> font-lock-cache-position beg) | |
555 | (setq font-lock-cache-position nil)) | |
a1eb1cf1 | 556 | ;; Rescan between start of line from `beg' and start of line after `end'. |
030f4a35 RS |
557 | (goto-char beg) |
558 | (beginning-of-line) | |
559 | (setq beg (point)) | |
a1eb1cf1 RS |
560 | (goto-char end) |
561 | (forward-line 1) | |
562 | (setq end (point)) | |
1ec9e15b RS |
563 | ;; First scan for strings and comments. |
564 | ;; Must scan from line start in case of | |
a1eb1cf1 | 565 | ;; inserting space into `intfoo () {}', and after widened. |
8f261d40 | 566 | (if font-lock-no-comments |
826b2925 | 567 | (font-lock-unfontify-region beg end) |
a1eb1cf1 | 568 | (font-lock-fontify-region beg end)) |
799761f0 | 569 | ;; Now scan for keywords. |
9e116f87 SM |
570 | (font-lock-hack-keywords beg end)))) |
571 | ||
826b2925 | 572 | ;; The following must be rethought, since keywords can override fontification. |
9e116f87 SM |
573 | ; ;; Now scan for keywords, but not if we are inside a comment now. |
574 | ; (or (and (not font-lock-no-comments) | |
575 | ; (let ((state (parse-partial-sexp beg end nil nil | |
576 | ; font-lock-cache-state))) | |
577 | ; (or (nth 4 state) (nth 7 state)))) | |
578 | ; (font-lock-hack-keywords beg end)) | |
030f4a35 RS |
579 | \f |
580 | ;;; Fontifying arbitrary patterns | |
581 | ||
52436656 | 582 | (defun font-lock-compile-keywords (&optional keywords) |
826b2925 SM |
583 | ;; Compile `font-lock-keywords' into the form (t KEYWORD ...) where KEYWORD |
584 | ;; is the (MATCHER HIGHLIGHT ...) shown in the variable's doc string. | |
52436656 SM |
585 | (let ((keywords (or keywords font-lock-keywords))) |
586 | (setq font-lock-keywords | |
587 | (if (eq (car-safe keywords) t) | |
588 | keywords | |
589 | (cons t | |
590 | (mapcar | |
591 | (function (lambda (item) | |
592 | (cond ((nlistp item) | |
593 | (list item '(0 font-lock-keyword-face))) | |
594 | ((numberp (cdr item)) | |
595 | (list (car item) (list (cdr item) 'font-lock-keyword-face))) | |
596 | ((symbolp (cdr item)) | |
597 | (list (car item) (list 0 (cdr item)))) | |
598 | ((nlistp (nth 1 item)) | |
599 | (list (car item) (cdr item))) | |
600 | (t | |
601 | item)))) | |
602 | keywords)))))) | |
826b2925 SM |
603 | |
604 | (defsubst font-lock-apply-highlight (highlight) | |
605 | "Apply HIGHLIGHT following a match. See `font-lock-keywords'." | |
606 | (let* ((match (nth 0 highlight)) | |
607 | (beg (match-beginning match)) (end (match-end match)) | |
608 | (override (nth 2 highlight))) | |
609 | (cond ((not beg) | |
610 | ;; No match but we might not signal an error | |
611 | (or (nth 3 highlight) (error "Highlight %S failed" highlight))) | |
612 | ((and (not override) (text-property-not-all beg end 'face nil)) | |
613 | ;; Can't override and already fontified | |
614 | nil) | |
615 | ((not (eq override 'keep)) | |
616 | ;; Can override but need not keep existing fontification | |
617 | (put-text-property beg end 'face (eval (nth 1 highlight)))) | |
618 | (t | |
619 | ;; Can override but must keep existing fontification | |
620 | (let ((pos (text-property-any beg end 'face nil)) next | |
621 | (face (eval (nth 1 highlight)))) | |
622 | (while pos | |
623 | (setq next (next-single-property-change pos 'face nil end)) | |
624 | (put-text-property pos next 'face face) | |
625 | (setq pos (text-property-any next end 'face nil)))))))) | |
626 | ||
030f4a35 | 627 | (defun font-lock-hack-keywords (start end &optional loudly) |
a1eb1cf1 | 628 | "Fontify according to `font-lock-keywords' between START and END." |
030f4a35 | 629 | (let ((case-fold-search font-lock-keywords-case-fold-search) |
826b2925 SM |
630 | (keywords (cdr (if (eq (car-safe font-lock-keywords) t) |
631 | font-lock-keywords | |
632 | (font-lock-compile-keywords)))) | |
030f4a35 | 633 | (count 0) |
d46c21ec SM |
634 | (inhibit-read-only t) (buffer-undo-list t) |
635 | buffer-file-name buffer-file-truename | |
313d590c | 636 | (modified (buffer-modified-p)) |
a1eb1cf1 RS |
637 | (old-syntax (syntax-table)) |
638 | (bufname (buffer-name))) | |
b056da51 | 639 | (unwind-protect |
d46c21ec | 640 | (let (keyword matcher highlights lowdarks) |
a1eb1cf1 RS |
641 | (if loudly (message "Fontifying %s... (regexps...)" bufname)) |
642 | (if font-lock-syntax-table (set-syntax-table font-lock-syntax-table)) | |
643 | (while keywords | |
644 | (setq keyword (car keywords) keywords (cdr keywords) | |
826b2925 | 645 | matcher (car keyword) highlights (cdr keyword)) |
b056da51 | 646 | (goto-char start) |
826b2925 SM |
647 | (while (if (stringp matcher) |
648 | (re-search-forward matcher end t) | |
649 | (funcall matcher end)) | |
d46c21ec SM |
650 | ;; An explicit `while' loop is slightly faster than a `mapcar'. |
651 | ;(mapcar 'font-lock-apply-highlight highlights) | |
652 | (setq lowdarks highlights) | |
653 | (while lowdarks | |
654 | (font-lock-apply-highlight (car lowdarks)) | |
655 | (setq lowdarks (cdr lowdarks)))) | |
a1eb1cf1 | 656 | (if loudly (message "Fontifying %s... (regexps...%s)" bufname |
b056da51 | 657 | (make-string (setq count (1+ count)) ?.))))) |
bda60941 SM |
658 | (set-syntax-table old-syntax) |
659 | (and (buffer-modified-p) | |
660 | (not modified) | |
661 | (set-buffer-modified-p nil))))) | |
030f4a35 RS |
662 | \f |
663 | ;; The user level functions | |
664 | ||
665 | (defvar font-lock-mode nil) ; for modeline | |
030f4a35 RS |
666 | |
667 | (defvar font-lock-fontified nil) ; whether we have hacked this buffer | |
668 | (put 'font-lock-fontified 'permanent-local t) | |
669 | ||
670 | ;;;###autoload | |
671 | (defun font-lock-mode (&optional arg) | |
672 | "Toggle Font Lock mode. | |
673 | With arg, turn Font Lock mode on if and only if arg is positive. | |
674 | ||
675 | When Font Lock mode is enabled, text is fontified as you type it: | |
676 | ||
a1eb1cf1 RS |
677 | - Comments are displayed in `font-lock-comment-face'; |
678 | - Strings are displayed in `font-lock-string-face'; | |
679 | - Certain other expressions are displayed in other faces according to the | |
680 | value of the variable `font-lock-keywords'. | |
681 | ||
682 | You can enable Font Lock mode in any major mode automatically by turning on in | |
683 | the major mode's hook. For example, put in your ~/.emacs: | |
684 | ||
685 | (add-hook 'c-mode-hook 'turn-on-font-lock) | |
686 | ||
687 | Or for any visited file with the following in your ~/.emacs: | |
688 | ||
689 | (add-hook 'find-file-hooks 'turn-on-font-lock) | |
690 | ||
691 | The default Font Lock mode faces and their attributes are defined in the | |
692 | variable `font-lock-face-attributes', and Font Lock mode default settings in | |
693 | the variable `font-lock-defaults-alist'. | |
030f4a35 | 694 | |
826b2925 | 695 | Where modes support different levels of fontification, you can use the variable |
fb512de9 | 696 | `font-lock-maximum-decoration' to specify which level you generally prefer. |
b89e1134 SM |
697 | When you turn Font Lock mode on/off the buffer is fontified/defontified, though |
698 | fontification occurs only if the buffer is less than `font-lock-maximum-size'. | |
699 | To fontify a buffer without turning on Font Lock mode, and regardless of buffer | |
700 | size, you can use \\[font-lock-fontify-buffer]." | |
030f4a35 | 701 | (interactive "P") |
a1eb1cf1 | 702 | (let ((on-p (if arg (> (prefix-numeric-value arg) 0) (not font-lock-mode)))) |
030f4a35 RS |
703 | (if (equal (buffer-name) " *Compiler Input*") ; hack for bytecomp... |
704 | (setq on-p nil)) | |
a1eb1cf1 RS |
705 | (if (not on-p) |
706 | (remove-hook 'after-change-functions 'font-lock-after-change-function) | |
707 | (make-local-variable 'after-change-functions) | |
708 | (add-hook 'after-change-functions 'font-lock-after-change-function)) | |
030f4a35 RS |
709 | (set (make-local-variable 'font-lock-mode) on-p) |
710 | (cond (on-p | |
711 | (font-lock-set-defaults) | |
7daa8d6b | 712 | (make-local-variable 'before-revert-hook) |
87cd38d6 | 713 | (make-local-variable 'after-revert-hook) |
7daa8d6b KH |
714 | ;; If buffer is reverted, must clean up the state. |
715 | (add-hook 'before-revert-hook 'font-lock-revert-setup) | |
716 | (add-hook 'after-revert-hook 'font-lock-revert-cleanup) | |
030f4a35 | 717 | (run-hooks 'font-lock-mode-hook) |
b89e1134 SM |
718 | (cond (font-lock-fontified |
719 | nil) | |
720 | ((or (null font-lock-maximum-size) | |
721 | (> font-lock-maximum-size (buffer-size))) | |
722 | (font-lock-fontify-buffer)) | |
723 | (font-lock-verbose | |
724 | (message "Fontifying %s... buffer too big." (buffer-name))))) | |
030f4a35 RS |
725 | (font-lock-fontified |
726 | (setq font-lock-fontified nil) | |
7daa8d6b KH |
727 | (remove-hook 'before-revert-hook 'font-lock-revert-setup) |
728 | (remove-hook 'after-revert-hook 'font-lock-revert-cleanup) | |
799761f0 SM |
729 | (font-lock-unfontify-region (point-min) (point-max)) |
730 | (font-lock-thing-lock-cleanup)) | |
731 | (t | |
800479f5 KH |
732 | (remove-hook 'before-revert-hook 'font-lock-revert-setup) |
733 | (remove-hook 'after-revert-hook 'font-lock-revert-cleanup) | |
799761f0 | 734 | (font-lock-thing-lock-cleanup))) |
030f4a35 RS |
735 | (force-mode-line-update))) |
736 | ||
a1eb1cf1 RS |
737 | ;;;###autoload |
738 | (defun turn-on-font-lock () | |
739 | "Unconditionally turn on Font Lock mode." | |
740 | (font-lock-mode 1)) | |
741 | ||
bda60941 | 742 | ;; Turn off other related packages if they're on. I prefer a hook. --sm. |
800479f5 KH |
743 | ;; These explicit calls are easier to understand |
744 | ;; because people know what they will do. | |
bda60941 | 745 | ;; A hook is a mystery because it might do anything whatever. --rms. |
799761f0 SM |
746 | (defun font-lock-thing-lock-cleanup () |
747 | (cond ((and (boundp 'fast-lock-mode) fast-lock-mode) | |
748 | (fast-lock-mode -1)) | |
749 | ((and (boundp 'lazy-lock-mode) lazy-lock-mode) | |
750 | (lazy-lock-mode -1)))) | |
751 | ||
826b2925 SM |
752 | ;; Do something special for these packages after fontifying. I prefer a hook. |
753 | (defun font-lock-after-fontify-buffer () | |
754 | (cond ((and (boundp 'fast-lock-mode) fast-lock-mode) | |
755 | (fast-lock-after-fontify-buffer)) | |
756 | ((and (boundp 'lazy-lock-mode) lazy-lock-mode) | |
757 | (lazy-lock-after-fontify-buffer)))) | |
758 | ||
800479f5 | 759 | ;; If the buffer is about to be reverted, it won't be fontified afterward. |
7daa8d6b KH |
760 | (defun font-lock-revert-setup () |
761 | (setq font-lock-fontified nil)) | |
762 | ||
800479f5 KH |
763 | ;; If the buffer has just been reverted, normally that turns off |
764 | ;; Font Lock mode. So turn the mode back on if necessary. | |
7daa8d6b | 765 | (defun font-lock-revert-cleanup () |
800479f5 | 766 | (font-lock-mode 1)) |
7daa8d6b | 767 | |
a1eb1cf1 | 768 | ;;;###autoload |
030f4a35 | 769 | (defun font-lock-fontify-buffer () |
a1eb1cf1 | 770 | "Fontify the current buffer the way `font-lock-mode' would." |
030f4a35 RS |
771 | (interactive) |
772 | (let ((was-on font-lock-mode) | |
826b2925 SM |
773 | (verbose (and (or font-lock-verbose (interactive-p)) |
774 | (not (zerop (buffer-size))))) | |
a1eb1cf1 | 775 | (modified (buffer-modified-p))) |
b89e1134 | 776 | (set (make-local-variable 'font-lock-fontified) nil) |
a1eb1cf1 | 777 | (if verbose (message "Fontifying %s..." (buffer-name))) |
b89e1134 | 778 | ;; Turn it on to run hooks and get the right `font-lock-keywords' etc. |
366b3ecc | 779 | (or was-on (font-lock-set-defaults)) |
a1eb1cf1 RS |
780 | (condition-case nil |
781 | (save-excursion | |
799761f0 SM |
782 | (if font-lock-no-comments |
783 | (font-lock-unfontify-region (point-min) (point-max)) | |
784 | (font-lock-fontify-region (point-min) (point-max) verbose)) | |
a1eb1cf1 RS |
785 | (font-lock-hack-keywords (point-min) (point-max) verbose) |
786 | (setq font-lock-fontified t)) | |
787 | ;; We don't restore the old fontification, so it's best to unfontify. | |
b89e1134 | 788 | (quit (font-lock-unfontify-region (point-min) (point-max)))) |
a1eb1cf1 RS |
789 | (if verbose (message "Fontifying %s... %s." (buffer-name) |
790 | (if font-lock-fontified "done" "aborted"))) | |
791 | (and (buffer-modified-p) | |
792 | (not modified) | |
799761f0 | 793 | (set-buffer-modified-p nil)) |
826b2925 | 794 | (font-lock-after-fontify-buffer))) |
d46c21ec SM |
795 | |
796 | (defun font-lock-choose-keywords (keywords level) | |
797 | ;; Return LEVELth element of KEYWORDS. A LEVEL of nil is equal to a | |
798 | ;; LEVEL of 0, a LEVEL of t is equal to (1- (length KEYWORDS)). | |
799 | (cond ((symbolp keywords) | |
800 | keywords) | |
801 | ((numberp level) | |
802 | (or (nth level keywords) (car (reverse keywords)))) | |
803 | ((eq level t) | |
804 | (car (reverse keywords))) | |
805 | (t | |
806 | (car keywords)))) | |
807 | ||
808 | (defun font-lock-set-defaults () | |
809 | "Set fontification defaults appropriately for this mode. | |
810 | Sets `font-lock-keywords', `font-lock-no-comments', `font-lock-syntax-table' | |
811 | and `font-lock-keywords-case-fold-search' using `font-lock-defaults' (or, if | |
812 | nil, using `font-lock-defaults-alist') and `font-lock-maximum-decoration'." | |
813 | ;; Set face defaults. | |
814 | (font-lock-make-faces) | |
815 | ;; Set fontification defaults. | |
816 | (or font-lock-keywords | |
817 | (let ((defaults (or font-lock-defaults | |
818 | (cdr (assq major-mode font-lock-defaults-alist))))) | |
819 | ;; Keywords? | |
820 | (setq font-lock-keywords | |
821 | (font-lock-compile-keywords | |
822 | (eval (font-lock-choose-keywords (nth 0 defaults) | |
823 | font-lock-maximum-decoration)))) | |
824 | ;; Syntactic? | |
825 | (if (nth 1 defaults) | |
826 | (set (make-local-variable 'font-lock-no-comments) t)) | |
827 | ;; Case fold? | |
828 | (if (nth 2 defaults) | |
829 | (set (make-local-variable 'font-lock-keywords-case-fold-search) t)) | |
830 | ;; Syntax table? | |
831 | (if (nth 3 defaults) | |
832 | (let ((slist (nth 3 defaults))) | |
833 | (set (make-local-variable 'font-lock-syntax-table) | |
834 | (copy-syntax-table (syntax-table))) | |
835 | (while slist | |
836 | (modify-syntax-entry (car (car slist)) (cdr (car slist)) | |
837 | font-lock-syntax-table) | |
838 | (setq slist (cdr slist))))) | |
839 | ;; Syntactic cache function? | |
840 | (if (nth 4 defaults) | |
841 | (set (make-local-variable 'font-lock-beginning-of-syntax-function) | |
842 | (nth 4 defaults)))))) | |
030f4a35 | 843 | \f |
a1eb1cf1 RS |
844 | ;;; Various information shared by several modes. |
845 | ;;; Information specific to a single mode should go in its load library. | |
030f4a35 | 846 | |
030f4a35 | 847 | (defconst lisp-font-lock-keywords-1 |
a1eb1cf1 | 848 | (list |
d46c21ec SM |
849 | ;; Everything not a variable or type declaration is fontified as a function. |
850 | ;; It would be cleaner to allow preceding whitespace, but it would also be | |
851 | ;; about five times slower. | |
852 | (list (concat "^(\\(def\\(" | |
853 | ;; Variable declarations. | |
854 | "\\(const\\(\\|ant\\)\\|ine-key\\(\\|-after\\)\\|var\\)\\|" | |
855 | ;; Structure declarations. | |
856 | "\\(class\\|struct\\|type\\)\\|" | |
857 | ;; Everything else is a function declaration. | |
858 | "\\([^ \t\n\(\)]+\\)" | |
859 | "\\)\\)\\>" | |
860 | ;; Any whitespace and declared object. | |
861 | "[ \t'\(]*" | |
862 | "\\([^ \t\n\)]+\\)?") | |
863 | '(1 font-lock-keyword-face) | |
864 | '(8 (cond ((match-beginning 3) font-lock-variable-name-face) | |
865 | ((match-beginning 6) font-lock-type-face) | |
866 | (t font-lock-function-name-face)) | |
867 | nil t))) | |
fb512de9 | 868 | "Subdued level highlighting Lisp modes.") |
030f4a35 RS |
869 | |
870 | (defconst lisp-font-lock-keywords-2 | |
799761f0 SM |
871 | (append lisp-font-lock-keywords-1 |
872 | (let ((word-char "[-+a-zA-Z0-9_:*]")) | |
873 | (list | |
874 | ;; | |
bda60941 | 875 | ;; Control structures. ELisp and CLisp combined. |
d46c21ec SM |
876 | ; (make-regexp |
877 | ; '("cond" "if" "while" "let\\*?" "prog[nv12*]?" "catch" "throw" | |
878 | ; "save-restriction" "save-excursion" "save-window-excursion" | |
879 | ; "save-selected-window" "save-match-data" "unwind-protect" | |
880 | ; "condition-case" "track-mouse" | |
881 | ; "eval-after-load" "eval-and-compile" "eval-when-compile" | |
882 | ; "when" "unless" "do" "flet" "labels" "return" "return-from")) | |
799761f0 SM |
883 | (cons |
884 | (concat | |
885 | "(\\(" | |
d46c21ec SM |
886 | "\\(c\\(atch\\|ond\\(\\|ition-case\\)\\)\\|do\\|" |
887 | "eval-\\(a\\(fter-load\\|nd-compile\\)\\|when-compile\\)\\|flet\\|" | |
888 | "if\\|l\\(abels\\|et\\*?\\)\\|prog[nv12*]?\\|return\\(\\|-from\\)\\|" | |
889 | "save-\\(excursion\\|match-data\\|restriction\\|selected-window\\|" | |
890 | "window-excursion\\)\\|t\\(hrow\\|rack-mouse\\)\\|" | |
891 | "un\\(less\\|wind-protect\\)\\|wh\\(en\\|ile\\)\\)" | |
799761f0 | 892 | "\\)\\>") 1) |
799761f0 SM |
893 | ;; |
894 | ;; Function names in emacs-lisp docstrings (in the syntax that | |
895 | ;; `substitute-command-keys' understands). | |
826b2925 SM |
896 | (list (concat "\\\\\\\\\\[\\(" word-char "+\\)]") |
897 | 1 font-lock-reference-face t) | |
799761f0 SM |
898 | ;; |
899 | ;; Words inside `' which tend to be symbol names. | |
a1eb1cf1 | 900 | (list (concat "`\\(" word-char word-char "+\\)'") |
799761f0 SM |
901 | 1 'font-lock-reference-face t) |
902 | ;; | |
bda60941 SM |
903 | ;; CLisp `:' keywords as references. |
904 | (list (concat "\\<:" word-char "+\\>") 0 font-lock-reference-face t) | |
905 | ;; | |
906 | ;; ELisp and CLisp `&' keywords as types. | |
799761f0 SM |
907 | '("\\&\\(optional\\|rest\\|whole\\)\\>" . font-lock-type-face) |
908 | ))) | |
fb512de9 | 909 | "Gaudy level highlighting for Lisp modes.") |
030f4a35 | 910 | |
fb512de9 SM |
911 | (defvar lisp-font-lock-keywords lisp-font-lock-keywords-1 |
912 | "Default expressions to highlight in Lisp modes.") | |
030f4a35 RS |
913 | |
914 | ||
d46c21ec SM |
915 | (defvar scheme-font-lock-keywords |
916 | (list | |
917 | ;; | |
918 | ;; Declarations. | |
919 | '("^[ \t]*(\\(define\\)\\>[ \t]*(?\\([^ \t\n\)]+\\)?" | |
920 | (1 font-lock-keyword-face) (2 font-lock-function-name-face nil t)) | |
921 | ;; | |
922 | ;; Control structures. | |
923 | ;(make-regexp '("begin" "call-with-current-continuation" "call/cc" | |
924 | ; "call-with-input-file" "call-with-output-file" "case" "cond" | |
925 | ; "define-syntax" "do" "else" "for-each" "if" "lambda" | |
926 | ; "let-syntax" "let\\*?" "letrec" "letrec-syntax" | |
927 | ; ;; Stefan Monnier <stefan.monnier@epfl.ch> says don't bother. | |
928 | ; ;;"quasiquote" "quote" "unquote" "unquote-splicing" | |
929 | ; "map" "syntax" "syntax-rules")) | |
930 | (cons | |
931 | (concat "(\\(" | |
932 | "begin\\|c\\(a\\(ll\\(-with-\\(current-continuation\\|" | |
933 | "input-file\\|output-file\\)\\|/cc\\)\\|se\\)\\|ond\\)\\|" | |
934 | "d\\(efine-syntax\\|o\\)\\|else\\|for-each\\|if\\|" | |
935 | "l\\(ambda\\|et\\(-syntax\\|\\*?\\|rec\\(\\|-syntax\\)\\)\\)\\|" | |
936 | "map\\|syntax\\(\\|-rules\\)" | |
937 | "\\)\\>") 1)) | |
938 | "Default expressions to highlight in Scheme modes.") | |
939 | ||
940 | ||
030f4a35 | 941 | (defconst c-font-lock-keywords-1 nil |
fb512de9 | 942 | "Subdued level highlighting for C modes.") |
030f4a35 RS |
943 | |
944 | (defconst c-font-lock-keywords-2 nil | |
fb512de9 | 945 | "Gaudy level highlighting for C modes.") |
030f4a35 | 946 | |
1bd50840 | 947 | (defconst c++-font-lock-keywords-1 nil |
fb512de9 | 948 | "Subdued level highlighting for C++ modes.") |
1bd50840 RS |
949 | |
950 | (defconst c++-font-lock-keywords-2 nil | |
fb512de9 | 951 | "Gaudy level highlighting for C++ modes.") |
1bd50840 | 952 | |
b89e1134 SM |
953 | (let ((c-keywords |
954 | ; ("break" "continue" "do" "else" "for" "if" "return" "switch" "while") | |
955 | "break\\|continue\\|do\\|else\\|for\\|if\\|return\\|switch\\|while") | |
956 | (c-type-types | |
a1eb1cf1 RS |
957 | ; ("auto" "extern" "register" "static" "typedef" "struct" "union" "enum" |
958 | ; "signed" "unsigned" "short" "long" "int" "char" "float" "double" | |
b89e1134 SM |
959 | ; "void" "volatile" "const") |
960 | (concat "auto\\|c\\(har\\|onst\\)\\|double\\|e\\(num\\|xtern\\)\\|" | |
961 | "float\\|int\\|long\\|register\\|" | |
962 | "s\\(hort\\|igned\\|t\\(atic\\|ruct\\)\\)\\|typedef\\|" | |
963 | "un\\(ion\\|signed\\)\\|vo\\(id\\|latile\\)")) ; 6 ()s deep. | |
964 | (c++-keywords | |
965 | ; ("break" "continue" "do" "else" "for" "if" "return" "switch" "while" | |
966 | ; "asm" "catch" "delete" "new" "operator" "sizeof" "this" "throw" "try" | |
967 | ; "protected" "private" "public") | |
968 | (concat "asm\\|break\\|c\\(atch\\|ontinue\\)\\|d\\(elete\\|o\\)\\|" | |
969 | "else\\|for\\|if\\|new\\|operator\\|" | |
970 | "p\\(r\\(ivate\\|otected\\)\\|ublic\\)\\|return\\|" | |
971 | "s\\(izeof\\|witch\\)\\|t\\(h\\(is\\|row\\)\\|ry\\)\\|while")) | |
972 | (c++-type-types | |
973 | ; ("auto" "extern" "register" "static" "typedef" "struct" "union" "enum" | |
974 | ; "signed" "unsigned" "short" "long" "int" "char" "float" "double" | |
975 | ; "void" "volatile" "const" "class" "inline" "friend" "bool" | |
976 | ; "virtual" "complex" "template") | |
977 | (concat "auto\\|bool\\|c\\(har\\|lass\\|o\\(mplex\\|nst\\)\\)\\|" | |
978 | "double\\|e\\(num\\|xtern\\)\\|f\\(loat\\|riend\\)\\|" | |
979 | "in\\(line\\|t\\)\\|long\\|register\\|" | |
980 | "s\\(hort\\|igned\\|t\\(atic\\|ruct\\)\\)\\|" | |
981 | "t\\(emplate\\|ypedef\\)\\|un\\(ion\\|signed\\)\\|" | |
982 | "v\\(irtual\\|o\\(id\\|latile\\)\\)")) ; 11 ()s deep. | |
a1eb1cf1 | 983 | (ctoken "[a-zA-Z0-9_:~]+")) |
f60f18ae KH |
984 | (setq c-font-lock-keywords-1 |
985 | (list | |
f60f18ae | 986 | ;; |
a1eb1cf1 | 987 | ;; Fontify filenames in #include <...> preprocessor directives. |
f60f18ae KH |
988 | '("^#[ \t]*include[ \t]+\\(<[^>\"\n]+>\\)" 1 font-lock-string-face) |
989 | ;; | |
a1eb1cf1 RS |
990 | ;; Fontify function macro names. |
991 | '("^#[ \t]*define[ \t]+\\(\\(\\sw+\\)(\\)" 2 font-lock-function-name-face) | |
f60f18ae | 992 | ;; |
a1eb1cf1 RS |
993 | ;; Fontify otherwise as symbol names, and the preprocessor directive names. |
994 | '("^\\(#[ \t]*[a-z]+\\)\\>[ \t]*\\(\\sw+\\)?" | |
995 | (1 font-lock-reference-face) (2 font-lock-variable-name-face nil t)) | |
f60f18ae | 996 | ;; |
a1eb1cf1 RS |
997 | ;; Fontify function name definitions (without type on line). |
998 | (list (concat "^\\(" ctoken "\\)[ \t]*(") 1 'font-lock-function-name-face) | |
f60f18ae KH |
999 | )) |
1000 | ||
1001 | (setq c-font-lock-keywords-2 | |
1002 | (append c-font-lock-keywords-1 | |
030f4a35 | 1003 | (list |
030f4a35 | 1004 | ;; |
a1eb1cf1 | 1005 | ;; Fontify all storage classes and type specifiers (before declarations). |
b89e1134 | 1006 | (cons (concat "\\<\\(" c-type-types "\\)\\>") 'font-lock-type-face) |
030f4a35 | 1007 | ;; |
a1eb1cf1 RS |
1008 | ;; Fontify variable/structure name declarations and definitions, or |
1009 | ;; function name declarations (plus definitions with type on same line). | |
b89e1134 SM |
1010 | (list (concat "\\<\\(" c-type-types "\\)[ \t*]+" |
1011 | "\\(" ctoken "[ \t*]+\\)*" | |
1012 | "\\(" ctoken "\\)[ \t]*\\((\\)?") | |
1013 | 9 | |
1014 | '(if (match-beginning 10) | |
1015 | font-lock-function-name-face | |
1016 | font-lock-variable-name-face)) | |
1017 | ;; | |
1018 | ;; Fontify function/variable name declarations at the start of the line. | |
1019 | ;; (Not everyone follows the GNU convention of function name at the start.) | |
1020 | (list (concat "^" ctoken "[ \t*]+" | |
1021 | "\\(" ctoken "[ \t*]+\\)*" | |
a1eb1cf1 | 1022 | "\\(" ctoken "\\)[ \t]*\\((\\)?") |
b89e1134 SM |
1023 | 2 |
1024 | '(if (match-beginning 3) | |
1025 | font-lock-function-name-face | |
1026 | font-lock-variable-name-face)) | |
030f4a35 | 1027 | ;; |
a1eb1cf1 | 1028 | ;; Fontify variable names declared with structures, or typedef names. |
b89e1134 | 1029 | '("}[ \t*]*\\(\\sw+\\)[ \t]*[;,[]" 1 font-lock-variable-name-face) |
030f4a35 | 1030 | ;; |
b89e1134 SM |
1031 | ;; Fontify all builtin keywords (except case, default and goto; see below). |
1032 | (concat "\\<\\(" c-keywords "\\)\\>") | |
030f4a35 | 1033 | ;; |
b89e1134 | 1034 | ;; Fontify case/goto keywords and targets, and goto tags (incl "default:"). |
a1eb1cf1 RS |
1035 | '("\\<\\(case\\|goto\\)\\>[ \t]*\\([^ \t\n:;]+\\)?" |
1036 | (1 font-lock-keyword-face) (2 font-lock-reference-face nil t)) | |
1037 | '("^[ \t]*\\(\\sw+\\)[ \t]*:" 1 font-lock-reference-face) | |
f60f18ae | 1038 | ))) |
1bd50840 | 1039 | |
a1eb1cf1 | 1040 | (setq c++-font-lock-keywords-1 c-font-lock-keywords-1) |
1bd50840 | 1041 | (setq c++-font-lock-keywords-2 |
b89e1134 | 1042 | (append c++-font-lock-keywords-1 |
a1eb1cf1 | 1043 | (list |
b89e1134 SM |
1044 | ;; We don't just add to the C keywords for subtle differences and speed. |
1045 | ;; See the above comments for `c-font-lock-keywords-2'. | |
1046 | (cons (concat "\\<\\(" c++-type-types "\\)\\>") 'font-lock-type-face) | |
1047 | (list (concat "\\<\\(" c++-type-types "\\)[ \t*&]+" | |
1048 | "\\(" ctoken "[ \t*&]+\\)*" | |
d46c21ec | 1049 | "\\(" ctoken "\\)[ \t<>=!+-]*\\((\\)?") |
b89e1134 SM |
1050 | 14 |
1051 | '(if (match-beginning 15) | |
1052 | font-lock-function-name-face | |
1053 | font-lock-variable-name-face)) | |
1054 | (list (concat "^" ctoken "[ \t*]+" | |
1055 | "\\(" ctoken "[ \t*]+\\)*" | |
d46c21ec | 1056 | "\\(" ctoken "\\)[ \t<>=!+-]*\\((\\)?") |
b89e1134 SM |
1057 | 2 |
1058 | '(if (match-beginning 3) | |
1059 | font-lock-function-name-face | |
1060 | font-lock-variable-name-face)) | |
1061 | '("}[ \t*]*\\(\\sw+\\)[ \t]*[;,[]" 1 font-lock-variable-name-face) | |
1062 | (concat "\\<\\(" c++-keywords "\\)\\>") | |
1063 | '("\\<\\(case\\|goto\\)\\>[ \t]*\\([^ \t\n:;]+\\)?" | |
1064 | (1 font-lock-keyword-face) (2 font-lock-reference-face nil t)) | |
1065 | '("^[ \t]*\\(\\sw+\\)[ \t]*:[^:]" 1 font-lock-reference-face)))) | |
f60f18ae | 1066 | ) |
030f4a35 | 1067 | |
fb512de9 SM |
1068 | (defvar c-font-lock-keywords c-font-lock-keywords-1 |
1069 | "Default expressions to highlight in C mode.") | |
030f4a35 | 1070 | |
fb512de9 SM |
1071 | (defvar c++-font-lock-keywords c++-font-lock-keywords-1 |
1072 | "Default expressions to highlight in C++ mode.") | |
030f4a35 | 1073 | |
d46c21ec | 1074 | |
030f4a35 | 1075 | (defvar tex-font-lock-keywords |
d46c21ec SM |
1076 | ; ;; Regexps updated with help from Ulrik Dickow <dickow@nbi.dk>. |
1077 | ; '(("\\\\\\(begin\\|end\\|newcommand\\){\\([a-zA-Z0-9\\*]+\\)}" | |
1078 | ; 2 font-lock-function-name-face) | |
1079 | ; ("\\\\\\(cite\\|label\\|pageref\\|ref\\){\\([^} \t\n]+\\)}" | |
1080 | ; 2 font-lock-reference-face) | |
1081 | ; ;; It seems a bit dubious to use `bold' and `italic' faces since we might | |
1082 | ; ;; not be able to display those fonts. | |
1083 | ; ("{\\\\bf\\([^}]+\\)}" 1 'bold keep) | |
1084 | ; ("{\\\\\\(em\\|it\\|sl\\)\\([^}]+\\)}" 2 'italic keep) | |
1085 | ; ("\\\\\\([a-zA-Z@]+\\|.\\)" . font-lock-keyword-face) | |
1086 | ; ("^[ \t\n]*\\\\def[\\\\@]\\(\\w+\\)" 1 font-lock-function-name-face keep)) | |
1087 | ;; Rewritten and extended for LaTeX2e by Ulrik Dickow <dickow@nbi.dk>. | |
826b2925 SM |
1088 | '(("\\\\\\(begin\\|end\\|newcommand\\){\\([a-zA-Z0-9\\*]+\\)}" |
1089 | 2 font-lock-function-name-face) | |
1090 | ("\\\\\\(cite\\|label\\|pageref\\|ref\\){\\([^} \t\n]+\\)}" | |
1091 | 2 font-lock-reference-face) | |
d46c21ec SM |
1092 | ("^[ \t]*\\\\def\\\\\\(\\(\\w\\|@\\)+\\)" 1 font-lock-function-name-face) |
1093 | ("\\\\\\([a-zA-Z@]+\\|.\\)" . font-lock-keyword-face) | |
826b2925 SM |
1094 | ;; It seems a bit dubious to use `bold' and `italic' faces since we might |
1095 | ;; not be able to display those fonts. | |
d46c21ec SM |
1096 | ;; LaTeX2e: \emph{This is emphasized}. |
1097 | ("\\\\emph{\\([^}]+\\)}" 1 'italic keep) | |
1098 | ;; LaTeX2e: \textbf{This is bold}, \textit{...}, \textsl{...} | |
1099 | ("\\\\text\\(\\(bf\\)\\|it\\|sl\\){\\([^}]+\\)}" | |
1100 | 3 (if (match-beginning 2) 'bold 'italic) keep) | |
1101 | ;; Old-style bf/em/it/sl. Stop at `\\' and un-escaped `&', for good tables. | |
1102 | ("\\\\\\(\\(bf\\)\\|em\\|it\\|sl\\)\\>\\(\\([^}&\\]\\|\\\\[^\\]\\)+\\)" | |
1103 | 3 (if (match-beginning 2) 'bold 'italic) keep)) | |
1104 | "Additional expressions to highlight in TeX modes.") | |
1105 | \f | |
a1eb1cf1 RS |
1106 | ;; Install ourselves: |
1107 | ||
a1eb1cf1 RS |
1108 | (or (assq 'font-lock-mode minor-mode-alist) |
1109 | (setq minor-mode-alist (cons '(font-lock-mode " Font") minor-mode-alist))) | |
1110 | ||
1111 | ;; Provide ourselves: | |
8f261d40 | 1112 | |
030f4a35 RS |
1113 | (provide 'font-lock) |
1114 | ||
1115 | ;;; font-lock.el ends here |