]> code.delx.au - gnu-emacs-elpa/blob - packages/auctex-11.86/font-latex.el
(debbugs-emacs): New function and modes for listing the Emacs bugs, reading them...
[gnu-emacs-elpa] / packages / auctex-11.86 / font-latex.el
1 ;;; font-latex.el --- LaTeX fontification for Font Lock mode.
2
3 ;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
4 ;; 2004, 2005, 2006, 2007, 2008 Free Software Foundation.
5
6 ;; Authors: Peter S. Galbraith <psg@debian.org>
7 ;; Simon Marshall <Simon.Marshall@esrin.esa.it>
8 ;; Maintainer: auctex-devel@gnu.org
9 ;; Created: 06 July 1996
10 ;; Keywords: tex, wp, faces
11
12 ;;; This file is not part of GNU Emacs.
13
14 ;; This package is free software; you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation; either version 3, or (at your option)
17 ;; any later version.
18
19 ;; This package is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ;; GNU General Public License for more details.
23
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs; see the file COPYING. If not, write to the
26 ;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
27 ;; Boston, MA 02110-1301, USA.
28
29 ;;; Commentary:
30 ;;
31 ;; This package enhances font-lock fontification patterns for LaTeX.
32 ;; font-lock mode is a minor mode that causes your comments to be
33 ;; displayed in one face, strings in another, reserved words in
34 ;; another, and so on.
35 ;;
36 ;; ** Infinite loops !? **
37 ;; If you get an infinite loop, send a bug report!
38 ;; Then set the following in your ~/.emacs file to keep on working:
39 ;; (setq font-latex-do-multi-line nil)
40
41 ;;; Code:
42
43 (require 'font-lock)
44 (require 'tex)
45
46 (eval-when-compile
47 (require 'cl))
48
49 (defgroup font-latex nil
50 "Font-latex text highlighting package."
51 :prefix "font-latex-"
52 :group 'faces
53 :group 'tex
54 :group 'AUCTeX)
55
56 (defgroup font-latex-keywords nil
57 "Keywords for highlighting text in font-latex."
58 :prefix "font-latex-"
59 :group 'font-latex)
60
61 (defgroup font-latex-highlighting-faces nil
62 "Faces for highlighting text in font-latex."
63 :prefix "font-latex-"
64 :group 'font-latex)
65
66 (defvar font-latex-multiline-boundary 5000
67 "Size of region to search for the start or end of a multiline construct.")
68
69 (defvar font-latex-quote-regexp-beg nil
70 "Regexp used to find quotes.")
71 (make-variable-buffer-local 'font-latex-quote-regexp-beg)
72
73 (defvar font-latex-quote-list '(("``" "''") ("<<" ">>" french) ("«" "»" french))
74 "List of quote specifiers for quotation fontification.
75
76 Each element of the list is either a list consisting of two
77 strings to be used as opening and closing quotation marks
78 independently of the value of `font-latex-quotes' or a list with
79 three elements where the first and second element are strings for
80 opening and closing quotation marks and the third element being
81 either the symbol 'german or 'french describing the order of
82 quotes.
83
84 If `font-latex-quotes' specifies a different state, order of the
85 added quotes will be reversed for fontification. For example if
86 '(\"\\\"<\" \"\\\">\" french) is given but `font-latex-quotes'
87 specifies 'german, quotes will be used like \">foo\"< for
88 fontification.")
89
90 (defvar font-latex-quotes-control nil
91 "Internal variable for keeping track if `font-latex-quotes' changed.")
92 (make-variable-buffer-local 'font-latex-quotes-control)
93
94 (defvar font-latex-quotes-internal nil
95 "Internal variable for tracking outcome of automatic detection.
96 If automatic detection is not enabled, it is assigned the value
97 of `font-latex-quotes'.")
98 (make-variable-buffer-local 'font-latex-quotes-internal)
99
100 (defvar font-latex-quotes-fallback 'french
101 "Fallback value for `font-latex-quotes' if automatic detection fails.")
102
103 (defvar font-latex-quote-style-list-french
104 '("french" "frenchb" "frenchle" "frenchpro" "francais" "canadien"
105 "acadian" "italian")
106 "List of styles for which French-style quote matching should be activated.")
107
108 (defvar font-latex-quote-style-list-german
109 '("austrian" "german" "germanb" "naustrian" "ngerman")
110 "List of styles for which German-style quote matching should be activated.")
111
112 (defcustom font-latex-quotes 'auto
113 "Whether to fontify << French quotes >> or >>German quotes<<.
114 Also selects \"<quote\"> versus \">quote\"<.
115
116 If value `auto' is chosen, an attempt is being made in deriving
117 the type of quotation mark matching from document settings like
118 the language option supplied to the babel package.
119
120 If nil, quoted content will not be fontified."
121 :type '(choice (const auto) (const french) (const german) (const nil))
122 :group 'font-latex)
123 (put 'font-latex-quotes 'safe-local-variable
124 '(lambda (x) (memq x '(auto french german nil))))
125
126 (defun font-latex-add-quotes (quotes)
127 "Add QUOTES to `font-latex-quote-list'.
128 QUOTES has to be a list adhering to the format of an element of
129 `font-latex-quote-list'."
130 (setq font-latex-quotes-control nil)
131 (make-local-variable 'font-latex-quote-list)
132 (add-to-list 'font-latex-quote-list quotes))
133
134 (defun font-latex-quotes-set-internal ()
135 "Set `font-latex-quotes-internal' according to `font-latex-quotes'.
136 If `font-latex-quotes' is set to `auto', try to derive the
137 correct value from document properties."
138 (setq font-latex-quotes-internal
139 (if (eq font-latex-quotes 'auto)
140 (or (when (TeX-elt-of-list-member
141 font-latex-quote-style-list-french TeX-active-styles)
142 'french)
143 (when (TeX-elt-of-list-member
144 font-latex-quote-style-list-german TeX-active-styles)
145 'german)
146 font-latex-quotes-fallback)
147 font-latex-quotes)))
148 ;; Update the value of `font-latex-quotes-internal' when the list of
149 ;; styles changes.
150 (add-hook 'TeX-update-style-hook 'font-latex-quotes-set-internal)
151
152 ;; The definitions of the title faces were originally taken from
153 ;; info.el (Copyright (C) 1985, 86, 92, 93, 94, 95, 96, 97, 98, 99,
154 ;; 2000, 2001 Free Software Foundation, Inc.) and adapted to the needs
155 ;; of font-latex.el.
156
157 (defconst font-latex-sectioning-max 5
158 "Highest number for font-latex-sectioning-N-face")
159 (defface font-latex-sectioning-5-face
160 (if (featurep 'xemacs)
161 '((((type tty pc) (class color) (background light))
162 (:foreground "blue4" :bold t))
163 (((type tty pc) (class color) (background dark))
164 (:foreground "yellow" :bold t))
165 (((class color) (background light))
166 (:bold t :foreground "blue4" :family "helvetica"))
167 (((class color) (background dark))
168 (:bold t :foreground "yellow" :family "helvetica"))
169 (t (:bold t :family "helvetica")))
170 '((((type tty pc) (class color) (background light))
171 (:foreground "blue4" :weight bold))
172 (((type tty pc) (class color) (background dark))
173 (:foreground "yellow" :weight bold))
174 (((class color) (background light))
175 (:weight bold :inherit variable-pitch :foreground "blue4"))
176 (((class color) (background dark))
177 (:weight bold :inherit variable-pitch :foreground "yellow"))
178 (t (:weight bold :inherit variable-pitch))))
179 "Face for sectioning commands at level 5."
180 :group 'font-latex-highlighting-faces)
181
182 (defun font-latex-update-sectioning-faces (&optional max height-scale)
183 "Update sectioning commands faces."
184 (unless height-scale
185 (setq height-scale (if (numberp font-latex-fontify-sectioning)
186 font-latex-fontify-sectioning
187 1.1)))
188 (unless max
189 (setq max font-latex-sectioning-max))
190 (dotimes (num max)
191 (let* (;; reverse for XEmacs:
192 (num (- max (1+ num)))
193 (face-name (intern (format "font-latex-sectioning-%s-face" num))))
194 (unless (get face-name 'saved-face) ; Do not touch customized faces.
195 (if (featurep 'xemacs)
196 (let ((size
197 ;; Multiply with .9 because `face-height' returns a value
198 ;; slightly larger than the actual font size.
199 ;; `make-face-size' takes numeric points according to Aidan
200 ;; Kehoe in <16989.15536.613916.678965@parhasard.net> (not
201 ;; documented).
202 (round (* 0.9
203 (face-height 'default)
204 (expt height-scale (- max 1 num))))))
205 ;; (message "%s - %s" face-name size)
206 (make-face-size face-name size))
207 (set-face-attribute face-name nil :height height-scale))))))
208
209 (defcustom font-latex-fontify-sectioning 1.1
210 "Whether to fontify sectioning macros with varying height or a color face.
211
212 If it is a number, use varying height faces. The number is used
213 for scaling starting from `font-latex-sectioning-5-face'. Typically
214 values from 1.05 to 1.3 give best results, depending on your font
215 setup. If it is the symbol `color', use `font-lock-type-face'.
216
217 Caveats: Customizing the scaling factor applies to all sectioning
218 faces unless those face have been saved by customize. Setting
219 this variable directly does not take effect unless you call
220 `font-latex-update-sectioning-faces' or restart Emacs.
221
222 Switching from `color' to a number or vice versa does not take
223 effect unless you call \\[font-lock-fontify-buffer] or restart
224 Emacs."
225 ;; Possibly add some words about XEmacs here. :-(
226 :type '(choice (number :tag "Scale factor")
227 (const color))
228 :initialize 'custom-initialize-default
229 :set (lambda (symbol value)
230 (set-default symbol value)
231 (unless (eq value 'color)
232 (font-latex-update-sectioning-faces font-latex-sectioning-max value)))
233 :group 'font-latex)
234
235 (defun font-latex-make-sectioning-faces (max &optional height-scale)
236 "Build the faces used to fontify sectioning commands."
237 (unless max (setq max font-latex-sectioning-max))
238 (unless height-scale
239 (setq height-scale (if (numberp font-latex-fontify-sectioning)
240 font-latex-fontify-sectioning
241 1.1)))
242 (dotimes (num max)
243 (let* (;; reverse for XEmacs:
244 (num (- max (1+ num)))
245 (face-name (intern (format "font-latex-sectioning-%s-face" num)))
246 (f-inherit (intern (format "font-latex-sectioning-%s-face" (1+ num))))
247 (size (when (featurep 'xemacs)
248 (round (* 0.9 (face-height 'default)
249 (expt height-scale (- max 1 num)))))))
250 (eval
251 `(defface ,face-name
252 (if (featurep 'xemacs)
253 '((t (:size ,(format "%spt" size))))
254 '((t (:height ,height-scale :inherit ,f-inherit))))
255 (format "Face for sectioning commands at level %s.
256
257 Probably you don't want to customize this face directly. Better
258 change the base face `font-latex-sectioning-5-face' or customize the
259 variable `font-latex-fontify-sectioning'." num)
260 :group 'font-latex-highlighting-faces))
261 (when (and (featurep 'xemacs)
262 ;; Do not touch customized faces.
263 (not (get face-name 'saved-face)))
264 (set-face-parent face-name f-inherit)
265 ;; Explicitely set the size again to code around the bug that
266 ;; `set-face-parent' overwrites the original face size.
267 (make-face-size face-name size)))))
268
269 (font-latex-make-sectioning-faces font-latex-sectioning-max)
270
271
272 ;;; Keywords
273
274 (defvar font-latex-keywords-1 nil
275 "Subdued level highlighting for LaTeX modes.")
276
277 (defvar font-latex-keywords-2 nil
278 "High level highlighting for LaTeX modes.")
279
280 (defvar font-latex-built-in-keyword-classes
281 '(("warning"
282 ("nopagebreak" "pagebreak" "newpage" "clearpage" "cleardoublepage"
283 "enlargethispage" "nolinebreak" "linebreak" "newline" "-" "\\" "\\*"
284 "appendix" "displaybreak" "allowdisplaybreaks" "include")
285 'font-latex-warning-face 1 noarg)
286 ("variable"
287 (("setlength" "|{\\{") ("settowidth" "|{\\{") ("setcounter" "{|{\\")
288 ("addtolength" "|{\\{") ("addtocounter" "{|{\\"))
289 'font-lock-variable-name-face 2 command)
290 ("reference"
291 (("nocite" "{") ("cite" "[{") ("label" "{") ("pageref" "{")
292 ("vref" "{") ("eqref" "{") ("ref" "{") ("include" "{")
293 ("input" "{") ("bibliography" "{") ("index" "{") ("glossary" "{")
294 ("footnote" "[{") ("footnotemark" "[") ("footnotetext" "[{"))
295 'font-lock-constant-face 2 command)
296 ("function"
297 (("begin" "{") ("end" "{") ("pagenumbering" "{")
298 ("thispagestyle" "{") ("pagestyle" "{") ("nofiles" "")
299 ("includeonly" "{") ("bibliographystyle" "{") ("documentstyle" "[{")
300 ("documentclass" "[{") ("newenvironment" "*{[[{{")
301 ("newcommand" "*|{\\[[{") ("newlength" "|{\\")
302 ("newtheorem" "{[{[")
303 ("newcounter" "{[") ("renewenvironment" "*{[{{")
304 ("renewcommand" "*|{\\[[{") ("renewtheorem" "{[{[")
305 ("usepackage" "[{") ("fbox" "{") ("mbox" "{") ("sbox" "{")
306 ("vspace" "*{") ("hspace" "*{") ("thinspace" "") ("negthinspace" "")
307 ;; XXX: Should macros without arguments rather be listed in a
308 ;; separate category with 'noarg instead of 'command handling?
309 ("enspace" "") ("enskip" "") ("quad" "") ("qquad" "") ("nonumber" "")
310 ("centering" "") ("TeX" "") ("LaTeX" ""))
311 'font-lock-function-name-face 2 command)
312 ("sectioning-0"
313 (("part" "*[{"))
314 (if (eq font-latex-fontify-sectioning 'color)
315 'font-lock-type-face
316 'font-latex-sectioning-0-face)
317 2 command)
318 ("sectioning-1"
319 (("chapter" "*[{"))
320 (if (eq font-latex-fontify-sectioning 'color)
321 'font-lock-type-face
322 'font-latex-sectioning-1-face)
323 2 command)
324 ("sectioning-2"
325 (("section" "*[{"))
326 (if (eq font-latex-fontify-sectioning 'color)
327 'font-lock-type-face
328 'font-latex-sectioning-2-face)
329 2 command)
330 ("sectioning-3"
331 (("subsection" "*[{"))
332 (if (eq font-latex-fontify-sectioning 'color)
333 'font-lock-type-face
334 'font-latex-sectioning-3-face)
335 2 command)
336 ("sectioning-4"
337 (("subsubsection" "*[{"))
338 (if (eq font-latex-fontify-sectioning 'color)
339 'font-lock-type-face
340 'font-latex-sectioning-4-face)
341 2 command)
342 ("sectioning-5"
343 (("paragraph" "*[{") ("subparagraph" "*[{")
344 ("subsubparagraph" "*[{"))
345 (if (eq font-latex-fontify-sectioning 'color)
346 'font-lock-type-face
347 'font-latex-sectioning-5-face)
348 2 command)
349 ("slide-title" () 'font-latex-slide-title-face 2 command)
350 ("textual"
351 (("item" "[") ("title" "{") ("author" "{") ("date" "{")
352 ("thanks" "{") ("address" "{") ("caption" "[{")
353 ("textsuperscript" "{"))
354 'font-lock-type-face 2 command)
355 ("bold-command"
356 (("textbf" "{") ("textsc" "{") ("textup" "{") ("boldsymbol" "{")
357 ("pmb" "{"))
358 'font-latex-bold-face 1 command)
359 ("italic-command"
360 (("emph" "{") ("textit" "{") ("textsl" "{"))
361 'font-latex-italic-face 1 command)
362 ("math-command"
363 (("ensuremath" "|{\\"))
364 'font-latex-math-face 1 command)
365 ("type-command"
366 (("texttt" "{") ("textsf" "{") ("textrm" "{") ("textmd" "{"))
367 'font-lock-type-face 1 command)
368 ("bold-declaration"
369 ("bf" "bfseries" "sc" "scshape" "upshape")
370 'font-latex-bold-face 1 declaration)
371 ("italic-declaration"
372 ("em" "it" "itshape" "sl" "slshape")
373 'font-latex-italic-face 1 declaration)
374 ("type-declaration"
375 ("tt" "ttfamily" "sf" "sffamily" "rm" "rmfamily" "mdseries"
376 "tiny" "scriptsize" "footnotesize" "small" "normalsize"
377 "large" "Large" "LARGE" "huge" "Huge")
378 'font-lock-type-face 1 declaration))
379 "Built-in keywords and specifications for font locking.
380
381 The first element of each item is the name of the keyword class.
382
383 The second element is a list of keywords (macros without an
384 escape character) to highlight or, if the fifth element is the
385 symbol 'command, a list of lists where the first element of each
386 item is a keyword and the second a string specifying the macro
387 syntax. It can contain \"*\" if the macro has a starred variant,
388 \"[\" for an optional argument, \"{\" for a mandatory argument,
389 and \"\\\" for a macro. A \"|\" means the following two tokens
390 should be regarded as alternatives.
391
392 The third element is the symbol of a face to be used or a Lisp
393 form returning a face symbol.
394
395 The fourth element is the fontification level.
396
397 The fifth element is the type of construct to be matched. It can
398 be one of 'noarg which will match simple macros without
399 arguments (like \"\\foo\"), 'declaration which will match macros
400 inside a TeX group (like \"{\\bfseries foo}\"), or 'command which
401 will match macros of the form \"\\foo[bar]{baz}\".")
402
403 (defcustom font-latex-deactivated-keyword-classes nil
404 "List of strings for built-in keyword classes to be deactivated.
405
406 Valid entries are \"warning\", \"variable\", \"reference\",
407 \"function\" , \"sectioning-0\", \"sectioning-1\", \"sectioning-2\",
408 \"sectioning-3\", \"sectioning-4\", \"sectioning-5\", \"textual\",
409 \"bold-command\", \"italic-command\", \"math-command\", \"type-command\",
410 \"bold-declaration\", \"italic-declaration\", \"type-declaration\".
411
412 You have to restart Emacs for a change of this variable to take effect."
413 :group 'font-latex-keywords
414 :type `(set ,@(mapcar
415 (lambda (spec)
416 `(const :tag ,(concat
417 ;; Name of the keyword class
418 (let ((name (split-string (car spec) "-")))
419 (setcar name (capitalize (car name)))
420 (mapconcat 'identity name " "))
421 " keywords in `"
422 ;; Name of the face
423 (symbol-name (eval (nth 2 spec))) "'.\n"
424 ;; List of keywords
425 (with-temp-buffer
426 (insert " Keywords: "
427 (mapconcat (lambda (x)
428 (if (listp x)
429 (car x)
430 x))
431 (nth 1 spec) ", "))
432 (fill-paragraph nil)
433 (buffer-substring-no-properties
434 (point-min) (point-max))))
435 ,(car spec)))
436 font-latex-built-in-keyword-classes)))
437
438 (defun font-latex-make-match-defun (prefix name face type)
439 "Return a function definition for keyword matching.
440 The variable holding the keywords to match are determined by the
441 strings PREFIX and NAME. The type of matcher is determined by
442 the symbol TYPE.
443
444 This is a helper function for `font-latex-make-built-in-keywords'
445 and `font-latex-make-user-keywords' and not intended for general
446 use."
447 ;; Note: The functions are byte-compiled at the end of font-latex.el.
448 ;; FIXME: Is the cond-clause possible inside of the defun?
449
450 ;; In an earlier version of font-latex the type could be a list like
451 ;; (command 1). This indicated a macro with one argument. Provide
452 ;; a match function in this case but don't actually support it.
453 (cond ((or (eq type 'command) (listp type))
454 (eval `(defun ,(intern (concat prefix name)) (limit)
455 ,(concat "Fontify `" prefix name "' up to LIMIT.
456
457 Generated by `font-latex-make-match-defun'.")
458 (when ,(intern (concat prefix name))
459 (font-latex-match-command-with-arguments
460 ,(intern (concat prefix name))
461 (append
462 (when (boundp ',(intern (concat prefix name
463 "-keywords-local")))
464 ,(intern (concat prefix name "-keywords-local")))
465 ,(intern (concat prefix name "-keywords")))
466 ;; `face' can be a face symbol, a form returning
467 ;; a face symbol, or a list of face attributes.
468 (if (and (listp ,face) (functionp (car ,face)))
469 (eval ,face)
470 ,face)
471 limit)))))
472 ((eq type 'declaration)
473 (eval `(defun ,(intern (concat prefix name)) (limit)
474 ,(concat "Fontify `" prefix name "' up to LIMIT.
475
476 Generated by `font-latex-make-match-defun'.")
477 (when ,(intern (concat prefix name))
478 (font-latex-match-command-in-braces
479 ,(intern (concat prefix name)) limit)))))
480 ((eq type 'noarg)
481 (eval `(defun ,(intern (concat prefix name)) (limit)
482 ,(concat "Fontify `" prefix name "' up to LIMIT.
483
484 Generated by `font-latex-make-match-defun'.")
485 (when ,(intern (concat prefix name))
486 (re-search-forward
487 ,(intern (concat prefix name)) limit t)))))))
488
489 (defun font-latex-keyword-matcher (prefix name face type)
490 "Return a matcher and highlighter as required by `font-lock-keywords'.
491 PREFIX and NAME are strings which are concatenated to form the
492 respective match function. FACE is a face name or a list of text
493 properties that will be applied to the respective part of the
494 match returned by the match function. TYPE is the type of
495 construct to be highlighted. Currently the symbols 'command,
496 'sectioning, 'declaration and 'noarg are valid.
497
498 This is a helper function for `font-latex-make-built-in-keywords'
499 and `font-latex-make-user-keywords' and not intended for general
500 use."
501 ;; In an earlier version of font-latex the type could be a list like
502 ;; (command 1). This indicated a macro with one argument. Provide
503 ;; a matcher in this case but don't actually support it.
504 (cond ((or (eq type 'command) (listp type))
505 `(,(intern (concat prefix name))
506 (0 (font-latex-matched-face 0) append t)
507 (1 (font-latex-matched-face 1) append t)
508 (2 (font-latex-matched-face 2) append t)
509 (3 (font-latex-matched-face 3) append t)
510 (4 (font-latex-matched-face 4) append t)
511 (5 (font-latex-matched-face 5) append t)
512 (6 (font-latex-matched-face 6) append t)
513 (7 (font-latex-matched-face 7) append t)))
514 ((eq type 'noarg)
515 `(,(intern (concat prefix name))
516 (0 ,face)))
517 ((eq type 'declaration)
518 `(,(intern (concat prefix name))
519 (0 'font-latex-warning-face t t)
520 (1 'font-lock-keyword-face append t)
521 (2 ,face append t)))))
522
523 (defun font-latex-make-built-in-keywords ()
524 "Build defuns, defvars and defcustoms for built-in keyword fontification."
525 (dolist (item font-latex-built-in-keyword-classes)
526 (let ((prefix "font-latex-match-")
527 (name (nth 0 item))
528 (keywords (nth 1 item))
529 (face (nth 2 item))
530 (level (nth 3 item))
531 (type (nth 4 item)))
532
533 ;; defvar font-latex-match-*-keywords-local
534 (eval `(defvar ,(intern (concat prefix name "-keywords-local"))
535 ',keywords
536 ,(concat "Buffer-local keywords to add to `"
537 prefix name "-keywords'.
538
539 This must be a list where each element is a list consisting of a
540 keyword string \(not a regular expression\) omitting the leading
541 backslash and a format specifier as. The options for the format
542 specifier are described in the doc string of
543 `font-latex-user-keyword-classes'.
544
545 This is an internal variable which should not be set directly.
546 Use `font-latex-add-keywords' instead.
547
548 Generated by `font-latex-make-built-in-keywords'.")))
549 (eval `(make-variable-buffer-local
550 ',(intern (concat prefix name "-keywords-local"))))
551
552 ;; defun font-latex-match-*-make
553 ;; Note: The functions are byte-compiled at the end of font-latex.el.
554 (eval `(defun ,(intern (concat prefix name "-make")) ()
555 ,(concat "Make or remake the variable `" prefix name "'.
556
557 Generated by `font-latex-make-built-in-keywords'.")
558 (let ((keywords
559 (append
560 (unless (member ,name
561 font-latex-deactivated-keyword-classes)
562 ,(intern (concat prefix name "-keywords-local")))
563 ,(intern (concat prefix name "-keywords"))))
564 multi-char-macros single-char-macros)
565 (dolist (elt keywords)
566 (let ((keyword (if (listp elt) (car elt) elt)))
567 (if (string-match "^[A-Za-z]" keyword)
568 (add-to-list 'multi-char-macros keyword)
569 (add-to-list 'single-char-macros keyword))))
570 (when (or multi-char-macros single-char-macros)
571 (setq ,(intern (concat prefix name))
572 (concat
573 "\\\\\\("
574 (when multi-char-macros
575 (concat
576 "\\(?:" (regexp-opt multi-char-macros) "\\)\\>"))
577 (when single-char-macros
578 (concat
579 (when multi-char-macros "\\|")
580 "\\(?:" (regexp-opt single-char-macros) "\\)"))
581 "\\)"))))))
582
583 ;; defcustom font-latex-match-*-keywords
584 (eval `(defcustom ,(intern (concat prefix name "-keywords")) nil
585 ,(concat "List of keywords "
586 (when (eq type 'command) "and formats ")
587 "for " name " face.\n"
588 (if (eq type 'command)
589 "\
590 Each element has to be a list consisting of the name of a macro
591 omitting the leading backslash and a format specifier as
592 described in the doc string of `font-latex-user-keyword-classes'."
593 "\
594 Each element has to be the name of a macro as a string, omitting
595 the leading backslash.")
596 "\n\n\
597 Setting this variable directly does not take effect; restart
598 Emacs.
599
600 Generated by `font-latex-make-built-in-keywords'.")
601 :type '(repeat (string :tag "Keyword"))
602 :type '(repeat ,(if (eq type 'command)
603 '(list (string :tag "Keyword")
604 (string :tag "Format"))
605 '(string :tag "Keyword")))
606 :set (lambda (symbol value)
607 (set-default symbol value)
608 (funcall ',(intern (concat prefix name "-make"))))
609 :group 'font-latex-keywords))
610
611 ;; defvar font-latex-match-*
612 (eval `(defvar ,(intern (concat prefix name))
613 ,(intern (concat prefix name "-keywords"))))
614 (eval `(make-variable-buffer-local
615 ',(intern (concat prefix name))))
616
617 ;; defun font-latex-match-*
618 (font-latex-make-match-defun prefix name face type)
619
620 ;; Add matchers and highlighters to `font-latex-keywords-{1,2}'.
621 (let ((keywords-entry (font-latex-keyword-matcher
622 prefix name face type)))
623 (add-to-list (intern (concat "font-latex-keywords-"
624 (number-to-string level)))
625 keywords-entry t)
626 (when (= level 1)
627 (add-to-list (intern (concat "font-latex-keywords-2"))
628 keywords-entry t))))))
629 (font-latex-make-built-in-keywords)
630
631 (defcustom font-latex-user-keyword-classes nil
632 "List of user-defined keyword classes for font locking.
633
634 Every keyword class consists of four parts, a name, a list of
635 keywords, a face and a specifier for the type of macro to be
636 highlighted.
637
638 When adding new entries, you have to use unique values for the
639 class names, i.e. they must not clash with names of the built-in
640 keyword classes or other names given by you. Additionally the
641 names must not contain spaces.
642
643 The list of keywords defines which commands and declarations
644 should be covered by the keyword class. A keyword can either be
645 a simple command name omitting the leading backslash or a list
646 consisting of the command name and a string specifying the syntax
647 of the command. The latter is useful if you want to match LaTeX
648 macros with arguments (see below). You can specify the occurence
649 and order of optional (\"[\") and mandatory (\"{\") arguments for
650 each keyword. For example for \"documentclass\" you'd use \"[{\"
651 because the macro has one optional followed by one mandatory
652 argument. Optionally starred macros can be indicated with \"*\".
653 In case an argument is an unbraced macro, use \"\\\". You can
654 also specify two alternative arguments by prefixing them with
655 \"|\". As an example, the specifier for \\newcommand is
656 \"*|{\\=\\[[{\".
657
658 The face argument can either be an existing face or a font
659 specification. (The latter option is not available in XEmacs.)
660
661 There are three alternatives for the class type:
662
663 A value of `command' indicates commands with arguments
664 \(\"\\foo[bar]{baz}\"). The mandatory arguments in curly braces
665 will get the face you specified.
666
667 A value of `declaration' indicates declarations inside of TeX
668 groups (\"{\\foo bar}\"). The content inside the braces,
669 excluding the command, will get the face you specified. In case
670 the braces are missing, the face will be applied to the command
671 itself.
672
673 A value of `noarg' indicates commands without arguments
674 \(\"\\foo\"). The command itself will get the face you
675 specified.
676
677 Setting this variable directly does not take effect;
678 use \\[customize] or restart Emacs."
679 :group 'font-latex-keywords
680 :type `(repeat (list (string :tag "Name")
681 (choice (repeat :tag "Keywords" (string :tag "Keyword"))
682 (repeat
683 :tag "Keywords with specs"
684 (group (string :tag "Keyword")
685 (string :tag "Format specifier"))))
686 ,(if (featurep 'xemacs)
687 '(face :tag "Face name")
688 '(choice (custom-face-edit :tag "Face attributes")
689 (face :tag "Face name")))
690 (choice :tag "Type"
691 ;; Maps to
692 ;;`font-latex-match-command-with-arguments'
693 (const :tag "Command with arguments"
694 command)
695 ;; Maps to
696 ;;`font-latex-match-command-in-braces'
697 (const :tag "Declaration inside TeX group"
698 declaration)
699 ;; Maps to `re-search-forward'
700 (const :tag "Command without arguments"
701 noarg))))
702 :set (lambda (symbol value)
703 (dolist (item value)
704 (when (string-match " " (car item))
705 (error "No spaces allowed in name")))
706 (let (names names-uniq)
707 (dolist (item (append font-latex-built-in-keyword-classes value))
708 (setq names (append names (list (car item)))))
709 (setq names (TeX-sort-strings names))
710 (setq names-uniq (TeX-delete-duplicate-strings names))
711 (dotimes (i (safe-length names-uniq))
712 (unless (string= (nth i names) (nth i names-uniq))
713 (error "Name %S already exists" (nth i names)))))
714 (set-default symbol value)
715 (let ((prefix "font-latex-match-"))
716 (dolist (elt value)
717 (unless (boundp (intern (concat prefix (car elt))))
718 ;; defvar font-latex-match-*
719 (eval `(defvar ,(intern (concat prefix (car elt))) nil)))
720 (let ((keywords (nth 1 elt))
721 single-char-macro-flag)
722 (setq keywords (if (listp (car keywords))
723 (mapcar 'car keywords)
724 keywords))
725 (catch 'single-char
726 (dolist (keyword keywords)
727 (unless (string-match "^[A-Za-z]" keyword)
728 (setq single-char-macro-flag t)
729 (throw 'single-char nil))))
730 (set (intern (concat prefix (car elt)))
731 (when (> (safe-length keywords) 0)
732 (concat "\\\\" (let ((max-specpdl-size 1000))
733 (regexp-opt keywords t))
734 (unless single-char-macro-flag "\\>")))))))))
735
736 (defun font-latex-make-user-keywords ()
737 "Build defuns and defvars for user keyword fontification."
738 (let ((keyword-specs font-latex-user-keyword-classes))
739 (dolist (item keyword-specs)
740 (let ((prefix "font-latex-match-")
741 (name (nth 0 item))
742 (keywords (nth 1 item))
743 (face (nth 2 item))
744 (type (nth 3 item)))
745
746 ;; defvar font-latex-match-*-keywords
747 (eval `(defvar ,(intern (concat prefix name "-keywords")) ',keywords
748 ,(concat "Font-latex keywords for " name " face.
749
750 Generated by `font-latex-make-user-keywords'.")))
751
752 ;; defun font-latex-match-*
753 (eval `(font-latex-make-match-defun prefix name '',face type))
754
755 ;; Add the matcher to `font-latex-keywords-2'.
756 (add-to-list 'font-latex-keywords-2
757 (font-latex-keyword-matcher prefix name face type) t))))
758
759 ;; Add the "fixed" matchers and highlighters.
760 (dolist (item
761 '(("\\(^\\|[^\\]\\)\\(&+\\)" 2 'font-latex-warning-face)
762 ("\\$\\$\\([^$]+\\)\\$\\$" 1 'font-latex-math-face)
763 (font-latex-match-quotation
764 (0 'font-latex-string-face append)
765 (1 'font-latex-warning-face))
766 ;; Hack to remove the verbatim face from the \ in
767 ;; \end{verbatim} and similar. The same hack is used in
768 ;; tex-mode.el.
769 ("^[ \t]*\\(\\\\\\)end"
770 (1 (get-text-property (match-end 1) 'face) t))))
771 (add-to-list 'font-latex-keywords-1 item)
772 (add-to-list 'font-latex-keywords-2 item))
773 (dolist (item
774 '((font-latex-match-math-env
775 (0 'font-latex-warning-face t t)
776 (1 'font-latex-math-face append t))
777 (font-latex-match-math-envII
778 (0 'font-latex-math-face append t))
779 (font-latex-match-simple-command
780 (0 'font-latex-sedate-face append))
781 (font-latex-match-script
782 (1 (font-latex-script (match-beginning 0)) append))))
783 (add-to-list 'font-latex-keywords-2 item t)))
784 (font-latex-make-user-keywords)
785
786 (defun font-latex-add-keywords (keywords class)
787 "Add KEYWORDS to CLASS.
788 KEYWORDS is a list of keywords or keywords with syntax specs.
789 CLASS corresponds to a keyword class and can be one of the
790 symbols 'warning, 'variable, 'reference, 'function, sectioning-0,
791 'sectioning-1, 'sectioning-2, 'sectioning-3, 'sectioning-4,
792 'sectioning-5, 'slide-title, 'textual, 'bold-command,
793 'italic-command, 'math-command, 'type-command, 'bold-declaration,
794 'italic-declaration or 'type-declaration.
795
796 The keywords will be added to the buffer-local list of keywords
797 of the respective keyword class and necessary updates of the font
798 locking machinery will be triggered."
799 (let* ((class (symbol-name class))
800 (list (intern (format "font-latex-match-%s-keywords-local" class))))
801 (dolist (elt keywords)
802 (add-to-list list elt))
803 (funcall (intern (format "font-latex-match-%s-make" class)))
804 (setq font-lock-set-defaults nil)
805 (font-lock-set-defaults)))
806
807 (defvar font-latex-keywords font-latex-keywords-1
808 "Default expressions to highlight in TeX mode.")
809
810
811 ;;; Subscript and superscript
812
813 (defcustom font-latex-fontify-script (not (featurep 'xemacs))
814 "If non-nil, fontify subscript and superscript strings.
815 This feature does not work in XEmacs."
816 :type 'boolean
817 :group 'font-latex)
818 (put 'font-latex-fontify-script 'safe-local-variable 'TeX-booleanp)
819
820 (defcustom font-latex-script-display '((raise -0.3) . (raise 0.3))
821 "Display specification for subscript and superscript content.
822 The car is used for subscript, the cdr is used for superscripts."
823 :group 'font-latex
824 :type '(cons (choice (sexp :tag "Subscript form")
825 (const :tag "No lowering" nil))
826 (choice (sexp :tag "Superscript form")
827 (const :tag "No raising" nil))))
828
829
830 ;;; Syntactic keywords
831
832 (defvar font-latex-syntactic-keywords nil
833 "Syntactic keywords used by `font-latex'.")
834 (make-variable-buffer-local 'font-latex-syntactic-keywords)
835
836 (defvar font-latex-syntactic-keywords-extra nil
837 "List of syntactic keywords to add to `font-latex-syntactic-keywords'.
838 The form should be the same as in `font-lock-syntactic-keywords'.")
839 (make-variable-buffer-local 'font-latex-syntactic-keywords-extra)
840
841 (defun font-latex-set-syntactic-keywords ()
842 "Set the variable `font-latex-syntactic-keywords'.
843 This function can be used to refresh the variable in case other
844 variables influencing its value, like `LaTeX-verbatim-environments',
845 have changed."
846 ;; Checks for non-emptiness of lists added in order to cater for
847 ;; installations where `(regexp-opt-group nil)' would enter a loop.
848 (let ((verb-envs (and (fboundp 'LaTeX-verbatim-environments)
849 (LaTeX-verbatim-environments)))
850 (verb-macros-with-delims
851 (and (fboundp 'LaTeX-verbatim-macros-with-delims)
852 (LaTeX-verbatim-macros-with-delims)))
853 (verb-macros-with-braces
854 (and (fboundp 'LaTeX-verbatim-macros-with-braces)
855 (LaTeX-verbatim-macros-with-braces))))
856 (setq verb-envs (and verb-envs (regexp-opt verb-envs))
857 verb-macros-with-delims (and verb-macros-with-delims
858 (regexp-opt verb-macros-with-delims))
859 verb-macros-with-braces (and verb-macros-with-braces
860 (regexp-opt verb-macros-with-braces))
861 font-latex-syntactic-keywords nil)
862 (unless (= (length verb-envs) 0)
863 (add-to-list 'font-latex-syntactic-keywords
864 `(,(concat "^[ \t]*\\\\begin *{\\(?:" verb-envs
865 "\\)}.*\\(\n\\)")
866 (1 "|" t)))
867 (add-to-list 'font-latex-syntactic-keywords
868 ;; Using the newline character for the syntax
869 ;; property often resulted in fontification
870 ;; problems when text was inserted at the end of
871 ;; the verbatim environment. That's why we now use
872 ;; the starting backslash of \end. There is a hack
873 ;; in `font-latex-make-user-keywords' to remove the
874 ;; spurious fontification of the backslash.
875 `(,(concat "^[ \t]*\\(\\\\\\)end *{\\(?:" verb-envs "\\)}")
876 (1 "|" t))))
877 (unless (= (length verb-macros-with-delims) 0)
878 (add-to-list 'font-latex-syntactic-keywords
879 `(,(concat "\\\\\\(?:" verb-macros-with-delims "\\)"
880 ;; An opening curly brace as delimiter
881 ;; is valid, but allowing it might screw
882 ;; up fontification of stuff like
883 ;; "\url{...} foo \textbf{<--!...}".
884 "\\([^a-z@*\n\f{]\\).*?"
885 ;; Give an escape char at the end of the
886 ;; verbatim construct punctuation syntax.
887 ;; Prevents wrong fontification of stuff
888 ;; like "\verb|foo\|".
889 "\\(" (regexp-quote TeX-esc) "*\\)\\(\\1\\)")
890 (1 "\"") (2 ".") (3 "\""))))
891 (unless (= (length verb-macros-with-braces) 0)
892 (add-to-list 'font-latex-syntactic-keywords
893 `(,(concat "\\\\\\(?:" verb-macros-with-braces "\\)"
894 "\\({\\).*?[^\\]\\(?:\\\\\\\\\\)*\\(}\\)")
895 (1 "|") (2 "|")))))
896 (when font-latex-syntactic-keywords-extra
897 (nconc font-latex-syntactic-keywords font-latex-syntactic-keywords-extra))
898 ;; Cater for docTeX mode.
899 (setq font-latex-doctex-syntactic-keywords
900 (append font-latex-syntactic-keywords
901 ;; For docTeX comment-in-doc.
902 `(("\\(\\^\\)\\^A" (1 (font-latex-doctex-^^A)))))))
903
904
905 ;;; Syntactic fontification
906
907 ;; Copy and adaptation of `tex-font-lock-syntactic-face-function' in
908 ;; `tex-mode.el' of CVS Emacs (March 2004)
909 (defun font-latex-syntactic-face-function (state)
910 (let ((char (nth 3 state)))
911 (cond
912 ((not char) 'font-lock-comment-face)
913 ((eq char ?$) 'font-latex-math-face)
914 (t
915 (when (char-valid-p char)
916 ;; This is a \verb?...? construct. Let's find the end and mark it.
917 (save-excursion
918 (skip-chars-forward (string ?^ char)) ;; Use `end' ?
919 (when (eq (char-syntax (preceding-char)) ?/)
920 (put-text-property (1- (point)) (point) 'syntax-table '(1)))
921 (unless (eobp)
922 (put-text-property (point) (1+ (point)) 'syntax-table '(7)))))
923 'font-latex-verbatim-face))))
924
925
926 ;;; Faces
927
928 (defface font-latex-bold-face
929 (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit bold))
930 ((assq :weight custom-face-attributes) '(:weight bold))
931 (t '(:bold t)))))
932 `((((class grayscale) (background light))
933 (:foreground "DimGray" ,@font))
934 (((class grayscale) (background dark))
935 (:foreground "LightGray" ,@font))
936 (((class color) (background light))
937 (:foreground "DarkOliveGreen" ,@font))
938 (((class color) (background dark))
939 (:foreground "OliveDrab" ,@font))
940 (t (,@font))))
941 "Face used to highlight text to be typeset in bold."
942 :group 'font-latex-highlighting-faces)
943
944 (defface font-latex-italic-face
945 (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit italic))
946 ((assq :slant custom-face-attributes) '(:slant italic))
947 (t '(:italic t)))))
948 `((((class grayscale) (background light))
949 (:foreground "DimGray" ,@font))
950 (((class grayscale) (background dark))
951 (:foreground "LightGray" ,@font))
952 (((class color) (background light))
953 (:foreground "DarkOliveGreen" ,@font))
954 (((class color) (background dark))
955 (:foreground "OliveDrab" ,@font))
956 (t (,@font))))
957 "Face used to highlight text to be typeset in italic."
958 :group 'font-latex-highlighting-faces)
959
960 (defface font-latex-math-face
961 (let ((font (cond ((assq :inherit custom-face-attributes)
962 '(:inherit underline))
963 (t '(:underline t)))))
964 `((((class grayscale) (background light))
965 (:foreground "DimGray" ,@font))
966 (((class grayscale) (background dark))
967 (:foreground "LightGray" ,@font))
968 (((class color) (background light))
969 (:foreground "SaddleBrown"))
970 (((class color) (background dark))
971 (:foreground "burlywood"))
972 (t (,@font))))
973 "Face used to highlight math."
974 :group 'font-latex-highlighting-faces)
975
976 (defface font-latex-sedate-face
977 '((((class grayscale) (background light)) (:foreground "DimGray"))
978 (((class grayscale) (background dark)) (:foreground "LightGray"))
979 (((class color) (background light)) (:foreground "DimGray"))
980 (((class color) (background dark)) (:foreground "LightGray"))
981 ;;;(t (:underline t))
982 )
983 "Face used to highlight sedate stuff."
984 :group 'font-latex-highlighting-faces)
985
986 (defface font-latex-string-face
987 (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit italic))
988 ((assq :slant custom-face-attributes) '(:slant italic))
989 (t '(:italic t)))))
990 `((((type tty) (class color))
991 (:foreground "green"))
992 (((class grayscale) (background light))
993 (:foreground "DimGray" ,@font))
994 (((class grayscale) (background dark))
995 (:foreground "LightGray" ,@font))
996 (((class color) (background light))
997 (:foreground "RosyBrown"))
998 (((class color) (background dark))
999 (:foreground "LightSalmon"))
1000 (t (,@font))))
1001 "Face used to highlight strings."
1002 :group 'font-latex-highlighting-faces)
1003
1004 (defface font-latex-warning-face
1005 (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit bold))
1006 ((assq :weight custom-face-attributes) '(:weight bold))
1007 (t '(:bold t)))))
1008 `((((class grayscale)(background light))
1009 (:foreground "DimGray" ,@font))
1010 (((class grayscale)(background dark))
1011 (:foreground "LightGray" ,@font))
1012 (((class color)(background light))
1013 (:foreground "red" ,@font))
1014 (((class color)(background dark))
1015 (:foreground "red" ,@font))
1016 (t (,@font))))
1017 "Face for important keywords."
1018 :group 'font-latex-highlighting-faces)
1019
1020 (defface font-latex-verbatim-face
1021 (let ((font (if (and (assq :inherit custom-face-attributes)
1022 (if (featurep 'xemacs)
1023 (find-face 'fixed-pitch)
1024 (facep 'fixed-pitch)))
1025 '(:inherit fixed-pitch)
1026 '(:family "courier"))))
1027 `((((class grayscale) (background light))
1028 (:foreground "DimGray" ,@font))
1029 (((class grayscale) (background dark))
1030 (:foreground "LightGray" ,@font))
1031 (((class color) (background light))
1032 (:foreground "SaddleBrown" ,@font))
1033 (((class color) (background dark))
1034 (:foreground "burlywood" ,@font))
1035 (t (,@font))))
1036 "Face used to highlight TeX verbatim environments."
1037 :group 'font-latex-highlighting-faces)
1038
1039 (defface font-latex-superscript-face
1040 '((t (:height 0.8)))
1041 "Face used for superscripts."
1042 :group 'font-latex-highlighting-faces)
1043
1044 (defface font-latex-subscript-face
1045 '((t (:height 0.8)))
1046 "Face used for subscripts."
1047 :group 'font-latex-highlighting-faces)
1048
1049 (defface font-latex-slide-title-face
1050 (let* ((scale 1.2)
1051 (size (when (featurep 'xemacs)
1052 (round (* 0.9 (face-height 'default) scale)))))
1053 (if (featurep 'xemacs)
1054 `((t (:bold t :family "helvetica" :size ,size)))
1055 `((t (:inherit (variable-pitch font-lock-type-face)
1056 :weight bold :height ,scale)))))
1057 "Face for slide titles."
1058 :group 'font-latex-highlighting-faces)
1059 (when (featurep 'xemacs)
1060 (set-face-parent 'font-latex-slide-title-face 'font-lock-type-face
1061 nil nil 'append))
1062
1063
1064 ;;; Setup
1065
1066 (defvar font-lock-comment-start-regexp nil
1067 "Regexp to match the start of a comment.")
1068
1069 (defvar font-latex-extend-region-functions nil
1070 "List of functions extending the region for multiline constructs.
1071
1072 Each function should accept two arguments, the begin and end of
1073 the region to be fontified, and return the new region start. If
1074 no extension is necessary, the original region start should be
1075 returned.
1076
1077 All specified functions will be called and the region extended
1078 backwards to the minimum over their return values.")
1079
1080 (defvar font-latex-syntax-alist
1081 ;; Use word syntax for @ because we use \> for matching macros and
1082 ;; we don't want \foo@bar to be found if we search for \foo.
1083 '((?\( . ".") (?\) . ".") (?$ . "\"") (?@ . "w"))
1084 "List of specifiers for the syntax alist of `font-lock-defaults'.")
1085
1086 (defun font-latex-add-to-syntax-alist (list)
1087 "Activate syntactic font locking for the entries in LIST.
1088 The entries are added to `font-latex-syntax-alist' and eventually
1089 end up in `font-lock-defaults'. Each entry in LIST should be a
1090 cons pair as expected by `font-lock-defaults'. The function also
1091 triggers Font Lock to recognize the change."
1092 (make-local-variable 'font-latex-syntax-alist)
1093 (nconc font-latex-syntax-alist list)
1094 ;; FIXME: Are there situations where we need to alter `font-lock-defaults'
1095 ;; directly?
1096 ;; (dolist (entry list)
1097 ;; (setcar (cdddr font-lock-defaults)
1098 ;; (cons entry (cadddr font-lock-defaults))))
1099 ;; Tell font-lock about the update.
1100 (setq font-lock-set-defaults nil)
1101 (font-lock-set-defaults))
1102
1103 ;;;###autoload
1104 (defun font-latex-setup ()
1105 "Setup this buffer for LaTeX font-lock. Usually called from a hook."
1106 (font-latex-set-syntactic-keywords)
1107 ;; Trickery to make $$ fontification be in `font-latex-math-face' while
1108 ;; strings get whatever `font-lock-string-face' has been set to.
1109 (when (fboundp 'built-in-face-specifiers)
1110 ;; Cool patch from Christoph Wedler...
1111 (let (instance)
1112 (mapc (lambda (property)
1113 (setq instance
1114 (face-property-instance 'font-latex-math-face property
1115 nil 0 t))
1116 (if (numberp instance)
1117 (setq instance
1118 (face-property-instance 'default property nil 0)))
1119 (or (numberp instance)
1120 (set-face-property 'font-lock-string-face property
1121 instance (current-buffer))))
1122 (built-in-face-specifiers))))
1123
1124 ;; Activate multi-line fontification facilities if available.
1125 (when (boundp 'font-lock-multiline)
1126 (set (make-local-variable 'font-lock-multiline) t))
1127
1128 ;; Functions for extending the region.
1129 (dolist (elt '(font-latex-extend-region-backwards-command-with-args
1130 font-latex-extend-region-backwards-command-in-braces
1131 font-latex-extend-region-backwards-quotation
1132 font-latex-extend-region-backwards-math-env
1133 font-latex-extend-region-backwards-math-envII))
1134 (add-to-list 'font-latex-extend-region-functions elt))
1135
1136 ;; Tell Font Lock about the support.
1137 (make-local-variable 'font-lock-defaults)
1138 ;; The test for `major-mode' currently only works with docTeX mode
1139 ;; because `TeX-install-font-lock' is called explicitely in
1140 ;; `doctex-mode'. In case other modes have to be distinguished as
1141 ;; well, remove the call to `TeX-install-font-lock' from
1142 ;; `VirTeX-common-initialization' and place it in the different
1143 ;; `xxx-mode' calls instead, but _after_ `major-mode' is set.
1144 (let ((defaults
1145 `((font-latex-keywords font-latex-keywords-1 font-latex-keywords-2)
1146 nil nil ,font-latex-syntax-alist nil))
1147 (variables
1148 '((font-lock-comment-start-regexp . "%")
1149 (font-lock-mark-block-function . mark-paragraph)
1150 (font-lock-fontify-region-function
1151 . font-latex-fontify-region)
1152 (font-lock-unfontify-region-function
1153 . font-latex-unfontify-region))))
1154 ;; Add the mode-dependent stuff to the basic variables defined above.
1155 (if (eq major-mode 'doctex-mode)
1156 (progn
1157 (setcar defaults (append (car defaults)
1158 '(font-latex-doctex-keywords)))
1159 (setq variables
1160 (append variables
1161 '((font-lock-syntactic-face-function
1162 . font-latex-doctex-syntactic-face-function)
1163 (font-lock-syntactic-keywords
1164 . font-latex-doctex-syntactic-keywords)))))
1165 (setq variables
1166 (append variables
1167 '((font-lock-syntactic-face-function
1168 . font-latex-syntactic-face-function)
1169 (font-lock-syntactic-keywords
1170 . font-latex-syntactic-keywords)))))
1171 ;; Cater for the idiosyncrasies of Emacs and XEmacs.
1172 (if (featurep 'xemacs)
1173 (progn
1174 ;; XEmacs does not set these variables via `font-lock-defaults'
1175 ;; but requires them to be set explicitely.
1176 (mapc (lambda (alist)
1177 (set (car alist) (cdr alist))) variables)
1178 ;; Has to be set to t as otherwise syntax properties will not be
1179 ;; be picked up during fontification.
1180 (set (make-local-variable 'lookup-syntax-properties) t))
1181 (setq defaults (append defaults variables)))
1182 ;; Set the defaults.
1183 (setq font-lock-defaults defaults)))
1184
1185 (defun font-latex-jit-lock-force-redisplay (buf start end)
1186 "Compatibility for Emacsen not offering `jit-lock-force-redisplay'."
1187 (if (fboundp 'jit-lock-force-redisplay)
1188 (jit-lock-force-redisplay buf start end)
1189 ;; The following block is an expansion of `jit-lock-force-redisplay'
1190 ;; and involved macros taken from CVS Emacs on 2007-04-28.
1191 (with-current-buffer buf
1192 (let ((modified (buffer-modified-p)))
1193 (unwind-protect
1194 (let ((buffer-undo-list t)
1195 (inhibit-read-only t)
1196 (inhibit-point-motion-hooks t)
1197 (inhibit-modification-hooks t)
1198 deactivate-mark
1199 buffer-file-name
1200 buffer-file-truename)
1201 (put-text-property start end 'fontified t))
1202 (unless modified
1203 (restore-buffer-modified-p nil)))))))
1204
1205 (defun font-latex-fontify-region (beg end &optional loudly)
1206 "Fontify region from BEG to END.
1207 If optional argument is non-nil, print status messages."
1208 (let ((extend-list (delq nil (mapcar (lambda (fun) (funcall fun beg end))
1209 font-latex-extend-region-functions))))
1210 (when extend-list
1211 (let ((orig-beg beg))
1212 (setq beg (apply 'min extend-list))
1213 (when (featurep 'jit-lock)
1214 ;; Stolen from `jit-lock-fontify-now' (2007-04-27) and
1215 ;; adapted. Without this stanza only the line in which a
1216 ;; change happened will refontified. The rest will only be
1217 ;; refontified upon redisplay.
1218 (run-with-timer 0 nil 'font-latex-jit-lock-force-redisplay
1219 (current-buffer) beg orig-beg))))
1220 (font-lock-default-fontify-region beg end loudly)))
1221
1222 ;; Copy and adaption of `tex-font-lock-unfontify-region' from
1223 ;; tex-mode.el in GNU Emacs on 2004-08-04.
1224 ;; (XEmacs passes a third argument to the function.)
1225 (defun font-latex-unfontify-region (beg end &rest ignored)
1226 "Unfontify region from BEG to END."
1227 (font-lock-default-unfontify-region beg end)
1228 ;; XEmacs does not provide `font-lock-extra-managed-props', so
1229 ;; remove the `font-latex-multiline' property manually. (The
1230 ;; property is only added if `font-lock-multiline' is bound.)
1231 (unless (boundp 'font-lock-multiline)
1232 (remove-text-properties beg end '(font-latex-multiline)))
1233 (while (< beg end)
1234 (let ((next (next-single-property-change beg 'display nil end))
1235 (prop (get-text-property beg 'display)))
1236 (if (and (eq (car-safe prop) 'raise)
1237 (member (car-safe (cdr prop))
1238 (list (nth 1 (car font-latex-script-display))
1239 (nth 1 (cdr font-latex-script-display))))
1240 (null (cddr prop)))
1241 (put-text-property beg next 'display nil))
1242 (setq beg next))))
1243
1244 (defadvice font-lock-after-change-function (before font-latex-after-change
1245 activate)
1246 "Extend region for fontification of multiline constructs.
1247 This is only necessary if the editor does not provide multiline
1248 fontification facilities like `font-lock-multiline' itself."
1249 (unless (boundp 'font-lock-multiline)
1250 (let ((ad-beg (ad-get-arg 0))
1251 (ad-end (ad-get-arg 1)))
1252 (save-excursion
1253 (goto-char ad-beg)
1254 (beginning-of-line)
1255 (when (get-text-property (point) 'font-latex-multiline)
1256 (setq ad-beg (previous-single-property-change (point)
1257 'font-latex-multiline))
1258 (when (numberp ad-beg)
1259 (ad-set-arg 0 ad-beg)))
1260 (goto-char ad-end)
1261 (end-of-line)
1262 (when (get-text-property (point) 'font-latex-multiline)
1263 (setq ad-end (next-single-property-change (point)
1264 'font-latex-multiline))
1265 (when (numberp ad-end)
1266 (ad-set-arg 1 ad-end)))))))
1267
1268
1269 ;;; Utility functions
1270
1271 (defun font-latex-find-matching-close (openchar closechar)
1272 "Skip over matching pairs of OPENCHAR and CLOSECHAR.
1273 OPENCHAR is the opening character and CLOSECHAR is the closing
1274 character. Character pairs are usually { } or [ ]. Comments are
1275 ignored during the search."
1276 (let ((parse-sexp-ignore-comments
1277 (not (eq major-mode 'doctex-mode))) ; scan-sexps ignores comments
1278 (init-point (point))
1279 (mycount 1)
1280 (esc-char (or (and (boundp 'TeX-esc) TeX-esc) "\\"))
1281 ;; XXX: Do not look up syntax-table properties since they may
1282 ;; be misleading, e.g. in the case of "{foo}^^A" where the
1283 ;; closing brace gets a comment end syntax.
1284 (parse-sexp-lookup-properties nil))
1285 (or
1286 (condition-case nil
1287 (progn
1288 (goto-char (with-syntax-table
1289 (TeX-search-syntax-table openchar closechar)
1290 (scan-sexps (point) 1)))
1291 ;; No error code. See if closechar is unquoted
1292 (save-excursion
1293 (backward-char 1)
1294 (zerop (mod (skip-chars-backward (regexp-quote esc-char)) 2))))
1295 (error nil))
1296 (save-match-data
1297 (goto-char (1+ init-point))
1298 (while (and (> mycount 0)
1299 (re-search-forward
1300 (string ?\[
1301 ;; closechar might be ]
1302 ;; and therefor must be first in regexp
1303 closechar openchar
1304 ?\])
1305 nil t))
1306 (cond
1307 ((font-latex-commented-outp)
1308 (forward-line 1))
1309 ((save-excursion
1310 (backward-char 1)
1311 (zerop (mod (skip-chars-backward (regexp-quote esc-char))
1312 2)))
1313 (setq mycount (+ mycount
1314 (if (= (preceding-char) openchar) 1 -1)))))))
1315 (if (= mycount 0)
1316 t
1317 (goto-char init-point)
1318 nil))))
1319
1320 (defun font-latex-commented-outp ()
1321 "Return t if comment character is found between bol and point."
1322 (save-excursion
1323 (let ((limit (point))
1324 (esc-char (if (and (boundp 'TeX-esc) TeX-esc) TeX-esc "\\")))
1325 (forward-line 0)
1326 (if (and (eq (char-after) ?\%)
1327 (not (font-latex-faces-present-p 'font-latex-verbatim-face)))
1328 (not (eq major-mode 'doctex-mode))
1329 (catch 'found
1330 (while (progn (skip-chars-forward "^%" limit)
1331 (< (point) limit))
1332 (when (and (save-excursion
1333 (zerop (mod (skip-chars-backward
1334 (regexp-quote esc-char)) 2)))
1335 (not (font-latex-faces-present-p
1336 'font-latex-verbatim-face)))
1337 (throw 'found t))
1338 (forward-char)))))))
1339
1340 (defun font-latex-faces-present-p (faces &optional pos)
1341 "Return t if FACES are present at position POS.
1342 FACES may be a single face or a list of faces.
1343 If POS is omitted, the current position of point is used."
1344 (let* ((faces (if (listp faces) faces (list faces)))
1345 (pos (or pos (point)))
1346 (prop (get-text-property pos 'face))
1347 (prop-list (if (listp prop) prop (list prop))))
1348 (catch 'member
1349 (dolist (item prop-list)
1350 (when (memq item faces)
1351 (throw 'member t))))))
1352
1353 (defun font-latex-forward-comment ()
1354 "Like `forward-comment' but with special provisions for docTeX mode.
1355 In docTeX mode \"%\" at the start of a line will be treated as whitespace."
1356 (if (eq major-mode 'doctex-mode)
1357 ;; XXX: We should probably cater for ^^A as well.
1358 (progn
1359 (while (progn (if (bolp) (skip-chars-forward "%"))
1360 (> (skip-chars-forward " \t\n") 0)))
1361 (when (eq (char-after) ?%)
1362 (beginning-of-line 2)
1363 t))
1364 (forward-comment 1)))
1365
1366 (defun font-latex-put-multiline-property-maybe (beg end)
1367 "Add a multiline property if no equivalent is provided by the editor.
1368 The text property is used to find the start or end of a multiline
1369 construct when unfontifying a region. Emacs adds such a text
1370 property automatically if `font-lock-multiline' is set to t and
1371 extends the region to be unfontified automatically as well.
1372 XEmacs does not do this at the time of this writing."
1373 (unless (boundp 'font-lock-multiline)
1374 (put-text-property beg end 'font-latex-multiline t)))
1375
1376
1377 ;;; Match functions
1378
1379 (defvar font-latex-matched-faces nil
1380 "List of faces corresponding to matches in match data.")
1381
1382 (defun font-latex-matched-face (pos)
1383 "Return face at position POS in `font-latex-matched-faces'."
1384 (nth pos font-latex-matched-faces))
1385
1386 (defvar font-latex-command-with-args-default-spec nil ; "*[{"
1387 "Default specifier for keywords without syntax description.
1388 Set this to nil if verification of command syntax is unwanted.")
1389
1390 (defvar font-latex-command-with-args-opt-arg-delims
1391 '((?[ . ?]) (?< . ?>) (?\( . ?\)))
1392 "List character pairs used as delimiters for optional arguments.")
1393
1394 (defvar font-latex-syntax-error-modes '(latex-mode)
1395 "List of modes where syntax errors in macros should be indicated.")
1396
1397 (defun font-latex-match-command-with-arguments (regexp keywords face limit)
1398 "Search for regexp command KEYWORDS[opt]{arg} before LIMIT.
1399 Returns nil if none of KEYWORDS is found."
1400 (setq font-latex-matched-faces nil)
1401 (catch 'match
1402 (while (re-search-forward regexp limit t)
1403 (unless (font-latex-faces-present-p '(font-lock-comment-face
1404 font-latex-verbatim-face)
1405 (match-beginning 0))
1406 (let* ((beg (match-beginning 0))
1407 end ; Used for multiline text property.
1408 match-data match-beg syntax-error alternative spec
1409 error-indicator-pos
1410 (spec-list (string-to-list
1411 (or (cadr (assoc (match-string 1) keywords))
1412 font-latex-command-with-args-default-spec)))
1413 (parse-sexp-ignore-comments t)) ; scan-sexps ignores comments
1414 (add-to-list 'match-data beg)
1415 (goto-char (match-end 0))
1416 ;; Check for starred macro if first spec is an asterisk.
1417 (when (eq (car spec-list) ?*)
1418 (setq spec-list (cdr spec-list))
1419 (skip-chars-forward "*" (1+ (point))))
1420 ;; Add current point to match data and use keyword face for
1421 ;; region from start to point.
1422 (add-to-list 'match-data (point) t)
1423 (add-to-list 'font-latex-matched-faces 'font-lock-keyword-face)
1424 (setq end (point))
1425 (catch 'break
1426 ;; Walk the list of specs.
1427 (while spec-list
1428 (setq spec (pop spec-list)
1429 error-indicator-pos beg)
1430 (while (and (not (eobp)) (font-latex-forward-comment)))
1431 ;; Alternative
1432 (when (eq spec ?|)
1433 (setq alternative t)
1434 (setq spec (pop spec-list)))
1435 (cond
1436 ;; Macros: \foo
1437 ((eq spec ?\\)
1438 (if (eq (char-after) spec)
1439 (progn
1440 (nconc match-data
1441 (list (point)
1442 (progn
1443 (forward-char)
1444 (if (zerop (skip-chars-forward "A-Za-z@"))
1445 (forward-char) ; Single-char macro.
1446 (skip-chars-forward "*"))
1447 (point))))
1448 (nconc font-latex-matched-faces (list face))
1449 (setq end (max end (point)))
1450 (when alternative (pop spec-list)))
1451 (setq syntax-error t)
1452 (throw 'break nil)))
1453 ;; Mandatory arguments: {...}
1454 ((eq spec ?{)
1455 (if (and (eq (char-after) spec)
1456 (setq match-beg (point))
1457 (font-latex-find-matching-close ?{ ?}))
1458 (progn
1459 (nconc match-data (list (1+ match-beg) (1- (point))))
1460 (nconc font-latex-matched-faces (list face))
1461 (setq end (max end (1- (point))))
1462 (when alternative (pop spec-list)))
1463 (unless alternative
1464 (setq syntax-error t)
1465 (when (and match-beg (= match-beg (point)))
1466 (setq error-indicator-pos match-beg))
1467 (throw 'break nil))))
1468 ;; Optional arguments: [...] and others
1469 ((eq (char-after) spec)
1470 (setq match-beg (point))
1471 (if (font-latex-find-matching-close
1472 spec (cdr (assq
1473 spec
1474 font-latex-command-with-args-opt-arg-delims)))
1475 (progn
1476 (nconc match-data (list (1+ match-beg) (1- (point))))
1477 (nconc font-latex-matched-faces
1478 (list 'font-lock-variable-name-face))
1479 (setq end (max end (1- (point)))))
1480 (setq syntax-error t
1481 error-indicator-pos match-beg)
1482 (throw 'break nil))))
1483 (setq alternative nil)))
1484 (when (and syntax-error (memq major-mode
1485 font-latex-syntax-error-modes))
1486 ;; Add the warning face at the front of the list because
1487 ;; the matcher uses 'append and the face would otherwise
1488 ;; be overridden by the keyword face.
1489 (setq match-data (append (list error-indicator-pos
1490 (1+ error-indicator-pos))
1491 match-data))
1492 (push 'font-latex-warning-face font-latex-matched-faces))
1493 (font-latex-put-multiline-property-maybe beg end)
1494 (store-match-data match-data)
1495 (throw 'match t))))))
1496
1497 (defun font-latex-extend-region-backwards-command-with-args (beg end)
1498 "Return position to extend region backwards for commands with args.
1499 Return nil if region does not have to be extended for a multiline
1500 macro to fit in. The region between the positions BEG and END
1501 marks boundaries for searching for macro ends."
1502 (save-excursion
1503 (goto-char end)
1504 (catch 'extend
1505 (while (TeX-search-backward-unescaped "}" beg t)
1506 (let ((macro-start (TeX-find-macro-start
1507 (max (point-min)
1508 (- beg font-latex-multiline-boundary)))))
1509 (when (and macro-start
1510 (< macro-start beg))
1511 (throw 'extend macro-start))))
1512 nil)))
1513
1514 (defun font-latex-match-command-in-braces (keywords limit)
1515 "Search for command like {\\bfseries fubar} before LIMIT.
1516 Sets `match-data' so that:
1517 subexpression 0 is a warning indicator,
1518 subexpression 1 is the keyword, and
1519 subexpression 2 is the rest in the TeX group.
1520 Returns nil if no command is found."
1521 (catch 'match
1522 (while (re-search-forward keywords limit t)
1523 (unless (font-latex-faces-present-p '(font-lock-comment-face
1524 font-latex-verbatim-face)
1525 (match-beginning 0))
1526 (let ((kbeg (match-beginning 0)) (kend (match-end 1))
1527 (beg (match-end 0))
1528 end cbeg cend
1529 (parse-sexp-ignore-comments t)) ; scan-sexps ignores comments
1530 (goto-char kbeg)
1531 (if (not (eq (preceding-char) ?\{))
1532 ;; Fontify only the keyword (no argument found).
1533 (progn
1534 (setq cbeg kbeg cend kend)
1535 (goto-char (match-end 0))
1536 (store-match-data (list (point) (point)
1537 (point) (point)
1538 cbeg cend))
1539 (throw 'match t))
1540 ;; There's an opening bracket
1541 (save-restriction
1542 ;; Restrict to LIMIT.
1543 (narrow-to-region (point-min) limit)
1544 (forward-char -1) ; Move on the opening bracket
1545 (if (font-latex-find-matching-close ?\{ ?\})
1546 (progn
1547 (font-latex-put-multiline-property-maybe beg (1- (point)))
1548 (store-match-data (list kbeg kbeg
1549 kbeg kend
1550 beg (1- (point)))))
1551 (goto-char kend)
1552 (store-match-data (list (1- kbeg) kbeg
1553 kbeg kend
1554 kend kend)))
1555 (throw 'match t))))))))
1556
1557 (defun font-latex-extend-region-backwards-command-in-braces (beg end)
1558 "Return position to extend region backwards for commands in braces.
1559 Return nil if region does not have to be extended for a multiline
1560 group to fit in. The region between the positions BEG and END
1561 marks boundaries for searching for group ends."
1562 (save-excursion
1563 (goto-char end)
1564 (catch 'extend
1565 (while (TeX-search-backward-unescaped "}" beg t)
1566 (let ((group-start (TeX-find-opening-brace
1567 nil (max (point-min)
1568 (- beg font-latex-multiline-boundary)))))
1569 (when group-start
1570 ;; XXX: Actually we'd have to check if any of the
1571 ;; declaration-type macros can be found right after the
1572 ;; brace. If we don't do this (like now) large regions
1573 ;; may be refontified for no good reason. For checking
1574 ;; the built-in `font-latex-match-*' variables for
1575 ;; declaration-type macros as well as the respective
1576 ;; user-defined variables could be concatenated.
1577 (goto-char group-start)
1578 (when (< group-start beg)
1579 (throw 'extend group-start)))))
1580 nil)))
1581
1582 (defun font-latex-match-simple-command (limit)
1583 "Search for command like \\foo before LIMIT."
1584 (TeX-re-search-forward-unescaped "\\\\[@A-Za-z]+" limit t))
1585
1586 (defun font-latex-match-math-env (limit)
1587 "Match math pattern up to LIMIT.
1588 Used for patterns like:
1589 \\( F = ma \\)
1590 \\[ F = ma \\] but not \\\\ [len]"
1591 (catch 'match
1592 (while (re-search-forward "\\(\\\\(\\)\\|\\(\\\\\\[\\)" limit t)
1593 (unless (save-excursion
1594 (goto-char (match-beginning 0))
1595 ;; \\[ does not start a math environment
1596 (/= (mod (skip-chars-backward "\\\\") 2) 0))
1597 (let ((beg (match-beginning 0))
1598 (open-tag (if (match-beginning 1) "\\(" "\\["))
1599 (close-tag (if (match-beginning 1) "\\)" "\\]")))
1600 ;; Search for both opening and closing tags in order to be
1601 ;; able to avoid erroneously matching stuff like "\(foo \(bar\)".
1602 (if (and (re-search-forward (concat "[^\\]\\(?:\\\\\\\\\\)*\\("
1603 (regexp-quote open-tag) "\\|"
1604 (regexp-quote close-tag) "\\)")
1605 limit 'move)
1606 (string= (match-string 1) close-tag))
1607 ;; Found closing tag.
1608 (progn
1609 (font-latex-put-multiline-property-maybe beg (point))
1610 (store-match-data (list beg beg beg (point))))
1611 ;; Did not find closing tag.
1612 (goto-char (+ beg 2))
1613 (store-match-data (list beg (point) (point) (point))))
1614 (throw 'match t))))))
1615
1616 (defun font-latex-extend-region-backwards-math-env (beg end)
1617 "Return position to extend region backwards for math environments.
1618 Return nil if region does not have to be extended for a multiline
1619 environment to fit in. The region between the positions BEG and
1620 END marks boundaries for searching for environment ends."
1621 (save-excursion
1622 (goto-char end)
1623 (catch 'extend
1624 (while (re-search-backward "\\(\\\\)\\)\\|\\(\\\\]\\)" beg t)
1625 (when (and (zerop (mod (skip-chars-backward "\\\\") 2))
1626 (re-search-backward
1627 (concat "[^\\]\\(?:\\\\\\\\\\)*\\("
1628 (regexp-quote (if (match-beginning 1) "\\(" "\\["))
1629 "\\)")
1630 (- beg font-latex-multiline-boundary) t)
1631 (goto-char (match-beginning 1))
1632 (< (point) beg))
1633 (throw 'extend (point))))
1634 nil)))
1635
1636 (defcustom font-latex-math-environments
1637 '("display" "displaymath" "equation" "eqnarray" "gather" "multline"
1638 "align" "alignat" "xalignat")
1639 "List of math environment names for font locking."
1640 :type '(repeat string)
1641 :group 'font-latex)
1642
1643 (defun font-latex-match-math-envII (limit)
1644 "Match math patterns up to LIMIT.
1645 Used for patterns like:
1646 \\begin{equation}
1647 fontified stuff
1648 \\end{equation}
1649 The \\begin{equation} and \\end{equation} are not fontified here."
1650 (when (re-search-forward (concat "\\\\begin[ \t]*{"
1651 (regexp-opt font-latex-math-environments t)
1652 "\\*?}")
1653 limit t)
1654 (let ((beg (match-end 0)) end)
1655 (if (re-search-forward (concat "\\\\end[ \t]*{"
1656 (regexp-quote
1657 (buffer-substring-no-properties
1658 (match-beginning 1)
1659 (match-end 0))))
1660 ;; XXX: Should this rather be done by
1661 ;; extending the region to be fontified?
1662 (+ limit font-latex-multiline-boundary) 'move)
1663 (setq end (match-beginning 0))
1664 (goto-char beg)
1665 (setq end beg))
1666 (font-latex-put-multiline-property-maybe beg end)
1667 (store-match-data (list beg end))
1668 t)))
1669
1670 (defun font-latex-extend-region-backwards-math-envII (beg end)
1671 "Return position to extend region backwards for math environments.
1672 Return nil if region does not have to be extended for a multiline
1673 environment to fit in. The region between the positions BEG and
1674 END marks boundaries for searching for environment ends."
1675 (save-excursion
1676 (goto-char end)
1677 (catch 'extend
1678 (while (re-search-backward
1679 (concat "\\\\end[ \t]*{"
1680 (regexp-opt font-latex-math-environments t)
1681 "\\*?}") beg t)
1682 (when (and (re-search-backward (concat "\\\\begin[ \t]*{"
1683 (buffer-substring-no-properties
1684 (match-beginning 1)
1685 (match-end 0)))
1686 (- beg font-latex-multiline-boundary) t)
1687 (< (point) beg))
1688 (throw 'extend (point))))
1689 nil)))
1690
1691 (defun font-latex-update-quote-list ()
1692 "Update quote list and regexp if value of `font-latex-quotes' changed."
1693 (unless (eq font-latex-quotes-control font-latex-quotes)
1694 (setq font-latex-quotes-control font-latex-quotes)
1695 (font-latex-quotes-set-internal)
1696 ;; Set order of each entry in `font-latex-quote-list' according to
1697 ;; setting of `font-latex-quotes-internal'.
1698 (let ((tail font-latex-quote-list)
1699 elt)
1700 (while tail
1701 (setq elt (car tail))
1702 (when (and (> (safe-length elt) 2)
1703 (not (eq (nth 2 elt) font-latex-quotes-internal)))
1704 (setcar tail (list (nth 1 elt) (nth 0 elt)
1705 font-latex-quotes-internal)))
1706 (setq tail (cdr tail))))
1707 (setq font-latex-quote-regexp-beg
1708 (regexp-opt (mapcar 'car font-latex-quote-list) t))))
1709
1710 (defun font-latex-match-quotation (limit)
1711 "Match quote patterns up to LIMIT.
1712 Used for patterns like:
1713 ``this is a normal quote'' and these are multilingual quoted strings:
1714 \"< french \"> and \"`german\"' quotes.
1715 The quotes << french >> and 8-bit french are used if `font-latex-quotes' is
1716 set to french, and >>german<< (and 8-bit) are used if set to german."
1717 (when font-latex-quotes
1718 (font-latex-update-quote-list)
1719 ;; Search for matches.
1720 (catch 'match
1721 (while (TeX-re-search-forward-unescaped
1722 font-latex-quote-regexp-beg limit t)
1723 (unless (font-latex-faces-present-p '(font-lock-comment-face
1724 font-latex-verbatim-face
1725 font-latex-math-face)
1726 (match-beginning 0))
1727 (let* ((beg (match-beginning 0))
1728 (after-beg (match-end 0))
1729 (opening-quote (match-string 0))
1730 (closing-quote
1731 (nth 1 (assoc (if (fboundp 'string-make-multibyte)
1732 (string-make-multibyte (match-string 0))
1733 (match-string 0))
1734 font-latex-quote-list)))
1735 (nest-count 0)
1736 (point-of-surrender (+ beg font-latex-multiline-boundary)))
1737 ;; Find closing quote taking nested quotes into account.
1738 (while (progn
1739 (re-search-forward
1740 (concat opening-quote "\\|" closing-quote)
1741 point-of-surrender 'move)
1742 (when (and (< (point) point-of-surrender) (not (eobp)))
1743 (if (string= (match-string 0) opening-quote)
1744 (setq nest-count (1+ nest-count))
1745 (when (/= nest-count 0)
1746 (setq nest-count (1- nest-count)))))))
1747 ;; If no closing quote was found, set the second match which
1748 ;; will be marked with warning color, if one was found, set
1749 ;; the first match which will be marked with string color.
1750 (if (or (= (point) point-of-surrender) (eobp))
1751 (progn
1752 (goto-char after-beg)
1753 (store-match-data (list after-beg after-beg beg after-beg)))
1754 (font-latex-put-multiline-property-maybe beg (point))
1755 (store-match-data (list beg (point) (point) (point))))
1756 (throw 'match t)))))))
1757
1758 (defun font-latex-extend-region-backwards-quotation (beg end)
1759 "Return position to extend region backwards for quotations.
1760 Return nil if region does not have to be extended for a multiline
1761 quotation to fit in. The region between the positions BEG and
1762 END marks boundaries for searching for quotation ends."
1763 (if font-latex-quotes
1764 (progn
1765 (font-latex-update-quote-list)
1766 (let ((regexp-end (regexp-opt (mapcar 'cadr font-latex-quote-list) t)))
1767 (save-excursion
1768 (goto-char end)
1769 (catch 'extend
1770 (while (re-search-backward regexp-end beg t)
1771 (let ((closing-quote (match-string 0))
1772 (nest-count 0)
1773 (point-of-surrender (- beg font-latex-multiline-boundary))
1774 opening-quote)
1775 (catch 'found
1776 (dolist (elt font-latex-quote-list)
1777 (when (string= (cadr elt) closing-quote)
1778 (setq opening-quote (car elt))
1779 (throw 'found nil))))
1780 ;; Find opening quote taking nested quotes into account.
1781 (while (progn
1782 (re-search-backward (concat opening-quote "\\|"
1783 closing-quote)
1784 point-of-surrender 'move)
1785 (when (and (> (point) point-of-surrender)
1786 (not (bobp)))
1787 (if (string= (match-string 0) closing-quote)
1788 (setq nest-count (1+ nest-count))
1789 (when (/= nest-count 0)
1790 (setq nest-count (1- nest-count)))))))
1791 (when (< (point) beg)
1792 (throw 'extend (point)))))
1793 nil))))
1794 nil))
1795
1796 (defun font-latex-match-script (limit)
1797 "Match subscript and superscript patterns up to LIMIT."
1798 (when (and font-latex-fontify-script
1799 (re-search-forward "[_^] *\\([^\n\\{}]\\|\
1800 \\\\\\([a-zA-Z@]+\\|[^ \t\n]\\)\\|\\({\\)\\)" limit t))
1801 (if (font-latex-faces-present-p '(font-latex-subscript-face
1802 font-latex-superscript-face))
1803 ;; Apply subscript and superscript highlighting only once in
1804 ;; order to prevent the font size becoming too small. We set
1805 ;; an empty match to do that.
1806 (let ((point (point)))
1807 (store-match-data (list point point point point)))
1808 (when (match-end 3)
1809 (let ((beg (match-beginning 3))
1810 (end (TeX-find-closing-brace
1811 ;; Don't match groups spanning more than one line
1812 ;; in order to avoid visually wrong indentation in
1813 ;; subsequent lines.
1814 nil (line-end-position))))
1815 (store-match-data (if end
1816 (list (match-beginning 0) end beg end)
1817 (list beg beg beg beg))))))
1818 t))
1819
1820 ;; Copy and adaption of `tex-font-lock-suscript' from tex-mode.el in
1821 ;; GNU Emacs on 2004-07-07.
1822 (defun font-latex-script (pos)
1823 "Return face and display spec for subscript and superscript content."
1824 (when (and (font-latex-faces-present-p 'font-latex-math-face pos)
1825 (not (font-latex-faces-present-p '(font-lock-constant-face
1826 font-lock-builtin-face
1827 font-lock-comment-face
1828 font-latex-verbatim-face) pos))
1829 ;; Check for backslash quoting
1830 (not (let ((odd nil)
1831 (pos pos))
1832 (while (eq (char-before pos) ?\\)
1833 (setq pos (1- pos) odd (not odd)))
1834 odd)))
1835 ;; Adding other text properties than `face' is supported by
1836 ;; `font-lock-apply-highlight' in CVS Emacsen since 2001-10-28.
1837 ;; With the introduction of this feature the variable
1838 ;; `font-lock-extra-managed-props' was introduced and serves here
1839 ;; for feature checking. XEmacs (CVS and 21.4.15) currently
1840 ;; (2004-08-18) does not support this feature.
1841 (let ((extra-props-flag (boundp 'font-lock-extra-managed-props)))
1842 (if (eq (char-after pos) ?_)
1843 (if extra-props-flag
1844 `(face font-latex-subscript-face display
1845 ,(car font-latex-script-display))
1846 'font-latex-subscript-face)
1847 (if extra-props-flag
1848 `(face font-latex-superscript-face display
1849 ,(cdr font-latex-script-display))
1850 'font-latex-superscript-face)))))
1851
1852
1853 ;;; docTeX
1854
1855 (defvar font-latex-doctex-preprocessor-face
1856 'font-latex-doctex-preprocessor-face
1857 "Face used to highlight preprocessor directives in docTeX mode.")
1858
1859 (defface font-latex-doctex-preprocessor-face
1860 '((t (:inherit (font-latex-doctex-documentation-face
1861 font-lock-builtin-face ; Emacs 21 does not provide
1862 ; the preprocessor face.
1863 font-lock-preprocessor-face))))
1864 "Face used to highlight preprocessor directives in docTeX mode."
1865 :group 'font-latex-highlighting-faces)
1866
1867 (defvar font-latex-doctex-documentation-face
1868 'font-latex-doctex-documentation-face
1869 "Face used to highlight the documentation in docTeX mode.")
1870
1871 (defface font-latex-doctex-documentation-face
1872 '((((class mono)) (:inverse-video t))
1873 (((class grayscale) (background dark)) (:background "#333"))
1874 (((class color) (background dark)) (:background "#333"))
1875 (t (:background "#eeeeee")))
1876 "Face used to highlight the documentation parts in docTeX mode."
1877 :group 'font-latex-highlighting-faces)
1878
1879 (defvar font-latex-doctex-keywords
1880 (append font-latex-keywords-2
1881 '(("^%<[^>]*>" (0 font-latex-doctex-preprocessor-face t)))))
1882
1883 ;; Set and updated in `font-latex-set-syntactic-keywords'.
1884 (defvar font-latex-doctex-syntactic-keywords nil)
1885
1886 ;; Copy and adaptation of `doctex-font-lock-^^A' in `tex-mode.el' of
1887 ;; CVS Emacs (March 2004)
1888 (defun font-latex-doctex-^^A ()
1889 (if (eq (char-after (line-beginning-position)) ?\%)
1890 (progn
1891 (put-text-property
1892 (1- (match-beginning 1)) (match-beginning 1) 'syntax-table
1893 (if (= (1+ (line-beginning-position)) (match-beginning 1))
1894 ;; The `%' is a single-char comment, which Emacs
1895 ;; syntax-table can't deal with. We could turn it
1896 ;; into a non-comment, or use `\n%' or `%^' as the comment.
1897 ;; Instead, we include it in the ^^A comment.
1898 ;; COMPATIBILITY for Emacs 20 and XEmacs
1899 (eval-when-compile (if (fboundp 'string-to-syntax)
1900 (string-to-syntax "< b")
1901 '(2097163)))
1902 ;; COMPATIBILITY for Emacs 20 and XEmacs
1903 (eval-when-compile (if (fboundp 'string-to-syntax)
1904 (string-to-syntax ">")
1905 '(12)))))
1906 (let ((end (line-end-position)))
1907 (if (< end (point-max))
1908 (put-text-property end (1+ end) 'syntax-table
1909 ;; COMPATIBILITY for Emacs 20 and XEmacs
1910 (eval-when-compile
1911 (if (fboundp 'string-to-syntax)
1912 (string-to-syntax "> b")
1913 '(2097164))))))
1914 ;; COMPATIBILITY for Emacs 20 and XEmacs
1915 (eval-when-compile (if (fboundp 'string-to-syntax)
1916 (string-to-syntax "< b")
1917 '(2097163))))))
1918
1919 ;; Copy and adaptation of `doctex-font-lock-syntactic-face-function'
1920 ;; in `tex-mode.el' of CVS Emacs (March 2004)
1921 (defun font-latex-doctex-syntactic-face-function (state)
1922 ;; Mark docTeX documentation, which is parsed as a style A comment
1923 ;; starting in column 0.
1924 (if (or (nth 3 state) (nth 7 state)
1925 (not (memq (char-before (nth 8 state))
1926 '(?\n nil))))
1927 ;; Anything else is just as for LaTeX.
1928 (font-latex-syntactic-face-function state)
1929 font-latex-doctex-documentation-face))
1930
1931
1932 ;;; Installation in non-AUCTeX LaTeX mode
1933
1934 (add-hook 'latex-mode-hook 'font-latex-setup)
1935 ;; If font-latex is loaded using a latex-mode-hook, then the add-hook above
1936 ;; won't be called this time around. Check for this now:
1937 (if (eq major-mode 'latex-mode)
1938 (font-latex-setup))
1939
1940
1941 ;;; Byte-compilation of generated functions
1942
1943 (when (byte-code-function-p
1944 (symbol-function 'font-latex-make-built-in-keywords))
1945 (dolist (elt font-latex-built-in-keyword-classes)
1946 (let ((name (nth 0 elt)))
1947 (byte-compile (intern (concat "font-latex-" name)))
1948 (byte-compile (intern (concat "font-latex-" name "-make"))))))
1949
1950
1951 ;; Provide ourselves:
1952 (provide 'font-latex)
1953
1954 ;; Local Variables:
1955 ;; coding: iso-8859-1
1956 ;; End:
1957
1958 ;;; font-latex.el ends here