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