(font-lock-keywords): Add defvar.
[bpt/emacs.git] / lisp / textmodes / tex-mode.el
CommitLineData
95a045bd 1;;; tex-mode.el --- TeX, LaTeX, and SliTeX mode commands -*- coding: utf-8 -*-
d501f516 2
dd166d5f 3;; Copyright (C) 1985, 1986, 1989, 1992, 1994, 1995, 1996, 1997, 1998, 1999,
3731a850 4;; 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
eea8d4ef 5
70f20973 6;; Maintainer: FSF
d7b4d18f 7;; Keywords: tex
e5167999 8
528415e7 9;; Contributions over the years by William F. Schelter, Dick King,
70f20973 10;; Stephen Gildea, Michael Prange, Jacob Gore, and Edward M. Reingold.
528415e7 11
869bff31 12;; This file is part of GNU Emacs.
13
14;; GNU Emacs is free software; you can redistribute it and/or modify
15;; it under the terms of the GNU General Public License as published by
e5167999 16;; the Free Software Foundation; either version 2, or (at your option)
869bff31 17;; any later version.
18
19;; GNU Emacs 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
6da9bbd6 25;; along with GNU Emacs; see the file COPYING. If not, write to the
4fc5845f
LK
26;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27;; Boston, MA 02110-1301, USA.
869bff31 28
55535639
PJ
29;;; Commentary:
30
e5167999
ER
31;;; Code:
32
bed1b0c8
RS
33;; Pacify the byte-compiler
34(eval-when-compile
35 (require 'compare-w)
ea590e1c 36 (require 'cl)
bed1b0c8
RS
37 (require 'skeleton))
38
a0e9c22a 39(require 'shell)
2f3067de 40(require 'compile)
528415e7 41
d61140e8 42(defgroup tex-file nil
d1218e3e 43 "TeX files and directories."
d61140e8
RS
44 :prefix "tex-"
45 :group 'tex)
46
47(defgroup tex-run nil
d1218e3e 48 "Running external commands from TeX mode."
d61140e8
RS
49 :prefix "tex-"
50 :group 'tex)
51
52(defgroup tex-view nil
d1218e3e 53 "Viewing and printing TeX files."
d61140e8
RS
54 :prefix "tex-"
55 :group 'tex)
56
7e1dae73 57;;;###autoload
d61140e8
RS
58(defcustom tex-shell-file-name nil
59 "*If non-nil, the shell file name to run in the subshell used to run TeX."
60 :type '(choice (const :tag "None" nil)
61 string)
62 :group 'tex-run)
528415e7 63
7e1dae73 64;;;###autoload
d61140e8 65(defcustom tex-directory "."
f73741fc 66 "*Directory in which temporary files are written.
81c735c0 67You can make this `/tmp' if your TEXINPUTS has no relative directories in it
528415e7 68and you don't try to apply \\[tex-region] or \\[tex-buffer] when there are
d61140e8
RS
69`\\input' commands with relative directories."
70 :type 'directory
71 :group 'tex-file)
869bff31 72
725b7428 73;;;###autoload
d61140e8 74(defcustom tex-first-line-header-regexp nil
725b7428
RS
75 "Regexp for matching a first line which `tex-region' should include.
76If this is non-nil, it should be a regular expression string;
77if it matches the first line of the file,
d61140e8
RS
78`tex-region' always includes the first line in the TeX run."
79 :type '(choice (const :tag "None" nil)
80 regexp)
81 :group 'tex-file)
725b7428 82
f73741fc 83;;;###autoload
d61140e8 84(defcustom tex-main-file nil
f73741fc 85 "*The main TeX source file which includes this buffer's file.
be4a962d
RS
86The command `tex-file' runs TeX on the file specified by `tex-main-file'
87if the variable is non-nil."
d61140e8
RS
88 :type '(choice (const :tag "None" nil)
89 file)
90 :group 'tex-file)
f73741fc 91
7e1dae73 92;;;###autoload
d61140e8
RS
93(defcustom tex-offer-save t
94 "*If non-nil, ask about saving modified buffers before \\[tex-file] is run."
95 :type 'boolean
96 :group 'tex-file)
869bff31 97
7e1dae73 98;;;###autoload
d61140e8 99(defcustom tex-run-command "tex"
869bff31 100 "*Command used to run TeX subjob.
c3ce7bf4
RS
101TeX Mode sets `tex-command' to this string.
102See the documentation of that variable."
d61140e8
RS
103 :type 'string
104 :group 'tex-run)
869bff31 105
7e1dae73 106;;;###autoload
d61140e8 107(defcustom latex-run-command "latex"
869bff31 108 "*Command used to run LaTeX subjob.
c3ce7bf4
RS
109LaTeX Mode sets `tex-command' to this string.
110See the documentation of that variable."
d61140e8
RS
111 :type 'string
112 :group 'tex-run)
528415e7 113
bed1b0c8
RS
114;;;###autoload
115(defcustom slitex-run-command "slitex"
116 "*Command used to run SliTeX subjob.
c3ce7bf4
RS
117SliTeX Mode sets `tex-command' to this string.
118See the documentation of that variable."
bed1b0c8
RS
119 :type 'string
120 :group 'tex-run)
121
c3ce7bf4 122;;;###autoload
95a045bd 123(defcustom tex-start-options ""
9e0ad27a 124 "*TeX options to use when starting TeX.
95a045bd
SM
125These immediately precede the commands in `tex-start-commands'
126and the input file name, with no separating space and are not shell-quoted.
127If nil, TeX runs with no options. See the documentation of `tex-command'."
128 :type 'string
bed1b0c8 129 :group 'tex-run
bf247b6e 130 :version "22.1")
9e0ad27a
RS
131
132;;;###autoload
133(defcustom tex-start-commands "\\nonstopmode\\input"
134 "*TeX commands to use when starting TeX.
95a045bd
SM
135They are shell-quoted and precede the input file name, with a separating space.
136If nil, no commands are used. See the documentation of `tex-command'."
9e0ad27a
RS
137 :type '(radio (const :tag "Interactive \(nil\)" nil)
138 (const :tag "Nonstop \(\"\\nonstopmode\\input\"\)"
139 "\\nonstopmode\\input")
140 (string :tag "String at your choice"))
141 :group 'tex-run
bf247b6e 142 :version "22.1")
bed1b0c8 143
7afecb99 144(defvar latex-standard-block-names
dd459839
SM
145 '("abstract" "array" "center" "description"
146 "displaymath" "document" "enumerate" "eqnarray"
147 "eqnarray*" "equation" "figure" "figure*"
148 "flushleft" "flushright" "itemize" "letter"
149 "list" "minipage" "picture" "quotation"
150 "quote" "slide" "sloppypar" "tabbing"
151 "table" "table*" "tabular" "tabular*"
152 "thebibliography" "theindex*" "titlepage" "trivlist"
153 "verbatim" "verbatim*" "verse" "math")
528415e7
RS
154 "Standard LaTeX block names.")
155
7e1dae73 156;;;###autoload
d61140e8 157(defcustom latex-block-names nil
528415e7 158 "*User defined LaTeX block names.
7afecb99 159Combined with `latex-standard-block-names' for minibuffer completion."
d61140e8
RS
160 :type '(repeat string)
161 :group 'tex-run)
869bff31 162
7e1dae73 163;;;###autoload
d61140e8 164(defcustom tex-bibtex-command "bibtex"
528415e7 165 "*Command used by `tex-bibtex-file' to gather bibliographic data.
81c735c0 166If this string contains an asterisk (`*'), that is replaced by the file name;
d61140e8
RS
167otherwise, the file name, preceded by blank, is added at the end."
168 :type 'string
169 :group 'tex-run)
869bff31 170
7e1dae73 171;;;###autoload
d61140e8 172(defcustom tex-dvi-print-command "lpr -d"
528415e7 173 "*Command used by \\[tex-print] to print a .dvi file.
81c735c0 174If this string contains an asterisk (`*'), that is replaced by the file name;
d61140e8
RS
175otherwise, the file name, preceded by blank, is added at the end."
176 :type 'string
177 :group 'tex-view)
528415e7 178
7e1dae73 179;;;###autoload
d61140e8 180(defcustom tex-alt-dvi-print-command "lpr -d"
528415e7 181 "*Command used by \\[tex-print] with a prefix arg to print a .dvi file.
81c735c0
RS
182If this string contains an asterisk (`*'), that is replaced by the file name;
183otherwise, the file name, preceded by blank, is added at the end.
528415e7 184
81c735c0
RS
185If two printers are not enough of a choice, you can set the variable
186`tex-alt-dvi-print-command' to an expression that asks what you want;
528415e7
RS
187for example,
188
189 (setq tex-alt-dvi-print-command
190 '(format \"lpr -P%s\" (read-string \"Use printer: \")))
191
192would tell \\[tex-print] with a prefix argument to ask you which printer to
d61140e8
RS
193use."
194 :type '(choice (string :tag "Command")
195 (sexp :tag "Expression"))
196 :group 'tex-view)
869bff31 197
7e1dae73 198;;;###autoload
dd166d5f
SM
199(defcustom tex-dvi-view-command
200 '(cond
201 ((eq window-system 'x) "xdvi")
bf247b6e 202 ((eq window-system 'w32) "yap")
dd166d5f 203 (t "dvi2tty * | cat -s"))
81c735c0 204 "*Command used by \\[tex-view] to display a `.dvi' file.
746c30e2 205If it is a string, that specifies the command directly.
81c735c0 206If this string contains an asterisk (`*'), that is replaced by the file name;
746c30e2 207otherwise, the file name, preceded by a space, is added at the end.
528415e7 208
746c30e2
RS
209If the value is a form, it is evaluated to get the command to use."
210 :type '(choice (const nil) string sexp)
d61140e8 211 :group 'tex-view)
869bff31 212
7e1dae73 213;;;###autoload
d61140e8 214(defcustom tex-show-queue-command "lpq"
528415e7 215 "*Command used by \\[tex-show-print-queue] to show the print queue.
d61140e8
RS
216Should show the queue(s) that \\[tex-print] puts jobs on."
217 :type 'string
218 :group 'tex-view)
869bff31 219
7e1dae73 220;;;###autoload
9920303f 221(defcustom tex-default-mode 'latex-mode
869bff31 222 "*Mode to enter for a new file that might be either TeX or LaTeX.
223This variable is used when it can't be determined whether the file
224is plain TeX or LaTeX or what because the file contains no commands.
d61140e8
RS
225Normally set to either `plain-tex-mode' or `latex-mode'."
226 :type 'function
227 :group 'tex)
869bff31 228
7e1dae73 229;;;###autoload
d61140e8
RS
230(defcustom tex-open-quote "``"
231 "*String inserted by typing \\[tex-insert-quote] to open a quotation."
232 :type 'string
95a045bd 233 :options '("``" "\"<" "\"`" "<<" "«")
d61140e8 234 :group 'tex)
869bff31 235
7e1dae73 236;;;###autoload
d61140e8
RS
237(defcustom tex-close-quote "''"
238 "*String inserted by typing \\[tex-insert-quote] to close a quotation."
239 :type 'string
95a045bd 240 :options '("''" "\">" "\"'" ">>" "»")
d61140e8 241 :group 'tex)
869bff31 242
528415e7
RS
243(defvar tex-last-temp-file nil
244 "Latest temporary file generated by \\[tex-region] and \\[tex-buffer].
245Deleted when the \\[tex-region] or \\[tex-buffer] is next run, or when the
81c735c0 246tex shell terminates.")
528415e7 247
95a045bd 248(defvar tex-command "tex"
c3ce7bf4 249 "*Command to run TeX.
95a045bd 250If this string contains an asterisk \(`*'\), that is replaced by the file name;
9e0ad27a
RS
251otherwise the value of `tex-start-options', the \(shell-quoted\)
252value of `tex-start-commands', and the file name are added at the end
253with blanks as separators.
c3ce7bf4
RS
254
255In TeX, LaTeX, and SliTeX Mode this variable becomes buffer local.
256In these modes, use \\[set-variable] if you want to change it for the
257current buffer.")
869bff31 258
259(defvar tex-trailer nil
260 "String appended after the end of a region sent to TeX by \\[tex-region].")
261
262(defvar tex-start-of-header nil
898b9ac1 263 "Regular expression used by \\[tex-region] to find start of file's header.")
869bff31 264
265(defvar tex-end-of-header nil
898b9ac1 266 "Regular expression used by \\[tex-region] to find end of file's header.")
869bff31 267
268(defvar tex-shell-cd-command "cd"
269 "Command to give to shell running TeX to change directory.
81c735c0 270The value of `tex-directory' is appended to this, separated by a space.")
869bff31 271
272(defvar tex-zap-file nil
273 "Temporary file name used for text being sent as input to TeX.
274Should be a simple file name with no extension or directory specification.")
275
276(defvar tex-last-buffer-texed nil
277 "Buffer which was last TeXed.")
278
279(defvar tex-print-file nil
280 "File name that \\[tex-print] prints.
281Set by \\[tex-region], \\[tex-buffer], and \\[tex-file].")
282
8a591d52
SM
283(defvar tex-mode-syntax-table
284 (let ((st (make-syntax-table)))
285 (modify-syntax-entry ?% "<" st)
286 (modify-syntax-entry ?\n ">" st)
287 (modify-syntax-entry ?\f ">" st)
288 (modify-syntax-entry ?\C-@ "w" st)
289 (modify-syntax-entry ?' "w" st)
290 (modify-syntax-entry ?@ "_" st)
291 (modify-syntax-entry ?* "_" st)
292 (modify-syntax-entry ?\t " " st)
bca7a08b
SM
293 ;; ~ is printed by TeX as a space, but it's semantics in the syntax
294 ;; of TeX is not `whitespace' (i.e. it's just like \hspace{foo}).
8a591d52
SM
295 (modify-syntax-entry ?~ "." st)
296 (modify-syntax-entry ?$ "$$" st)
297 (modify-syntax-entry ?\\ "/" st)
298 (modify-syntax-entry ?\" "." st)
299 (modify-syntax-entry ?& "." st)
300 (modify-syntax-entry ?_ "." st)
301 (modify-syntax-entry ?^ "." st)
302 st)
869bff31 303 "Syntax table used while in TeX mode.")
53c4fe47
SM
304\f
305;;;;
306;;;; Imenu support
307;;;;
869bff31 308
d6709b80 309(defcustom latex-imenu-indent-string ". "
a53c647b
RS
310 "*String to add repeated in front of nested sectional units for Imenu.
311An alternative value is \" . \", if you use a font with a narrow period."
312 :type 'string
313 :group 'tex)
314
d6709b80
SM
315(defvar latex-section-alist
316 '(("part" . 0) ("chapter" . 1)
317 ("section" . 2) ("subsection" . 3)
318 ("subsubsection" . 4)
319 ("paragraph" . 5) ("subparagraph" . 6)))
320
53c4fe47
SM
321(defvar latex-metasection-list
322 '("documentstyle" "documentclass"
323 "begin{document}" "end{document}"
324 "appendix" "frontmatter" "mainmatter" "backmatter"))
325
a5e2ae01 326(defun latex-imenu-create-index ()
53c4fe47
SM
327 "Generate an alist for imenu from a LaTeX buffer."
328 (let ((section-regexp
329 (concat "\\\\" (regexp-opt (mapcar 'car latex-section-alist) t)
330 "\\*?[ \t]*{"))
331 (metasection-regexp
332 (concat "\\\\" (regexp-opt latex-metasection-list t)))
333 i0 menu case-fold-search)
a53c647b
RS
334 (save-excursion
335 ;; Find the top-most level in this file but don't allow it to be
336 ;; any deeper than "section" (which is top-level in an article).
337 (goto-char (point-min))
338 (if (search-forward-regexp "\\\\part\\*?[ \t]*{" nil t)
339 (setq i0 0)
340 (if (search-forward-regexp "\\\\chapter\\*?[ \t]*{" nil t)
341 (setq i0 1)
342 (setq i0 2)))
343
344 ;; Look for chapters and sections.
345 (goto-char (point-min))
53c4fe47 346 (while (search-forward-regexp section-regexp nil t)
a53c647b
RS
347 (let ((start (match-beginning 0))
348 (here (point))
349 (i (cdr (assoc (buffer-substring-no-properties
350 (match-beginning 1)
351 (match-end 1))
d6709b80 352 latex-section-alist))))
a53c647b
RS
353 (backward-char 1)
354 (condition-case err
355 (progn
356 ;; Using sexps allows some use of matching {...} inside
357 ;; titles.
358 (forward-sexp 1)
d6709b80
SM
359 (push (cons (concat (apply 'concat
360 (make-list
361 (max 0 (- i i0))
362 latex-imenu-indent-string))
363 (buffer-substring-no-properties
364 here (1- (point))))
365 start)
366 menu))
a53c647b
RS
367 (error nil))))
368
369 ;; Look for included material.
370 (goto-char (point-min))
371 (while (search-forward-regexp
372 "\\\\\\(include\\|input\\|verbatiminput\\|bibliography\\)\
53c4fe47 373\[ \t]*{\\([^}\n]+\\)}"
a53c647b 374 nil t)
53c4fe47
SM
375 (push (cons (concat "<<" (buffer-substring-no-properties
376 (match-beginning 2)
377 (match-end 2))
378 (if (= (char-after (match-beginning 1)) ?b)
379 ".bbl"
380 ".tex"))
381 (match-beginning 0))
382 menu))
a53c647b
RS
383
384 ;; Look for \frontmatter, \mainmatter, \backmatter, and \appendix.
385 (goto-char (point-min))
53c4fe47
SM
386 (while (search-forward-regexp metasection-regexp nil t)
387 (push (cons "--" (match-beginning 0)) menu))
a53c647b
RS
388
389 ;; Sort in increasing buffer position order.
390 (sort menu (function (lambda (a b) (< (cdr a) (cdr b))))))))
53c4fe47
SM
391\f
392;;;;
393;;;; Outline support
394;;;;
395
396(defvar latex-outline-regexp
397 (concat "\\\\"
398 (regexp-opt (append latex-metasection-list
399 (mapcar 'car latex-section-alist)) t)))
400
401(defun latex-outline-level ()
402 (if (looking-at latex-outline-regexp)
403 (1+ (or (cdr (assoc (match-string 1) latex-section-alist)) -1))
404 1000))
405\f
406;;;;
407;;;; Font-Lock support
408;;;;
409
410;(defvar tex-font-lock-keywords
411; ;; Regexps updated with help from Ulrik Dickow <dickow@nbi.dk>.
412; '(("\\\\\\(begin\\|end\\|newcommand\\){\\([a-zA-Z0-9\\*]+\\)}"
413; 2 font-lock-function-name-face)
414; ("\\\\\\(cite\\|label\\|pageref\\|ref\\){\\([^} \t\n]+\\)}"
415; 2 font-lock-constant-face)
416; ;; It seems a bit dubious to use `bold' and `italic' faces since we might
417; ;; not be able to display those fonts.
418; ("{\\\\bf\\([^}]+\\)}" 1 'bold keep)
419; ("{\\\\\\(em\\|it\\|sl\\)\\([^}]+\\)}" 2 'italic keep)
420; ("\\\\\\([a-zA-Z@]+\\|.\\)" . font-lock-keyword-face)
421; ("^[ \t\n]*\\\\def[\\\\@]\\(\\w+\\)" 1 font-lock-function-name-face keep))
422; ;; Rewritten and extended for LaTeX2e by Ulrik Dickow <dickow@nbi.dk>.
423; '(("\\\\\\(begin\\|end\\|newcommand\\){\\([a-zA-Z0-9\\*]+\\)}"
424; 2 font-lock-function-name-face)
425; ("\\\\\\(cite\\|label\\|pageref\\|ref\\){\\([^} \t\n]+\\)}"
426; 2 font-lock-constant-face)
427; ("^[ \t]*\\\\def\\\\\\(\\(\\w\\|@\\)+\\)" 1 font-lock-function-name-face)
428; "\\\\\\([a-zA-Z@]+\\|.\\)"
429; ;; It seems a bit dubious to use `bold' and `italic' faces since we might
430; ;; not be able to display those fonts.
431; ;; LaTeX2e: \emph{This is emphasized}.
432; ("\\\\emph{\\([^}]+\\)}" 1 'italic keep)
433; ;; LaTeX2e: \textbf{This is bold}, \textit{...}, \textsl{...}
434; ("\\\\text\\(\\(bf\\)\\|it\\|sl\\){\\([^}]+\\)}"
435; 3 (if (match-beginning 2) 'bold 'italic) keep)
436; ;; Old-style bf/em/it/sl. Stop at `\\' and un-escaped `&', for tables.
437; ("\\\\\\(\\(bf\\)\\|em\\|it\\|sl\\)\\>\\(\\([^}&\\]\\|\\\\[^\\]\\)+\\)"
438; 3 (if (match-beginning 2) 'bold 'italic) keep))
439
440;; Rewritten with the help of Alexandra Bac <abac@welcome.disi.unige.it>.
441(defconst tex-font-lock-keywords-1
442 (eval-when-compile
443 (let* (;; Names of commands whose arg should be fontified as heading, etc.
444 (headings (regexp-opt
445 '("title" "begin" "end" "chapter" "part"
446 "section" "subsection" "subsubsection"
447 "paragraph" "subparagraph" "subsubparagraph"
7afecb99
SM
448 "newcommand" "renewcommand" "providecommand"
449 "newenvironment" "renewenvironment"
450 "newtheorem" "renewtheorem")
53c4fe47
SM
451 t))
452 (variables (regexp-opt
453 '("newcounter" "newcounter*" "setcounter" "addtocounter"
454 "setlength" "addtolength" "settowidth")
455 t))
456 (includes (regexp-opt
457 '("input" "include" "includeonly" "bibliography"
458 "epsfig" "psfig" "epsf" "nofiles" "usepackage"
15ca8de7 459 "documentstyle" "documentclass" "verbatiminput"
dd166d5f
SM
460 "includegraphics" "includegraphics*"
461 "url" "nolinkurl")
53c4fe47
SM
462 t))
463 ;; Miscellany.
464 (slash "\\\\")
15ca8de7
SM
465 (opt " *\\(\\[[^]]*\\] *\\)*")
466 ;; This would allow highlighting \newcommand\CMD but requires
467 ;; adapting subgroup numbers below.
468 ;; (arg "\\(?:{\\(\\(?:[^{}\\]+\\|\\\\.\\|{[^}]*}\\)+\\)\\|\\\\[a-z*]+\\)"))
1598a961 469 (arg "{\\(\\(?:[^{}\\]+\\|\\\\.\\|{[^}]*}\\)+\\)"))
53c4fe47 470 (list
b119fdd5
SM
471 ;; font-lock-syntactic-keywords causes the \ of \end{verbatim} to be
472 ;; highlighted as tex-verbatim-face. Let's undo that.
473 ;; This is ugly and brittle :-( --Stef
474 '("^\\(\\\\\\)end" (1 (get-text-property (match-end 1) 'face) t))
95a045bd
SM
475 ;; display $$ math $$
476 ;; We only mark the match between $$ and $$ because the $$ delimiters
477 ;; themselves have already been marked (along with $..$) by syntactic
478 ;; fontification. Also this is done at the very beginning so as to
479 ;; interact with the other keywords in the same way as $...$ does.
480 (list "\\$\\$\\([^$]+\\)\\$\\$" 1 'tex-math-face)
53c4fe47
SM
481 ;; Heading args.
482 (list (concat slash headings "\\*?" opt arg)
bdbd9606
SM
483 ;; If ARG ends up matching too much (if the {} don't match, f.ex)
484 ;; jit-lock will do funny things: when updating the buffer
485 ;; the re-highlighting is only done locally so it will just
486 ;; match the local line, but defer-contextually will
487 ;; match more lines at a time, so ARG will end up matching
488 ;; a lot more, which might suddenly include a comment
489 ;; so you get things highlighted bold when you type them
490 ;; but they get turned back to normal a little while later
491 ;; because "there's already a face there".
492 ;; Using `keep' works around this un-intuitive behavior as well
15ca8de7
SM
493 ;; as improves the behavior in the very rare case where you do
494 ;; have a comment in ARG.
bdbd9606 495 3 'font-lock-function-name-face 'keep)
7afecb99
SM
496 (list (concat slash "\\(?:provide\\|\\(?:re\\)?new\\)command\\** *\\(\\\\[A-Za-z@]+\\)")
497 1 'font-lock-function-name-face 'keep)
53c4fe47 498 ;; Variable args.
15ca8de7 499 (list (concat slash variables " *" arg) 2 'font-lock-variable-name-face)
53c4fe47
SM
500 ;; Include args.
501 (list (concat slash includes opt arg) 3 'font-lock-builtin-face)
502 ;; Definitions. I think.
15ca8de7 503 '("^[ \t]*\\\\def *\\\\\\(\\(\\w\\|@\\)+\\)"
bdbd9606 504 1 font-lock-function-name-face))))
53c4fe47
SM
505 "Subdued expressions to highlight in TeX modes.")
506
1f4cc034
SM
507(defun tex-font-lock-append-prop (prop)
508 (unless (memq (get-text-property (match-end 1) 'face)
509 '(font-lock-comment-face tex-verbatim-face))
510 prop))
511
53c4fe47
SM
512(defconst tex-font-lock-keywords-2
513 (append tex-font-lock-keywords-1
514 (eval-when-compile
515 (let* (;;
516 ;; Names of commands whose arg should be fontified with fonts.
1598a961 517 (bold (regexp-opt '("textbf" "textsc" "textup"
53c4fe47 518 "boldsymbol" "pmb") t))
1598a961 519 (italic (regexp-opt '("textit" "textsl" "emph") t))
a3d80d4a
SM
520 ;; FIXME: unimplemented yet.
521 ;; (type (regexp-opt '("texttt" "textmd" "textrm" "textsf") t))
53c4fe47
SM
522 ;;
523 ;; Names of commands whose arg should be fontified as a citation.
524 (citations (regexp-opt
525 '("label" "ref" "pageref" "vref" "eqref"
15ca8de7 526 "cite" "nocite" "index" "glossary" "bibitem"
1598a961
SM
527 ;; These are text, rather than citations.
528 ;; "caption" "footnote" "footnotemark" "footnotetext"
529 )
53c4fe47
SM
530 t))
531 ;;
532 ;; Names of commands that should be fontified.
1b741d9e
AS
533 (specials-1 (regexp-opt '("\\" "\\*") t)) ;; "-"
534 (specials-2 (regexp-opt
535 '("linebreak" "nolinebreak" "pagebreak" "nopagebreak"
536 "newline" "newpage" "clearpage" "cleardoublepage"
537 "displaybreak" "allowdisplaybreaks"
538 "enlargethispage") t))
53c4fe47
SM
539 (general "\\([a-zA-Z@]+\\**\\|[^ \t\n]\\)")
540 ;;
541 ;; Miscellany.
542 (slash "\\\\")
15ca8de7 543 (opt " *\\(\\[[^]]*\\] *\\)*")
7afecb99 544 (args "\\(\\(?:[^{}&\\]+\\|\\\\.\\|{[^}]*}\\)+\\)")
1598a961 545 (arg "{\\(\\(?:[^{}\\]+\\|\\\\.\\|{[^}]*}\\)+\\)"))
53c4fe47
SM
546 (list
547 ;;
548 ;; Citation args.
549 (list (concat slash citations opt arg) 3 'font-lock-constant-face)
550 ;;
15ca8de7 551 ;; Text between `` quotes ''.
95a045bd 552 (cons (concat (regexp-opt `("``" "\"<" "\"`" "<<" "«") t)
7abc9add 553 "[^'\">{]+" ;a bit pessimistic
95a045bd 554 (regexp-opt `("''" "\">" "\"'" ">>" "»") t))
15ca8de7
SM
555 'font-lock-string-face)
556 ;;
53c4fe47 557 ;; Command names, special and general.
1b741d9e
AS
558 (cons (concat slash specials-1) 'font-lock-warning-face)
559 (list (concat "\\(" slash specials-2 "\\)\\([^a-zA-Z@]\\|\\'\\)")
560 1 'font-lock-warning-face)
53c4fe47
SM
561 (concat slash general)
562 ;;
563 ;; Font environments. It seems a bit dubious to use `bold' etc. faces
564 ;; since we might not be able to display those fonts.
1f4cc034
SM
565 (list (concat slash bold " *" arg) 2
566 '(tex-font-lock-append-prop 'bold) 'append)
567 (list (concat slash italic " *" arg) 2
568 '(tex-font-lock-append-prop 'italic) 'append)
1598a961 569 ;; (list (concat slash type arg) 2 '(quote bold-italic) 'append)
53c4fe47
SM
570 ;;
571 ;; Old-style bf/em/it/sl. Stop at `\\' and un-escaped `&', for tables.
7afecb99 572 (list (concat "\\\\\\(em\\|it\\|sl\\)\\>" args)
1f4cc034 573 2 '(tex-font-lock-append-prop 'italic) 'append)
7afecb99
SM
574 ;; This is separate from the previous one because of cases like
575 ;; {\em foo {\bf bar} bla} where both match.
797bf075 576 (list (concat "\\\\\\(bf\\(series\\)?\\)\\>" args)
1f4cc034 577 2 '(tex-font-lock-append-prop 'bold) 'append)))))
53c4fe47
SM
578 "Gaudy expressions to highlight in TeX modes.")
579
7afecb99
SM
580(defun tex-font-lock-suscript (pos)
581 (unless (or (memq (get-text-property pos 'face)
582 '(font-lock-constant-face font-lock-builtin-face
583 font-lock-comment-face tex-verbatim-face))
584 ;; Check for backslash quoting
585 (let ((odd nil)
586 (pos pos))
587 (while (eq (char-before pos) ?\\)
588 (setq pos (1- pos) odd (not odd)))
589 odd))
590 (if (eq (char-after pos) ?_)
591 '(face subscript display (raise -0.3))
592 '(face superscript display (raise +0.3)))))
593
594(defconst tex-font-lock-keywords-3
595 (append tex-font-lock-keywords-2
596 (eval-when-compile
597 (let ((general "\\([a-zA-Z@]+\\|[^ \t\n]\\)")
598 (slash "\\\\")
599 ;; This is not the same regexp as before: it has a `+' removed.
600 ;; The + makes the matching faster in the above cases (where we can
601 ;; exit as soon as the match fails) but would make this matching
602 ;; degenerate to nasty complexity (because we try to match the
603 ;; closing brace, which forces trying all matching combinations).
604 (arg "{\\(?:[^{}\\]\\|\\\\.\\|{[^}]*}\\)*"))
6ecedb40 605 `((,(concat "[_^] *\\([^\n\\{}#]\\|" slash general "\\|#[0-9]\\|" arg "}\\)")
7afecb99
SM
606 (1 (tex-font-lock-suscript (match-beginning 0))
607 append))))))
608 "Experimental expressions to highlight in TeX modes.")
609
53c4fe47
SM
610(defvar tex-font-lock-keywords tex-font-lock-keywords-1
611 "Default expressions to highlight in TeX modes.")
0fb4f245 612
7afecb99
SM
613(defvar tex-verbatim-environments
614 '("verbatim" "verbatim*"))
615
616(defvar tex-font-lock-syntactic-keywords
617 (let ((verbs (regexp-opt tex-verbatim-environments t)))
618 `((,(concat "^\\\\begin *{" verbs "}.*\\(\n\\)") 2 "|")
1f4cc034
SM
619 ;; Technically, we'd like to put the "|" property on the \n preceding
620 ;; the \end, but this would have 2 disadvantages:
621 ;; 1 - it's wrong if the verbatim env is empty (the same \n is used to
622 ;; start and end the fenced-string).
623 ;; 2 - font-lock considers the preceding \n as being part of the
624 ;; preceding line, so things gets screwed every time the previous
625 ;; line is re-font-locked on its own.
b119fdd5
SM
626 ;; There's a hack in tex-font-lock-keywords-1 to remove the verbatim
627 ;; face from the \ but C-M-f still jumps to the wrong spot :-( --Stef
1f4cc034 628 (,(concat "^\\(\\\\\\)end *{" verbs "}\\(.?\\)") (1 "|") (3 "<"))
7afecb99
SM
629 ;; ("^\\(\\\\\\)begin *{comment}" 1 "< b")
630 ;; ("^\\\\end *{comment}.*\\(\n\\)" 1 "> b")
631 ("\\\\verb\\**\\([^a-z@*]\\)" 1 "\""))))
632
633(defun tex-font-lock-unfontify-region (beg end)
634 (font-lock-default-unfontify-region beg end)
635 (while (< beg end)
636 (let ((next (next-single-property-change beg 'display nil end))
637 (prop (get-text-property beg 'display)))
638 (if (and (eq (car-safe prop) 'raise)
639 (member (car-safe (cdr prop)) '(-0.3 +0.3))
640 (null (cddr prop)))
641 (put-text-property beg next 'display nil))
642 (setq beg next))))
643
644(defface superscript
645 '((t :height 0.8)) ;; :raise 0.3
18a8c773
LK
646 "Face used for superscripts."
647 :group 'tex)
7afecb99
SM
648(defface subscript
649 '((t :height 0.8)) ;; :raise -0.3
18a8c773
LK
650 "Face used for subscripts."
651 :group 'tex)
bdbd9606 652
ad49d9d6 653(defface tex-math
bdbd9606 654 '((t :inherit font-lock-string-face))
18a8c773
LK
655 "Face used to highlight TeX math expressions."
656 :group 'tex)
ad49d9d6
MB
657;; backward-compatibility alias
658(put 'tex-math-face 'face-alias 'tex-math)
659(defvar tex-math-face 'tex-math)
660
661(defface tex-verbatim
7afecb99
SM
662 ;; '((t :inherit font-lock-string-face))
663 '((t :family "courier"))
18a8c773
LK
664 "Face used to highlight TeX verbatim environments."
665 :group 'tex)
ad49d9d6
MB
666;; backward-compatibility alias
667(put 'tex-verbatim-face 'face-alias 'tex-verbatim)
668(defvar tex-verbatim-face 'tex-verbatim)
bdbd9606
SM
669
670;; Use string syntax but math face for $...$.
671(defun tex-font-lock-syntactic-face-function (state)
7afecb99
SM
672 (let ((char (nth 3 state)))
673 (cond
674 ((not char) font-lock-comment-face)
675 ((eq char ?$) tex-math-face)
676 (t
677 (when (char-valid-p char)
678 ;; This is a \verb?...? construct. Let's find the end and mark it.
679 (save-excursion
680 (skip-chars-forward (string ?^ char)) ;; Use `end' ?
681 (when (eq (char-syntax (preceding-char)) ?/)
682 (put-text-property (1- (point)) (point) 'syntax-table '(1)))
683 (unless (eobp)
684 (put-text-property (point) (1+ (point)) 'syntax-table '(7)))))
685 tex-verbatim-face))))
bdbd9606 686
53c4fe47 687\f
869bff31 688(defun tex-define-common-keys (keymap)
81c735c0 689 "Define the keys that we want defined both in TeX mode and in the TeX shell."
869bff31 690 (define-key keymap "\C-c\C-k" 'tex-kill-job)
691 (define-key keymap "\C-c\C-l" 'tex-recenter-output-buffer)
692 (define-key keymap "\C-c\C-q" 'tex-show-print-queue)
693 (define-key keymap "\C-c\C-p" 'tex-print)
694 (define-key keymap "\C-c\C-v" 'tex-view)
62a24cb5
RS
695
696 (define-key keymap [menu-bar tex] (cons "TeX" (make-sparse-keymap "TeX")))
697
bdbd9606
SM
698 (define-key keymap [menu-bar tex tex-kill-job]
699 '(menu-item "Tex Kill" tex-kill-job :enable (tex-shell-running)))
cf6d6e8a 700 (define-key keymap [menu-bar tex tex-recenter-output-buffer]
bdbd9606
SM
701 '(menu-item "Tex Recenter" tex-recenter-output-buffer
702 :enable (get-buffer "*tex-shell*")))
62a24cb5
RS
703 (define-key keymap [menu-bar tex tex-show-print-queue]
704 '("Show Print Queue" . tex-show-print-queue))
cf6d6e8a 705 (define-key keymap [menu-bar tex tex-alt-print]
bdbd9606
SM
706 '(menu-item "Tex Print (alt printer)" tex-alt-print
707 :enable (stringp tex-print-file)))
708 (define-key keymap [menu-bar tex tex-print]
709 '(menu-item "Tex Print" tex-print :enable (stringp tex-print-file)))
710 (define-key keymap [menu-bar tex tex-view]
711 '(menu-item "Tex View" tex-view :enable (stringp tex-print-file))))
712
713(defvar tex-mode-map
714 (let ((map (make-sparse-keymap)))
15ca8de7 715 (set-keymap-parent map text-mode-map)
bdbd9606
SM
716 (tex-define-common-keys map)
717 (define-key map "\"" 'tex-insert-quote)
718 (define-key map "(" 'skeleton-pair-insert-maybe)
719 (define-key map "{" 'skeleton-pair-insert-maybe)
720 (define-key map "[" 'skeleton-pair-insert-maybe)
721 (define-key map "$" 'skeleton-pair-insert-maybe)
722 (define-key map "\n" 'tex-terminate-paragraph)
723 (define-key map "\M-\r" 'latex-insert-item)
724 (define-key map "\C-c}" 'up-list)
725 (define-key map "\C-c{" 'tex-insert-braces)
726 (define-key map "\C-c\C-r" 'tex-region)
727 (define-key map "\C-c\C-b" 'tex-buffer)
728 (define-key map "\C-c\C-f" 'tex-file)
75035a80 729 (define-key map "\C-c\C-c" 'tex-compile)
bdbd9606 730 (define-key map "\C-c\C-i" 'tex-bibtex-file)
7afecb99
SM
731 (define-key map "\C-c\C-o" 'latex-insert-block)
732 (define-key map "\C-c\C-e" 'latex-close-block)
bdbd9606
SM
733 (define-key map "\C-c\C-u" 'tex-goto-last-unclosed-latex-block)
734 (define-key map "\C-c\C-m" 'tex-feed-input)
735 (define-key map [(control return)] 'tex-feed-input)
736 (define-key map [menu-bar tex tex-bibtex-file]
737 '("BibTeX File" . tex-bibtex-file))
738 (define-key map [menu-bar tex tex-validate-region]
739 '(menu-item "Validate Region" tex-validate-region :enable mark-active))
740 (define-key map [menu-bar tex tex-validate-buffer]
741 '("Validate Buffer" . tex-validate-buffer))
742 (define-key map [menu-bar tex tex-region]
743 '(menu-item "TeX Region" tex-region :enable mark-active))
744 (define-key map [menu-bar tex tex-buffer]
745 '("TeX Buffer" . tex-buffer))
746 (define-key map [menu-bar tex tex-file] '("TeX File" . tex-file))
747 map)
15ca8de7
SM
748 "Keymap shared by TeX modes.")
749
750(defvar latex-mode-map
751 (let ((map (make-sparse-keymap)))
752 (set-keymap-parent map tex-mode-map)
a3d80d4a 753 (define-key map "\C-c\C-s" 'latex-split-block)
15ca8de7
SM
754 map)
755 "Keymap for `latex-mode'. See also `tex-mode-map'.")
756
757(defvar plain-tex-mode-map
758 (let ((map (make-sparse-keymap)))
759 (set-keymap-parent map tex-mode-map)
760 map)
761 "Keymap for `plain-tex-mode'. See also `tex-mode-map'.")
cf6d6e8a 762
d6709b80
SM
763(defvar tex-shell-map
764 (let ((m (make-sparse-keymap)))
765 (set-keymap-parent m shell-mode-map)
766 (tex-define-common-keys m)
767 m)
81c735c0 768 "Keymap for the TeX shell.
dca5ea48 769Inherits `shell-mode-map' with a few additions.")
869bff31 770
6da9bbd6
RS
771(defvar tex-face-alist
772 '((bold . "{\\bf ")
773 (italic . "{\\it ")
774 (bold-italic . "{\\bi ") ; hypothetical
775 (underline . "\\underline{")
776 (default . "{\\rm "))
777 "Alist of face and TeX font name for facemenu.")
778
779(defvar tex-latex-face-alist
780 `((italic . "{\\em ")
781 ,@tex-face-alist)
782 "Alist of face and LaTeX font name for facemenu.")
783
15ca8de7
SM
784;; This would be a lot simpler if we just used a regexp search,
785;; but then it would be too slow.
a3d80d4a 786(defun tex-guess-mode ()
d6709b80 787 (let ((mode tex-default-mode) slash comment)
869bff31 788 (save-excursion
789 (goto-char (point-min))
790 (while (and (setq slash (search-forward "\\" nil t))
791 (setq comment (let ((search-end (point)))
792 (save-excursion
793 (beginning-of-line)
794 (search-forward "%" search-end t))))))
bdbd9606
SM
795 (when (and slash (not comment))
796 (setq mode
797 (if (looking-at
798 (eval-when-compile
799 (concat
800 (regexp-opt '("documentstyle" "documentclass"
95a045bd 801 "begin" "subsection" "section"
bca7a08b 802 "part" "chapter" "newcommand"
29a47b89 803 "renewcommand" "RequirePackage") 'words)
bdbd9606 804 "\\|NeedsTeXFormat{LaTeX")))
dd166d5f
SM
805 (if (and (looking-at
806 "document\\(style\\|class\\)\\(\\[.*\\]\\)?{slides}")
807 ;; SliTeX is almost never used any more nowadays.
808 (tex-executable-exists-p slitex-run-command))
bdbd9606
SM
809 'slitex-mode
810 'latex-mode)
811 'plain-tex-mode))))
d6709b80 812 (funcall mode)))
e4c8c838 813
a3d80d4a
SM
814;; `tex-mode' plays two roles: it's the parent of several sub-modes
815;; but it's also the function that chooses between those submodes.
816;; To tell the difference between those two cases where the function
817;; might be called, we check `delay-mode-hooks'.
a3d80d4a
SM
818(define-derived-mode tex-mode text-mode "generic-TeX"
819 (tex-common-initialization))
bca7a08b
SM
820;; We now move the function and define it again. This gives a warning
821;; in the byte-compiler :-( but it's difficult to avoid because
822;; `define-derived-mode' will necessarily define the function once
823;; and we need to define it a second time for `autoload' to get the
824;; proper docstring.
825(defalias 'tex-mode-internal (symbol-function 'tex-mode))
826;;;###autoload
827(defun tex-mode ()
828 "Major mode for editing files of input for TeX, LaTeX, or SliTeX.
a3d80d4a
SM
829Tries to determine (by looking at the beginning of the file) whether
830this file is for plain TeX, LaTeX, or SliTeX and calls `plain-tex-mode',
831`latex-mode', or `slitex-mode', respectively. If it cannot be determined,
832such as if there are no commands in the file, the value of `tex-default-mode'
833says which mode to use."
bca7a08b
SM
834 (interactive)
835 (if delay-mode-hooks
836 ;; We're called from one of the children already.
837 (tex-mode-internal)
838 (tex-guess-mode)))
a3d80d4a 839
1639cc2e
DK
840;; The following three autoloaded aliases appear to conflict with
841;; AUCTeX. However, even though AUCTeX uses the mixed case variants
842;; for all mode relevant variables and hooks, the invocation function
843;; and setting of `major-mode' themselves need to be lowercase for
844;; AUCTeX to provide a fully functional user-level replacement. So
845;; these aliases should remain as they are, in particular since AUCTeX
846;; users are likely to use them.
847
6503cec3 848;;;###autoload
31e1d920 849(defalias 'TeX-mode 'tex-mode)
6503cec3 850;;;###autoload
c3ce7bf4
RS
851(defalias 'plain-TeX-mode 'plain-tex-mode)
852;;;###autoload
31e1d920 853(defalias 'LaTeX-mode 'latex-mode)
869bff31 854
7229064d 855;;;###autoload
a3d80d4a 856(define-derived-mode plain-tex-mode tex-mode "TeX"
869bff31 857 "Major mode for editing files of input for plain TeX.
858Makes $ and } display the characters they match.
859Makes \" insert `` when it seems to be the beginning of a quotation,
860and '' when it appears to be the end; it inserts \" only after a \\.
861
862Use \\[tex-region] to run TeX on the current region, plus a \"header\"
863copied from the top of the file (containing macro definitions, etc.),
864running TeX under a special subshell. \\[tex-buffer] does the whole buffer.
865\\[tex-file] saves the buffer and then processes the file.
866\\[tex-print] prints the .dvi file made by any of these.
867\\[tex-view] previews the .dvi file made by any of these.
868\\[tex-bibtex-file] runs bibtex on the file of the current buffer.
869
e6b0b773 870Use \\[tex-validate-buffer] to check buffer for paragraphs containing
869bff31 871mismatched $'s or braces.
872
873Special commands:
15ca8de7 874\\{plain-tex-mode-map}
869bff31 875
876Mode variables:
877tex-run-command
878 Command string used by \\[tex-region] or \\[tex-buffer].
879tex-directory
880 Directory in which to create temporary files for TeX jobs
881 run by \\[tex-region] or \\[tex-buffer].
882tex-dvi-print-command
883 Command string used by \\[tex-print] to print a .dvi file.
528415e7
RS
884tex-alt-dvi-print-command
885 Alternative command string used by \\[tex-print] (when given a prefix
886 argument) to print a .dvi file.
869bff31 887tex-dvi-view-command
888 Command string used by \\[tex-view] to preview a .dvi file.
889tex-show-queue-command
890 Command string used by \\[tex-show-print-queue] to show the print
891 queue that \\[tex-print] put your job on.
892
81c735c0
RS
893Entering Plain-tex mode runs the hook `text-mode-hook', then the hook
894`tex-mode-hook', and finally the hook `plain-tex-mode-hook'. When the
895special subshell is initiated, the hook `tex-shell-hook' is run."
a3d80d4a
SM
896 (set (make-local-variable 'tex-command) tex-run-command)
897 (set (make-local-variable 'tex-start-of-header) "%\\*\\*start of header")
898 (set (make-local-variable 'tex-end-of-header) "%\\*\\*end of header")
899 (set (make-local-variable 'tex-trailer) "\\bye\n"))
869bff31 900
7229064d 901;;;###autoload
a3d80d4a 902(define-derived-mode latex-mode tex-mode "LaTeX"
869bff31 903 "Major mode for editing files of input for LaTeX.
904Makes $ and } display the characters they match.
905Makes \" insert `` when it seems to be the beginning of a quotation,
906and '' when it appears to be the end; it inserts \" only after a \\.
907
908Use \\[tex-region] to run LaTeX on the current region, plus the preamble
909copied from the top of the file (containing \\documentstyle, etc.),
910running LaTeX under a special subshell. \\[tex-buffer] does the whole buffer.
911\\[tex-file] saves the buffer and then processes the file.
912\\[tex-print] prints the .dvi file made by any of these.
913\\[tex-view] previews the .dvi file made by any of these.
914\\[tex-bibtex-file] runs bibtex on the file of the current buffer.
915
e6b0b773 916Use \\[tex-validate-buffer] to check buffer for paragraphs containing
869bff31 917mismatched $'s or braces.
918
919Special commands:
15ca8de7 920\\{latex-mode-map}
869bff31 921
922Mode variables:
923latex-run-command
924 Command string used by \\[tex-region] or \\[tex-buffer].
925tex-directory
926 Directory in which to create temporary files for LaTeX jobs
927 run by \\[tex-region] or \\[tex-buffer].
928tex-dvi-print-command
929 Command string used by \\[tex-print] to print a .dvi file.
528415e7
RS
930tex-alt-dvi-print-command
931 Alternative command string used by \\[tex-print] (when given a prefix
932 argument) to print a .dvi file.
869bff31 933tex-dvi-view-command
934 Command string used by \\[tex-view] to preview a .dvi file.
935tex-show-queue-command
936 Command string used by \\[tex-show-print-queue] to show the print
937 queue that \\[tex-print] put your job on.
938
bed1b0c8 939Entering Latex mode runs the hook `text-mode-hook', then
81c735c0
RS
940`tex-mode-hook', and finally `latex-mode-hook'. When the special
941subshell is initiated, `tex-shell-hook' is run."
a3d80d4a
SM
942 (set (make-local-variable 'tex-command) latex-run-command)
943 (set (make-local-variable 'tex-start-of-header)
944 "\\\\document\\(style\\|class\\)")
945 (set (make-local-variable 'tex-end-of-header) "\\\\begin\\s-*{document}")
d9cbee57 946 (set (make-local-variable 'tex-trailer) "\\end{document}\n")
ab2c9f54
RS
947 ;; A line containing just $$ is treated as a paragraph separator.
948 ;; A line starting with $$ starts a paragraph,
949 ;; but does not separate paragraphs if it has more stuff on it.
d6709b80 950 (setq paragraph-start
a3d80d4a 951 (concat "[ \t]*\\(\\$\\$\\|"
d6709b80
SM
952 "\\\\[][]\\|"
953 "\\\\" (regexp-opt (append
954 (mapcar 'car latex-section-alist)
955 '("begin" "label" "end"
956 "item" "bibitem" "newline" "noindent"
957 "newpage" "footnote" "marginpar"
958 "parbox" "caption")) t)
959 "\\>\\|\\\\[a-z]*" (regexp-opt '("space" "skip" "page") t)
dd459839 960 "\\>\\)"))
d6709b80 961 (setq paragraph-separate
dd459839 962 (concat "[\f%]\\|[ \t]*\\($\\|"
d6709b80
SM
963 "\\\\[][]\\|"
964 "\\\\" (regexp-opt (append
965 (mapcar 'car latex-section-alist)
966 '("begin" "label" "end" )) t)
967 "\\>\\|\\\\\\(" (regexp-opt '("item" "bibitem" "newline"
968 "noindent" "newpage" "footnote"
969 "marginpar" "parbox" "caption"))
dd459839
SM
970 "\\|\\$\\$\\|[a-z]*\\(space\\|skip\\|page[a-z]*\\)"
971 "\\>\\)[ \t]*\\($\\|%\\)\\)"))
d6709b80
SM
972 (set (make-local-variable 'imenu-create-index-function)
973 'latex-imenu-create-index)
974 (set (make-local-variable 'tex-face-alist) tex-latex-face-alist)
95a045bd 975 (add-hook 'fill-nobreak-predicate 'latex-fill-nobreak-predicate nil t)
ea590e1c 976 (set (make-local-variable 'indent-line-function) 'latex-indent)
dd459839 977 (set (make-local-variable 'fill-indent-according-to-mode) t)
d6709b80
SM
978 (set (make-local-variable 'outline-regexp) latex-outline-regexp)
979 (set (make-local-variable 'outline-level) 'latex-outline-level)
53c4fe47 980 (set (make-local-variable 'forward-sexp-function) 'latex-forward-sexp)
a3d80d4a 981 (set (make-local-variable 'skeleton-end-hook) nil))
869bff31 982
bd2f2323 983;;;###autoload
d6709b80 984(define-derived-mode slitex-mode latex-mode "SliTeX"
869bff31 985 "Major mode for editing files of input for SliTeX.
986Makes $ and } display the characters they match.
987Makes \" insert `` when it seems to be the beginning of a quotation,
988and '' when it appears to be the end; it inserts \" only after a \\.
989
990Use \\[tex-region] to run SliTeX on the current region, plus the preamble
991copied from the top of the file (containing \\documentstyle, etc.),
992running SliTeX under a special subshell. \\[tex-buffer] does the whole buffer.
993\\[tex-file] saves the buffer and then processes the file.
994\\[tex-print] prints the .dvi file made by any of these.
995\\[tex-view] previews the .dvi file made by any of these.
996\\[tex-bibtex-file] runs bibtex on the file of the current buffer.
997
e6b0b773 998Use \\[tex-validate-buffer] to check buffer for paragraphs containing
869bff31 999mismatched $'s or braces.
1000
1001Special commands:
15ca8de7 1002\\{slitex-mode-map}
869bff31 1003
1004Mode variables:
1005slitex-run-command
1006 Command string used by \\[tex-region] or \\[tex-buffer].
1007tex-directory
1008 Directory in which to create temporary files for SliTeX jobs
1009 run by \\[tex-region] or \\[tex-buffer].
1010tex-dvi-print-command
1011 Command string used by \\[tex-print] to print a .dvi file.
528415e7
RS
1012tex-alt-dvi-print-command
1013 Alternative command string used by \\[tex-print] (when given a prefix
1014 argument) to print a .dvi file.
869bff31 1015tex-dvi-view-command
1016 Command string used by \\[tex-view] to preview a .dvi file.
1017tex-show-queue-command
1018 Command string used by \\[tex-show-print-queue] to show the print
1019 queue that \\[tex-print] put your job on.
1020
81c735c0
RS
1021Entering SliTeX mode runs the hook `text-mode-hook', then the hook
1022`tex-mode-hook', then the hook `latex-mode-hook', and finally the hook
1023`slitex-mode-hook'. When the special subshell is initiated, the hook
1024`tex-shell-hook' is run."
869bff31 1025 (setq tex-command slitex-run-command)
d6709b80 1026 (setq tex-start-of-header "\\\\documentstyle{slides}\\|\\\\documentclass{slides}"))
869bff31 1027
1028(defun tex-common-initialization ()
822eddf4 1029 ;; Regexp isearch should accept newline and formfeed as whitespace.
d6709b80 1030 (set (make-local-variable 'search-whitespace-regexp) "[ \t\r\n\f]+")
64db2461 1031 ;; A line containing just $$ is treated as a paragraph separator.
d6709b80
SM
1032 (set (make-local-variable 'paragraph-start)
1033 "[ \t]*$\\|[\f\\\\%]\\|[ \t]*\\$\\$")
ab2c9f54
RS
1034 ;; A line starting with $$ starts a paragraph,
1035 ;; but does not separate paragraphs if it has more stuff on it.
d6709b80
SM
1036 (set (make-local-variable 'paragraph-separate)
1037 "[ \t]*$\\|[\f\\\\%]\\|[ \t]*\\$\\$[ \t]*$")
1038 (set (make-local-variable 'comment-start) "%")
1039 (set (make-local-variable 'comment-add) 1)
1040 (set (make-local-variable 'comment-start-skip)
5ae0d697 1041 "\\(\\(^\\|[^\\\n]\\)\\(\\\\\\\\\\)*\\)\\(%+ *\\)")
d6709b80
SM
1042 (set (make-local-variable 'parse-sexp-ignore-comments) t)
1043 (set (make-local-variable 'compare-windows-whitespace)
1044 'tex-categorize-whitespace)
1045 (set (make-local-variable 'facemenu-add-face-function)
1046 (lambda (face end)
6ecedb40
SM
1047 (or (cdr (assq face tex-face-alist))
1048 (error "Face %s not configured for %s mode" face mode-name))))
d6709b80
SM
1049 (set (make-local-variable 'facemenu-end-add-face) "}")
1050 (set (make-local-variable 'facemenu-remove-face-function) t)
1051 (set (make-local-variable 'font-lock-defaults)
7afecb99
SM
1052 '((tex-font-lock-keywords tex-font-lock-keywords-1
1053 tex-font-lock-keywords-2 tex-font-lock-keywords-3)
d6709b80
SM
1054 nil nil ((?$ . "\"")) nil
1055 ;; Who ever uses that anyway ???
bdbd9606
SM
1056 (font-lock-mark-block-function . mark-paragraph)
1057 (font-lock-syntactic-face-function
7afecb99
SM
1058 . tex-font-lock-syntactic-face-function)
1059 (font-lock-unfontify-region-function
1060 . tex-font-lock-unfontify-region)
1061 (font-lock-syntactic-keywords
1062 . tex-font-lock-syntactic-keywords)
1063 (parse-sexp-lookup-properties . t)))
95a045bd
SM
1064 ;; TABs in verbatim environments don't do what you think.
1065 (set (make-local-variable 'indent-tabs-mode) nil)
7afecb99 1066 ;; Other vars that should be buffer-local.
869bff31 1067 (make-local-variable 'tex-command)
1068 (make-local-variable 'tex-start-of-header)
1069 (make-local-variable 'tex-end-of-header)
1070 (make-local-variable 'tex-trailer))
1071
869bff31 1072(defun tex-categorize-whitespace (backward-limit)
1073 ;; compare-windows-whitespace is set to this.
1074 ;; This is basically a finite-state machine.
1075 ;; Returns a symbol telling how TeX would treat
1076 ;; the whitespace we are looking at: null, space, or par.
1077 (let ((category 'null)
1078 (not-finished t))
1079 (skip-chars-backward " \t\n\f" backward-limit)
1080 (while not-finished
1081 (cond ((looking-at "[ \t]+")
1082 (goto-char (match-end 0))
2be5fefb 1083 (if (eq category 'null)
869bff31 1084 (setq category 'space)))
1085 ((looking-at "\n")
2be5fefb 1086 (cond ((eq category 'newline)
869bff31 1087 (setq category 'par)
1088 (setq not-finished nil))
1089 (t
1090 (setq category 'newline) ;a strictly internal state
1091 (goto-char (match-end 0)))))
1092 ((looking-at "\f+")
1093 (setq category 'par)
1094 (setq not-finished nil))
1095 (t
1096 (setq not-finished nil))))
1097 (skip-chars-forward " \t\n\f")
2be5fefb 1098 (if (eq category 'newline)
869bff31 1099 'space ;TeX doesn't distinguish
1100 category)))
1101
1102(defun tex-insert-quote (arg)
1103 "Insert the appropriate quote marks for TeX.
08348502
RS
1104Inserts the value of `tex-open-quote' (normally ``) or `tex-close-quote'
1105\(normally '') depending on the context. With prefix argument, always
869bff31 1106inserts \" characters."
528415e7 1107 (interactive "*P")
95a045bd 1108 (if (or arg (memq (char-syntax (preceding-char)) '(?/ ?\\))
ad49d9d6 1109 (eq (get-text-property (point) 'face) tex-verbatim-face)
95a045bd
SM
1110 (save-excursion
1111 (backward-char (length tex-open-quote))
1112 (when (or (looking-at (regexp-quote tex-open-quote))
1113 (looking-at (regexp-quote tex-close-quote)))
1114 (delete-char (length tex-open-quote))
1115 t)))
869bff31 1116 (self-insert-command (prefix-numeric-value arg))
d1218e3e 1117 (insert (if (memq (char-syntax (preceding-char)) '(?\( ?> ?\s))
95a045bd 1118 tex-open-quote tex-close-quote))))
869bff31 1119
e6b0b773
MR
1120(defun tex-validate-buffer ()
1121 "Check current buffer for paragraphs containing mismatched braces or $s.
bbd93e41 1122Their positions are recorded in the buffer `*Occur*'.
e6b0b773
MR
1123To find a particular invalidity from `*Occur*', switch to that buffer
1124and type C-c C-c or click with mouse-2
1125on the line for the invalidity you want to see."
869bff31 1126 (interactive)
bbd93e41
RS
1127 (let ((buffer (current-buffer))
1128 (prevpos (point-min))
e6b0b773
MR
1129 (linenum nil)
1130 (num-matches 0))
bbd93e41
RS
1131 (with-output-to-temp-buffer "*Occur*"
1132 (princ "Mismatches:\n")
a3d80d4a 1133 (with-current-buffer standard-output
bbd93e41 1134 (occur-mode)
52ab062c
CW
1135 ;; This won't actually work...Really, this whole thing should
1136 ;; be rewritten instead of being a hack on top of occur.
1137 (setq occur-revert-arguments (list nil 0 (list buffer))))
bbd93e41
RS
1138 (save-excursion
1139 (goto-char (point-max))
52ab062c 1140 (while (and (not (bobp)))
710a0f53
KH
1141 (let ((end (point))
1142 prev-end)
bbd93e41 1143 ;; Scan the previous paragraph for invalidities.
710a0f53
KH
1144 (if (search-backward "\n\n" nil t)
1145 (progn
1146 (setq prev-end (point))
1147 (forward-char 2))
1148 (goto-char (setq prev-end (point-min))))
869bff31 1149 (or (tex-validate-region (point) end)
a3d80d4a 1150 (let* ((end (line-beginning-position 2))
bbd93e41
RS
1151 start tem)
1152 (beginning-of-line)
1153 (setq start (point))
1154 ;; Keep track of line number as we scan,
1155 ;; in a cumulative fashion.
1156 (if linenum
1157 (setq linenum (- linenum (count-lines prevpos (point))))
1158 (setq linenum (1+ (count-lines 1 start))))
1159 (setq prevpos (point))
bed1b0c8 1160 ;; Mention this mismatch in *Occur*.
bbd93e41 1161 ;; Since we scan from end of buffer to beginning,
e6b0b773 1162 ;; add each mismatch at the beginning of *Occur*.
bbd93e41
RS
1163 (save-excursion
1164 (setq tem (point-marker))
1165 (set-buffer standard-output)
1166 (goto-char (point-min))
1167 ;; Skip "Mismatches:" header line.
1168 (forward-line 1)
e6b0b773 1169 (setq num-matches (1+ num-matches))
bbd93e41 1170 (insert-buffer-substring buffer start end)
e6b0b773
MR
1171 (let (text-beg (text-end (point-marker)))
1172 (forward-char (- start end))
1173 (setq text-beg (point-marker))
1174 (insert (format "%3d: " linenum))
a865de85
EZ
1175 (add-text-properties
1176 text-beg (- text-end 1)
1177 '(mouse-face highlight
1178 help-echo "mouse-2: go to this invalidity"))
1598a961 1179 (put-text-property text-beg (- text-end 1)
52ab062c 1180 'occur-target tem)))))
710a0f53 1181 (goto-char prev-end))))
bdbd9606 1182 (with-current-buffer standard-output
003274a0
JPW
1183 (let ((no-matches (zerop num-matches)))
1184 (if no-matches
1185 (insert "None!\n"))
1186 (if (interactive-p)
f04232c3
JPW
1187 (message (cond (no-matches "No mismatches found")
1188 ((= num-matches 1) "1 mismatch found")
1189 (t "%d mismatches found"))
1190 num-matches)))))))
869bff31 1191
1192(defun tex-validate-region (start end)
1193 "Check for mismatched braces or $'s in region.
1194Returns t if no mismatches. Returns nil and moves point to suspect
1195area if a mismatch is found."
1196 (interactive "r")
1197 (let ((failure-point nil) (max-possible-sexps (- end start)))
1198 (save-excursion
1199 (condition-case ()
1200 (save-restriction
1201 (narrow-to-region start end)
2ed2806c 1202 ;; First check that the open and close parens balance in numbers.
869bff31 1203 (goto-char start)
e6b0b773 1204 (while (<= 0 (setq max-possible-sexps (1- max-possible-sexps)))
2ed2806c
KH
1205 (forward-sexp 1))
1206 ;; Now check that like matches like.
1207 (goto-char start)
35dccc62
SM
1208 (while (re-search-forward "\\s(" nil t)
1209 (save-excursion
1210 (let ((pos (match-beginning 0)))
1211 (goto-char pos)
2ed2806c 1212 (forward-sexp 1)
35dccc62
SM
1213 (or (eq (preceding-char) (cdr (syntax-after pos)))
1214 (eq (char-after pos) (cdr (syntax-after (1- (point)))))
1215 (error "Mismatched parentheses"))))))
869bff31 1216 (error
bed1b0c8
RS
1217 (skip-syntax-forward " .>")
1218 (setq failure-point (point)))))
bdbd9606
SM
1219 (if failure-point (goto-char failure-point))
1220 (not failure-point)))
869bff31 1221
1222(defun tex-terminate-paragraph (inhibit-validation)
1223 "Insert two newlines, breaking a paragraph for TeX.
81c735c0 1224Check for mismatched braces or $s in paragraph being terminated.
869bff31 1225A prefix arg inhibits the checking."
528415e7 1226 (interactive "*P")
869bff31 1227 (or inhibit-validation
1228 (save-excursion
1229 (tex-validate-region
bed1b0c8
RS
1230 (save-excursion
1231 (search-backward "\n\n" nil 'move)
1232 (point))
1233 (point)))
869bff31 1234 (message "Paragraph being closed appears to contain a mismatch"))
1235 (insert "\n\n"))
1236
7afecb99 1237(define-skeleton tex-insert-braces
869bff31 1238 "Make a pair of braces and be poised to type inside of them."
7afecb99
SM
1239 nil
1240 ?\{ _ ?})
869bff31 1241
9bd4f69c
RS
1242;; This function is used as the value of fill-nobreak-predicate
1243;; in LaTeX mode. Its job is to prevent line-breaking inside
1244;; of a \verb construct.
1245(defun latex-fill-nobreak-predicate ()
7afecb99
SM
1246 (save-excursion
1247 (skip-chars-backward " ")
1248 ;; Don't break after \ since `\ ' has special meaning.
1249 (or (and (not (bobp)) (memq (char-syntax (char-before)) '(?\\ ?/)))
1250 (let ((opoint (point))
1251 inside)
1252 (beginning-of-line)
1253 (while (re-search-forward "\\\\verb\\(.\\)" opoint t)
1254 (unless (re-search-forward (regexp-quote (match-string 1)) opoint t)
1255 (setq inside t)))
1256 inside))))
9bd4f69c 1257
53c4fe47
SM
1258(defvar latex-block-default "enumerate")
1259
8084f5d8 1260(defvar latex-block-args-alist
dd166d5f
SM
1261 '(("array" nil ?\{ (skeleton-read "Format: ") ?\})
1262 ("tabular" nil ?\{ (skeleton-read "Format: ") ?\})
1263 ("minipage" nil ?\{ (skeleton-read "Size: ") ?\})
1264 ("picture" nil ?\( (skeleton-read "SizeX,SizeY: ") ?\))
1265 ;; FIXME: This is right for Prosper, but not for seminar.
1266 ;; ("slide" nil ?\{ (skeleton-read "Title: ") ?\})
1267 )
8084f5d8
SM
1268 "Skeleton element to use for arguments to particular environments.
1269Every element of the list has the form (NAME . SKEL-ELEM) where NAME is
1270the name of the environment and SKEL-ELEM is an element to use in
1271a skeleton (see `skeleton-insert').")
1272
1273(defvar latex-block-body-alist
1274 '(("enumerate" nil '(latex-insert-item) > _)
1275 ("itemize" nil '(latex-insert-item) > _)
dd166d5f
SM
1276 ("table" nil "\\caption{" > (skeleton-read "Caption: ") "}" > \n
1277 '(if (and (boundp 'reftex-mode) reftex-mode) (reftex-label "table"))
1278 \n _)
1279 ("figure" nil > _ \n "\\caption{" > (skeleton-read "Caption: ") "}" > \n
1280 '(if (and (boundp 'reftex-mode) reftex-mode) (reftex-label "table"))))
8084f5d8
SM
1281 "Skeleton element to use for the body of particular environments.
1282Every element of the list has the form (NAME . SKEL-ELEM) where NAME is
1283the name of the environment and SKEL-ELEM is an element to use in
1284a skeleton (see `skeleton-insert').")
1285
15ca8de7 1286;; Like tex-insert-braces, but for LaTeX.
7afecb99
SM
1287(defalias 'tex-latex-block 'latex-insert-block)
1288(define-skeleton latex-insert-block
8a591d52 1289 "Create a matching pair of lines \\begin{NAME} and \\end{NAME} at point.
869bff31 1290Puts point on a blank line between them."
53c4fe47
SM
1291 (let ((choice (completing-read (format "LaTeX block name [%s]: "
1292 latex-block-default)
95a045bd 1293 (append latex-block-names
7afecb99 1294 latex-standard-block-names)
53c4fe47
SM
1295 nil nil nil nil latex-block-default)))
1296 (setq latex-block-default choice)
7afecb99 1297 (unless (or (member choice latex-standard-block-names)
53c4fe47
SM
1298 (member choice latex-block-names))
1299 ;; Remember new block names for later completion.
1300 (push choice latex-block-names))
1301 choice)
95a045bd 1302 \n "\\begin{" str "}"
8084f5d8 1303 (cdr (assoc str latex-block-args-alist))
dd166d5f
SM
1304 > \n (or (cdr (assoc str latex-block-body-alist)) '(nil > _))
1305 (unless (bolp) '\n)
95a045bd 1306 "\\end{" str "}" > \n)
53c4fe47 1307
ea590e1c
SM
1308(define-skeleton latex-insert-item
1309 "Insert a \item macro."
1310 nil
15ca8de7 1311 \n "\\item " >)
ea590e1c 1312
53c4fe47
SM
1313\f
1314;;;;
1315;;;; LaTeX syntax navigation
1316;;;;
869bff31 1317
5e56fb53
SM
1318(defmacro tex-search-noncomment (&rest body)
1319 "Execute BODY as long as it return non-nil and point is in a comment.
1320Return the value returned by the last execution of BODY."
1321 (declare (debug t))
1322 (let ((res-sym (make-symbol "result")))
1323 `(let (,res-sym)
1324 (while
1325 (and (setq ,res-sym (progn ,@body))
1326 (save-excursion (skip-chars-backward "^\n%") (not (bolp)))))
1327 ,res-sym)))
1328
869bff31 1329(defun tex-last-unended-begin ()
81c735c0 1330 "Leave point at the beginning of the last `\\begin{...}' that is unended."
95a045bd 1331 (condition-case nil
5e56fb53
SM
1332 (while (and (tex-search-noncomment
1333 (re-search-backward "\\\\\\(begin\\|end\\)\\s *{"))
95a045bd
SM
1334 (looking-at "\\\\end"))
1335 (tex-last-unended-begin))
1336 (search-failed (error "Couldn't find unended \\begin"))))
869bff31 1337
53c4fe47
SM
1338(defun tex-next-unmatched-end ()
1339 "Leave point at the end of the next `\\end' that is unended."
5e56fb53
SM
1340 (while (and (tex-search-noncomment
1341 (re-search-forward "\\\\\\(begin\\|end\\)\\s *{[^}]+}"))
ea590e1c
SM
1342 (save-excursion (goto-char (match-beginning 0))
1343 (looking-at "\\\\begin")))
53c4fe47
SM
1344 (tex-next-unmatched-end)))
1345
6a900cf1
ER
1346(defun tex-goto-last-unclosed-latex-block ()
1347 "Move point to the last unclosed \\begin{...}.
1348Mark is left at original location."
1349 (interactive)
1350 (let ((spot))
1351 (save-excursion
95a045bd 1352 (tex-last-unended-begin)
6a900cf1
ER
1353 (setq spot (point)))
1354 (push-mark)
1355 (goto-char spot)))
1356
53c4fe47
SM
1357(defun latex-backward-sexp-1 ()
1358 "Like (backward-sexp 1) but aware of multi-char elements."
1359 (let ((pos (point))
1360 (forward-sexp-function))
1361 (backward-sexp 1)
1362 (if (looking-at "\\\\begin\\>")
1363 (signal 'scan-error
1364 (list "Containing expression ends prematurely"
1365 (point) (prog1 (point) (goto-char pos))))
1366 (when (eq (char-after) ?{)
1367 (let ((newpos (point)))
1368 (when (ignore-errors (backward-sexp 1) t)
e67064e2
SM
1369 (if (or (looking-at "\\\\end\\>")
1370 ;; In case the \\ ends a verbatim section.
1371 (and (looking-at "end\\>") (eq (char-before) ?\\)))
53c4fe47
SM
1372 (tex-last-unended-begin)
1373 (goto-char newpos))))))))
1374
1375(defun latex-forward-sexp-1 ()
1376 "Like (forward-sexp 1) but aware of multi-char elements."
1377 (let ((pos (point))
1378 (forward-sexp-function))
1379 (forward-sexp 1)
1380 (let ((newpos (point)))
1381 (skip-syntax-backward "/w")
1382 (cond
1383 ((looking-at "\\\\end\\>")
1384 (signal 'scan-error
1385 (list "Containing expression ends prematurely"
1386 (point)
1387 (prog1
1388 (progn (ignore-errors (forward-sexp 2)) (point))
1389 (goto-char pos)))))
1390 ((looking-at "\\\\begin\\>")
1391 (goto-char (match-end 0))
1392 (tex-next-unmatched-end))
1393 (t (goto-char newpos))))))
1394
1395(defun latex-forward-sexp (&optional arg)
1396 "Like `forward-sexp' but aware of multi-char elements."
1397 (interactive "P")
1398 (unless arg (setq arg 1))
1399 (let ((pos (point)))
1400 (condition-case err
1401 (while (/= arg 0)
1402 (setq arg
1403 (if (> arg 0)
1404 (progn (latex-forward-sexp-1) (1- arg))
1405 (progn (latex-backward-sexp-1) (1+ arg)))))
1406 (scan-error
1407 (goto-char pos)
1408 (signal (car err) (cdr err))))))
1409
ea590e1c
SM
1410(defun latex-syntax-after ()
1411 "Like (char-syntax (char-after)) but aware of multi-char elements."
15ca8de7 1412 (if (looking-at "\\\\end\\>") ?\) (char-syntax (following-char))))
ea590e1c
SM
1413
1414(defun latex-skip-close-parens ()
1415 "Like (skip-syntax-forward \" )\") but aware of multi-char elements."
1416 (let ((forward-sexp-function nil))
1417 (while (progn (skip-syntax-forward " )")
1418 (looking-at "\\\\end\\>"))
1419 (forward-sexp 2))))
1420
1421(defun latex-down-list ()
1422 "Like (down-list 1) but aware of multi-char elements."
1423 (forward-comment (point-max))
1424 (let ((forward-sexp-function nil))
1425 (if (not (looking-at "\\\\begin\\>"))
1426 (down-list 1)
1427 (forward-sexp 1)
1428 ;; Skip arguments.
7afecb99
SM
1429 (while (looking-at "[ \t]*[[{(]")
1430 (with-syntax-table tex-mode-syntax-table
1431 (forward-sexp))))))
ea590e1c 1432
7afecb99
SM
1433(defalias 'tex-close-latex-block 'latex-close-block)
1434(define-skeleton latex-close-block
1435 "Create an \\end{...} to match the last unclosed \\begin{...}."
1436 (save-excursion
1437 (tex-last-unended-begin)
1438 (if (not (looking-at "\\\\begin\\(\\s *{[^}\n]*}\\)")) '("{" _ "}")
1439 (match-string 1)))
1440 \n "\\end" str > \n)
1441
1442(define-skeleton latex-split-block
1443 "Split the enclosing environment by inserting \\end{..}\\begin{..} at point."
1444 (save-excursion
1445 (tex-last-unended-begin)
1446 (if (not (looking-at "\\\\begin\\(\\s *{[^}\n]*}\\)")) '("{" _ "}")
1447 (prog1 (match-string 1)
1448 (goto-char (match-end 1))
1449 (setq v1 (buffer-substring (point)
1450 (progn
1451 (while (looking-at "[ \t]*[[{]")
1452 (forward-sexp 1))
1453 (point)))))))
1454 \n "\\end" str > \n _ \n "\\begin" str v1 > \n)
15ca8de7
SM
1455
1456(defconst tex-discount-args-cmds
1457 '("begin" "end" "input" "special" "cite" "ref" "include" "includeonly"
1458 "documentclass" "usepackage" "label")
1459 "TeX commands whose arguments should not be counted as text.")
1460
1461(defun tex-count-words (begin end)
1462 "Count the number of words in the buffer."
1463 (interactive
1464 (if (and transient-mark-mode mark-active)
1465 (list (region-beginning) (region-end))
1466 (list (point-min) (point-max))))
1467 ;; TODO: skip comments and math and maybe some environments.
1468 (save-excursion
1469 (goto-char begin)
1470 (let ((count 0))
1471 (while (and (< (point) end) (re-search-forward "\\<" end t))
1472 (if (not (eq (char-syntax (preceding-char)) ?/))
1473 (progn
1474 ;; Don't count single-char words.
1475 (unless (looking-at ".\\>") (incf count))
1476 (forward-char 1))
1477 (let ((cmd
1478 (buffer-substring-no-properties
1479 (point) (progn (when (zerop (skip-chars-forward "a-zA-Z@"))
1480 (forward-char 1))
1481 (point)))))
1482 (when (member cmd tex-discount-args-cmds)
1483 (skip-chars-forward "*")
1484 (forward-comment (point-max))
1485 (when (looking-at "\\[")
1486 (forward-sexp 1)
1487 (forward-comment (point-max)))
1488 (if (not (looking-at "{"))
1489 (forward-char 1)
1490 (forward-sexp 1))))))
1491 (message "%s words" count))))
b781e739
SS
1492
1493
869bff31 1494\f
1495;;; Invoking TeX in an inferior shell.
1496
15ca8de7
SM
1497;; Why use a shell instead of running TeX directly? Because if TeX
1498;; gets stuck, the user can switch to the shell window and type at it.
869bff31 1499
15ca8de7 1500;; The utility functions:
869bff31 1501
bdbd9606 1502(define-derived-mode tex-shell shell-mode "TeX-Shell"
3f2c97ea
SM
1503 (set (make-local-variable 'compilation-parse-errors-function)
1504 'tex-compilation-parse-errors)
bdbd9606
SM
1505 (compilation-shell-minor-mode t))
1506
d974af30 1507;;;###autoload
869bff31 1508(defun tex-start-shell ()
d6709b80
SM
1509 (with-current-buffer
1510 (make-comint
1511 "tex-shell"
07c16ec4 1512 (or tex-shell-file-name (getenv "ESHELL") shell-file-name)
4042dc25 1513 nil
053be11a 1514 ;; Specify an interactive shell, to make sure it prompts.
4042dc25 1515 "-i")
528415e7
RS
1516 (let ((proc (get-process "tex-shell")))
1517 (set-process-sentinel proc 'tex-shell-sentinel)
003274a0 1518 (set-process-query-on-exit-flag proc nil)
bdbd9606 1519 (tex-shell)
528415e7 1520 (while (zerop (buffer-size))
51b2c841
RS
1521 (sleep-for 1)))))
1522
033306e3
RS
1523(defun tex-feed-input ()
1524 "Send input to the tex shell process.
1525In the tex buffer this can be used to continue an interactive tex run.
bed1b0c8 1526In the tex shell buffer this command behaves like `comint-send-input'."
033306e3 1527 (interactive)
b781e739 1528 (set-buffer (tex-shell-buf))
033306e3
RS
1529 (comint-send-input)
1530 (tex-recenter-output-buffer nil))
1531
51b2c841
RS
1532(defun tex-display-shell ()
1533 "Make the TeX shell buffer visible in a window."
b781e739 1534 (display-buffer (tex-shell-buf))
51b2c841 1535 (tex-recenter-output-buffer nil))
528415e7
RS
1536
1537(defun tex-shell-sentinel (proc msg)
1538 (cond ((null (buffer-name (process-buffer proc)))
1539 ;; buffer killed
1540 (set-process-buffer proc nil)
1541 (tex-delete-last-temp-files))
1542 ((memq (process-status proc) '(signal exit))
1543 (tex-delete-last-temp-files))))
1544
1545(defun tex-set-buffer-directory (buffer directory)
869bff31 1546 "Set BUFFER's default directory to be DIRECTORY."
1547 (setq directory (file-name-as-directory (expand-file-name directory)))
1548 (if (not (file-directory-p directory))
1549 (error "%s is not a directory" directory)
1550 (save-excursion
1551 (set-buffer buffer)
1552 (setq default-directory directory))))
1553
30803a05
RS
1554(defvar tex-send-command-modified-tick 0)
1555(make-variable-buffer-local 'tex-send-command-modified-tick)
1556
bdbd9606 1557(defun tex-shell-proc ()
b781e739 1558 (or (tex-shell-running) (error "No TeX subprocess")))
bdbd9606
SM
1559(defun tex-shell-buf ()
1560 (process-buffer (tex-shell-proc)))
b781e739
SS
1561(defun tex-shell-buf-no-error ()
1562 (let ((proc (tex-shell-running)))
1563 (and proc (process-buffer proc))))
bdbd9606 1564
528415e7 1565(defun tex-send-command (command &optional file background)
4cdc1d4b 1566 "Send COMMAND to TeX shell process, substituting optional FILE for *.
8241d7b9
ER
1567Do this in background if optional BACKGROUND is t. If COMMAND has no *,
1568FILE will be appended, preceded by a blank, to COMMAND. If FILE is nil, no
1569substitution will be made in COMMAND. COMMAND can be any expression that
460e1b7d
RS
1570evaluates to a command string.
1571
1572Return the process in which TeX is running."
528415e7
RS
1573 (save-excursion
1574 (let* ((cmd (eval command))
bdbd9606 1575 (proc (tex-shell-proc))
64db2461 1576 (buf (process-buffer proc))
4f45adda 1577 (star (string-match "\\*" cmd))
4cdc1d4b
RS
1578 (string
1579 (concat
1580 (if file
1581 (if star (concat (substring cmd 0 star)
6380e5a7
KB
1582 (shell-quote-argument file)
1583 (substring cmd (1+ star)))
1584 (concat cmd " " (shell-quote-argument file)))
4cdc1d4b
RS
1585 cmd)
1586 (if background "&" ""))))
64db2461
RS
1587 ;; Switch to buffer before checking for subproc output in it.
1588 (set-buffer buf)
30803a05
RS
1589 ;; If text is unchanged since previous tex-send-command,
1590 ;; we haven't got any output. So wait for output now.
64db2461 1591 (if (= (buffer-modified-tick buf) tex-send-command-modified-tick)
30803a05 1592 (accept-process-output proc))
4cdc1d4b
RS
1593 (goto-char (process-mark proc))
1594 (insert string)
30803a05 1595 (comint-send-input)
460e1b7d
RS
1596 (setq tex-send-command-modified-tick (buffer-modified-tick buf))
1597 proc)))
528415e7 1598
a15849cb
RS
1599(defun tex-delete-last-temp-files (&optional not-all)
1600 "Delete any junk files from last temp file.
1601If NOT-ALL is non-nil, save the `.dvi' file."
528415e7
RS
1602 (if tex-last-temp-file
1603 (let* ((dir (file-name-directory tex-last-temp-file))
adf6b7f9
KH
1604 (list (and (file-directory-p dir)
1605 (file-name-all-completions
02fd229c
RS
1606 (file-name-sans-extension
1607 (file-name-nondirectory tex-last-temp-file))
1608 dir))))
adf6b7f9 1609 (while list
a15849cb
RS
1610 (if not-all
1611 (and
1612 ;; If arg is non-nil, don't delete the .dvi file.
1613 (not (string-match "\\.dvi$" (car list)))
1614 (delete-file (concat dir (car list))))
1615 (delete-file (concat dir (car list))))
528415e7
RS
1616 (setq list (cdr list))))))
1617
99621a14 1618(add-hook 'kill-emacs-hook 'tex-delete-last-temp-files)
869bff31 1619
75035a80
SM
1620;;
1621;; Machinery to guess the command that the user wants to execute.
1622;;
1623
1624(defvar tex-compile-history nil)
1625
1626(defvar tex-input-files-re
1627 (eval-when-compile
1628 (concat "\\." (regexp-opt '("tex" "texi" "texinfo"
1629 "bbl" "ind" "sty" "cls") t)
1630 ;; Include files with no dots (for directories).
1631 "\\'\\|\\`[^.]+\\'")))
1632
1633(defcustom tex-use-reftex t
1634 "If non-nil, use RefTeX's list of files to determine what command to use."
18a8c773
LK
1635 :type 'boolean
1636 :group 'tex)
75035a80
SM
1637
1638(defvar tex-compile-commands
1639 '(((concat "pdf" tex-command
bf4ec222 1640 " " (if (< 0 (length tex-start-commands))
d18fc930 1641 (shell-quote-argument tex-start-commands)) " %f")
75035a80
SM
1642 t "%r.pdf")
1643 ((concat tex-command
bf4ec222 1644 " " (if (< 0 (length tex-start-commands))
d18fc930 1645 (shell-quote-argument tex-start-commands)) " %f")
75035a80
SM
1646 t "%r.dvi")
1647 ("xdvi %r &" "%r.dvi")
29a47b89
SM
1648 ("xpdf %r.pdf &" "%r.pdf")
1649 ("gv %r.ps &" "%r.ps")
1650 ("yap %r &" "%r.dvi")
75035a80 1651 ("advi %r &" "%r.dvi")
29a47b89 1652 ("gv %r.pdf &" "%r.pdf")
75035a80
SM
1653 ("bibtex %r" "%r.aux" "%r.bbl")
1654 ("makeindex %r" "%r.idx" "%r.ind")
1655 ("texindex %r.??")
1656 ("dvipdfm %r" "%r.dvi" "%r.pdf")
1657 ("dvipdf %r" "%r.dvi" "%r.pdf")
dd166d5f 1658 ("dvips -o %r.ps %r" "%r.dvi" "%r.ps")
e70ff1af 1659 ("ps2pdf %r.ps" "%r.ps" "%r.pdf")
75035a80
SM
1660 ("lpr %r.ps" "%r.ps"))
1661 "List of commands for `tex-compile'.
1662Each element should be of the form (FORMAT IN OUT) where
1663FORMAT is an expression that evaluates to a string that can contain
1664 - `%r' the main file name without extension.
1665 - `%f' the main file name.
1666IN can be either a string (with the same % escapes in it) indicating
1667 the name of the input file, or t to indicate that the input is all
1668 the TeX files of the document, or nil if we don't know.
1669OUT describes the output file and is either a %-escaped string
1670 or nil to indicate that there is no output file.")
1671
8084f5d8
SM
1672;; defsubst* gives better byte-code than defsubst.
1673(defsubst* tex-string-prefix-p (str1 str2)
1674 "Return non-nil if STR1 is a prefix of STR2"
1675 (eq t (compare-strings str2 nil (length str1) str1 nil nil)))
1676
dd459839
SM
1677(defun tex-guess-main-file (&optional all)
1678 "Find a likely `tex-main-file'.
1679Looks for hints in other buffers in the same directory or in
8084f5d8
SM
1680ALL other buffers. If ALL is `sub' only look at buffers in parent directories
1681of the current buffer."
dd459839
SM
1682 (let ((dir default-directory)
1683 (header-re tex-start-of-header))
1684 (catch 'found
1685 ;; Look for a buffer with `tex-main-file' set.
1686 (dolist (buf (if (consp all) all (buffer-list)))
1687 (with-current-buffer buf
8084f5d8
SM
1688 (when (and (cond
1689 ((null all) (equal dir default-directory))
1690 ((eq all 'sub) (tex-string-prefix-p default-directory dir))
1691 (t))
dd459839
SM
1692 (stringp tex-main-file))
1693 (throw 'found (expand-file-name tex-main-file)))))
1694 ;; Look for a buffer containing the magic `tex-start-of-header'.
1695 (dolist (buf (if (consp all) all (buffer-list)))
1696 (with-current-buffer buf
8084f5d8
SM
1697 (when (and (cond
1698 ((null all) (equal dir default-directory))
1699 ((eq all 'sub) (tex-string-prefix-p default-directory dir))
1700 (t))
dd459839
SM
1701 buffer-file-name
1702 ;; (or (easy-mmode-derived-mode-p 'latex-mode)
1703 ;; (easy-mmode-derived-mode-p 'plain-tex-mode))
1704 (save-excursion
cb30255a
SM
1705 (save-restriction
1706 (widen)
1707 (goto-char (point-min))
95a045bd
SM
1708 (re-search-forward
1709 header-re (+ (point) 10000) t))))
dd459839
SM
1710 (throw 'found (expand-file-name buffer-file-name))))))))
1711
07c16ec4
SM
1712(defun tex-main-file ()
1713 "Return the relative name of the main file."
bdbd9606
SM
1714 (let* ((file (or tex-main-file
1715 ;; Compatibility with AUCTeX.
96c0d9e9 1716 (with-no-warnings
034a48f4
MR
1717 (when (boundp 'TeX-master)
1718 (cond ((stringp TeX-master)
1719 (make-local-variable 'tex-main-file)
1720 (setq tex-main-file TeX-master))
1721 ((and (eq TeX-master t) buffer-file-name)
1722 (file-relative-name buffer-file-name)))))
bdbd9606
SM
1723 ;; Try to guess the main file.
1724 (if (not buffer-file-name)
1725 (error "Buffer is not associated with any file")
1726 (file-relative-name
1727 (if (save-excursion
1728 (goto-char (point-min))
95a045bd
SM
1729 (re-search-forward tex-start-of-header
1730 (+ (point) 10000) t))
bdbd9606
SM
1731 ;; This is the main file.
1732 buffer-file-name
1733 ;; This isn't the main file, let's try to find better,
1734 (or (tex-guess-main-file)
8084f5d8 1735 (tex-guess-main-file 'sub)
bdbd9606 1736 ;; (tex-guess-main-file t)
07c16ec4 1737 buffer-file-name)))))))
e70ff1af
SM
1738 (if (or (file-exists-p file) (string-match "\\.tex\\'" file))
1739 file (concat file ".tex"))))
dd459839 1740
75035a80
SM
1741(defun tex-summarize-command (cmd)
1742 (if (not (stringp cmd)) ""
1743 (mapconcat 'identity
1744 (mapcar (lambda (s) (car (split-string s)))
1745 (split-string cmd "\\s-*\\(?:;\\|&&\\)\\s-*"))
1746 "&")))
1747
1748(defun tex-uptodate-p (file)
1749 "Return non-nil if FILE is not uptodate w.r.t the document source files.
1750FILE is typically the output DVI or PDF file."
1751 ;; We should check all the files included !!!
1752 (and
1753 ;; Clearly, the target must exist.
1754 (file-exists-p file)
1755 ;; And the last run must not have asked for a rerun.
1756 ;; FIXME: this should check that the last run was done on the same file.
1757 (let ((buf (condition-case nil (tex-shell-buf) (error nil))))
1758 (when buf
1759 (with-current-buffer buf
1760 (save-excursion
1761 (goto-char (point-max))
1762 (and (re-search-backward
1763 "(see the transcript file for additional information)" nil t)
1764 (> (save-excursion
1765 (or (re-search-backward "\\[[0-9]+\\]" nil t)
1766 (point-min)))
1767 (save-excursion
1768 (or (re-search-backward "Rerun" nil t)
1769 (point-min)))))))))
1770 ;; And the input files must not have been changed in the meantime.
1771 (let ((files (if (and tex-use-reftex
1772 (fboundp 'reftex-scanning-info-available-p)
1773 (reftex-scanning-info-available-p))
1774 (reftex-all-document-files)
1775 (list (file-name-directory (expand-file-name file)))))
1776 (ignored-dirs-re
1777 (concat
1778 (regexp-opt
1779 (delq nil (mapcar (lambda (s) (if (eq (aref s (1- (length s))) ?/)
1780 (substring s 0 (1- (length s)))))
1781 completion-ignored-extensions))
1782 t) "\\'"))
1783 (uptodate t))
1784 (while (and files uptodate)
1785 (let ((f (pop files)))
e70ff1af
SM
1786 (if (and (file-directory-p f)
1787 ;; Avoid infinite loops.
1788 (not (file-symlink-p f)))
75035a80
SM
1789 (unless (string-match ignored-dirs-re f)
1790 (setq files (nconc
1791 (directory-files f t tex-input-files-re)
1792 files)))
1793 (when (file-newer-than-file-p f file)
1794 (setq uptodate nil)))))
1795 uptodate)))
bf247b6e 1796
75035a80
SM
1797
1798(autoload 'format-spec "format-spec")
1799
1800(defvar tex-executable-cache nil)
1801(defun tex-executable-exists-p (name)
1802 "Like `executable-find' but with a cache."
1803 (let ((cache (assoc name tex-executable-cache)))
1804 (if cache (cdr cache)
1805 (let ((executable (executable-find name)))
1806 (push (cons name executable) tex-executable-cache)
1807 executable))))
1808
1809(defun tex-command-executable (cmd)
1810 (let ((s (if (stringp cmd) cmd (eval (car cmd)))))
1811 (substring s 0 (string-match "[ \t]\\|\\'" s))))
1812
1813(defun tex-command-active-p (cmd fspec)
1814 "Return non-nil if the CMD spec might need to be run."
1815 (let ((in (nth 1 cmd))
1816 (out (nth 2 cmd)))
1817 (if (stringp in)
1818 (let ((file (format-spec in fspec)))
1819 (when (file-exists-p file)
1820 (or (not out)
1821 (file-newer-than-file-p
1822 file (format-spec out fspec)))))
1823 (when (and (eq in t) (stringp out))
1824 (not (tex-uptodate-p (format-spec out fspec)))))))
1825
8084f5d8 1826(defun tex-compile-default (fspec)
dd166d5f 1827 "Guess a default command given the `format-spec' FSPEC."
75035a80
SM
1828 ;; TODO: Learn to do latex+dvips!
1829 (let ((cmds nil)
1830 (unchanged-in nil))
1831 ;; Only consider active commands.
1832 (dolist (cmd tex-compile-commands)
1833 (when (tex-executable-exists-p (tex-command-executable cmd))
1834 (if (tex-command-active-p cmd fspec)
1835 (push cmd cmds)
1836 (push (nth 1 cmd) unchanged-in))))
dd166d5f 1837 ;; If no command seems to be applicable, arbitrarily pick the first one.
29a47b89 1838 (setq cmds (if cmds (nreverse cmds) (list (car tex-compile-commands))))
75035a80
SM
1839 ;; Remove those commands whose input was considered stable for
1840 ;; some other command (typically if (t . "%.pdf") is inactive
1841 ;; then we're using pdflatex and the fact that the dvi file
1842 ;; is inexistent doesn't matter).
1843 (let ((tmp nil))
1844 (dolist (cmd cmds)
1845 (unless (member (nth 1 cmd) unchanged-in)
1846 (push cmd tmp)))
8084f5d8 1847 ;; Only remove if there's something left.
29a47b89 1848 (if tmp (setq cmds (nreverse tmp))))
8084f5d8
SM
1849 ;; Remove commands whose input is not uptodate either.
1850 (let ((outs (delq nil (mapcar (lambda (x) (nth 2 x)) cmds)))
1851 (tmp nil))
1852 (dolist (cmd cmds)
75035a80 1853 (unless (member (nth 1 cmd) outs)
8084f5d8
SM
1854 (push cmd tmp)))
1855 ;; Only remove if there's something left.
29a47b89 1856 (if tmp (setq cmds (nreverse tmp))))
75035a80
SM
1857 ;; Select which file we're going to operate on (the latest).
1858 (let ((latest (nth 1 (car cmds))))
1859 (dolist (cmd (prog1 (cdr cmds) (setq cmds (list (car cmds)))))
1860 (if (equal latest (nth 1 cmd))
1861 (push cmd cmds)
1862 (unless (eq latest t) ;Can't beat that!
1863 (if (or (not (stringp latest))
1864 (eq (nth 1 cmd) t)
1865 (and (stringp (nth 1 cmd))
1866 (file-newer-than-file-p
1867 (format-spec (nth 1 cmd) fspec)
1868 (format-spec latest fspec))))
1869 (setq latest (nth 1 cmd) cmds (list cmd)))))))
1870 ;; Expand the command spec into the actual text.
1871 (dolist (cmd (prog1 cmds (setq cmds nil)))
1872 (push (cons (eval (car cmd)) (cdr cmd)) cmds))
1873 ;; Select the favorite command from the history.
1874 (let ((hist tex-compile-history)
8084f5d8 1875 re hist-cmd)
75035a80 1876 (while hist
8084f5d8 1877 (setq hist-cmd (pop hist))
75035a80 1878 (setq re (concat "\\`"
8084f5d8 1879 (regexp-quote (tex-command-executable hist-cmd))
75035a80
SM
1880 "\\([ \t]\\|\\'\\)"))
1881 (dolist (cmd cmds)
8084f5d8
SM
1882 ;; If the hist entry uses the same command and applies to a file
1883 ;; of the same type (e.g. `gv %r.pdf' vs `gv %r.ps'), select cmd.
1884 (and (string-match re (car cmd))
1885 (or (not (string-match "%[fr]\\([-._[:alnum:]]+\\)" (car cmd)))
1886 (string-match (regexp-quote (match-string 1 (car cmd)))
1887 hist-cmd))
1888 (setq hist nil cmds (list cmd)))))
1889 ;; Substitute and return.
1890 (if (and hist-cmd
1891 (string-match (concat "[' \t\"]" (format-spec "%r" fspec)
1892 "\\([;&' \t\"]\\|\\'\\)") hist-cmd))
1893 ;; The history command was already applied to the same file,
1894 ;; so just reuse it.
1895 hist-cmd
1896 (if cmds (format-spec (caar cmds) fspec))))))
75035a80
SM
1897
1898(defun tex-compile (dir cmd)
1899 "Run a command CMD on current TeX buffer's file in DIR."
1900 ;; FIXME: Use time-stamps on files to decide the next op.
1901 (interactive
1902 (let* ((file (tex-main-file))
5e56fb53
SM
1903 (default-directory
1904 (prog1 (file-name-directory (expand-file-name file))
1905 (setq file (file-name-nondirectory file))))
75035a80 1906 (root (file-name-sans-extension file))
d18fc930
SM
1907 (fspec (list (cons ?r (shell-quote-argument root))
1908 (cons ?f (shell-quote-argument file))))
8084f5d8 1909 (default (tex-compile-default fspec)))
5e56fb53 1910 (list default-directory
75035a80
SM
1911 (completing-read
1912 (format "Command [%s]: " (tex-summarize-command default))
1913 (mapcar (lambda (x)
1914 (list (format-spec (eval (car x)) fspec)))
1915 tex-compile-commands)
1916 nil nil nil 'tex-compile-history default))))
1917 (save-some-buffers (not compilation-ask-about-save) nil)
1918 (if (tex-shell-running)
1919 (tex-kill-job)
1920 (tex-start-shell))
1921 (tex-send-tex-command cmd dir))
d6709b80
SM
1922
1923(defun tex-start-tex (command file &optional dir)
460e1b7d 1924 "Start a TeX run, using COMMAND on FILE."
6633b891 1925 (let* ((star (string-match "\\*" command))
460e1b7d 1926 (compile-command
6633b891
KH
1927 (if star
1928 (concat (substring command 0 star)
d18fc930 1929 (shell-quote-argument file)
6633b891
KH
1930 (substring command (1+ star)))
1931 (concat command " "
95a045bd 1932 tex-start-options
9e0ad27a 1933 (if (< 0 (length tex-start-commands))
d18fc930
SM
1934 (concat
1935 (shell-quote-argument tex-start-commands) " "))
1936 (shell-quote-argument file)))))
bdbd9606
SM
1937 (tex-send-tex-command compile-command dir)))
1938
1939(defun tex-send-tex-command (cmd &optional dir)
b781e739
SS
1940 (unless (or (equal dir (let ((buf (tex-shell-buf-no-error)))
1941 (and buf (with-current-buffer buf
1942 default-directory))))
bdbd9606
SM
1943 (not dir))
1944 (let (shell-dirtrack-verbose)
966e4990
EZ
1945 (tex-send-command tex-shell-cd-command
1946 (concat "\"" (convert-standard-filename dir) "\""))))
bdbd9606 1947 (with-current-buffer (process-buffer (tex-send-command cmd))
bdbd9606
SM
1948 (setq compilation-last-buffer (current-buffer))
1949 (compilation-forget-errors)
1598a961 1950 ;; Don't parse previous compilations.
bdbd9606
SM
1951 (set-marker compilation-parsing-end (1- (point-max))))
1952 (tex-display-shell)
1953 (setq tex-last-buffer-texed (current-buffer)))
460e1b7d 1954\f
1598a961
SM
1955(defvar tex-error-parse-syntax-table
1956 (let ((st (make-syntax-table)))
1957 (modify-syntax-entry ?\( "()" st)
1958 (modify-syntax-entry ?\) ")(" st)
1959 (modify-syntax-entry ?\\ "\\" st)
1960 (modify-syntax-entry ?\{ "_" st)
1961 (modify-syntax-entry ?\} "_" st)
1962 (modify-syntax-entry ?\[ "_" st)
1963 (modify-syntax-entry ?\] "_" st)
1964 ;; Single quotations may appear in errors
1965 (modify-syntax-entry ?\" "_" st)
1966 st)
1967 "Syntax-table used while parsing TeX error messages.")
1968
460e1b7d 1969(defun tex-compilation-parse-errors (limit-search find-at-least)
f05bd645
RS
1970 "Parse the current buffer as TeX error messages.
1971See the variable `compilation-parse-errors-function' for the interface it uses.
1972
1973This function parses only the last TeX compilation.
1974It works on TeX compilations only. It is necessary for that purpose,
1975since TeX does not put file names and line numbers on the same line as
1976for the error messages."
460e1b7d
RS
1977 (require 'thingatpt)
1978 (setq compilation-error-list nil)
f05bd645
RS
1979 (let ((default-directory ; Perhaps dir has changed meanwhile.
1980 (file-name-directory (buffer-file-name tex-last-buffer-texed)))
f05bd645
RS
1981 found-desired (num-errors-found 0)
1982 last-filename last-linenum last-position
1983 begin-of-error end-of-error)
f05bd645
RS
1984 ;; Don't reparse messages already seen at last parse.
1985 (goto-char compilation-parsing-end)
1986 ;; Parse messages.
1987 (while (and (not (or found-desired (eobp)))
1988 (prog1 (re-search-forward "^! " nil 'move)
1989 (setq begin-of-error (match-beginning 0)
1990 end-of-error (match-end 0)))
1991 (re-search-forward
1992 "^l\\.\\([0-9]+\\) \\(\\.\\.\\.\\)?\\(.*\\)$" nil 'move))
3f2c97ea 1993 (let* ((this-error (copy-marker begin-of-error))
003274a0 1994 (linenum (string-to-number (match-string 1)))
f05bd645
RS
1995 (error-text (regexp-quote (match-string 3)))
1996 (filename
1997 (save-excursion
ea590e1c
SM
1998 (with-syntax-table tex-error-parse-syntax-table
1999 (backward-up-list 1)
2000 (skip-syntax-forward "(_")
2001 (while (not (file-readable-p (thing-at-point 'filename)))
2002 (skip-syntax-backward "(_")
2003 (backward-up-list 1)
2004 (skip-syntax-forward "(_"))
2005 (thing-at-point 'filename))))
f05bd645
RS
2006 (new-file
2007 (or (null last-filename)
2008 (not (string-equal last-filename filename))))
2009 (error-location
cc9f5376
SM
2010 (with-current-buffer
2011 (if (equal filename (concat tex-zap-file ".tex"))
2012 tex-last-buffer-texed
2013 (find-file-noselect filename))
2014 (save-excursion
2015 (if new-file
2016 (progn (goto-line linenum) (setq last-position nil))
2017 (goto-char last-position)
2018 (forward-line (- linenum last-linenum)))
2019 ;; first try a forward search for the error text,
2020 ;; then a backward search limited by the last error.
2021 (let ((starting-point (point)))
2022 (or (re-search-forward error-text nil t)
2023 (re-search-backward error-text last-position t)
2024 (goto-char starting-point)))
2025 (point-marker)))))
f05bd645
RS
2026 (goto-char this-error)
2027 (if (and compilation-error-list
2028 (or (and find-at-least
2029 (>= num-errors-found
2030 find-at-least))
2031 (and limit-search
2032 (>= end-of-error limit-search)))
2033 new-file)
2034 (setq found-desired t)
2035 (setq num-errors-found (1+ num-errors-found)
2036 last-filename filename
2037 last-linenum linenum
2038 last-position error-location
2039 compilation-error-list ; Add the new error
2040 (cons (cons this-error error-location)
2041 compilation-error-list))
2042 (goto-char end-of-error)))))
ee13a145 2043 (set-marker compilation-parsing-end (point))
13376c78 2044 (setq compilation-error-list (nreverse compilation-error-list)))
460e1b7d 2045\f
528415e7 2046;;; The commands:
869bff31 2047
2048(defun tex-region (beg end)
2049 "Run TeX on the current region, via a temporary file.
2050The file's name comes from the variable `tex-zap-file' and the
2051variable `tex-directory' says where to put it.
2052
2053If the buffer has a header, the header is given to TeX before the
2054region itself. The buffer's header is all lines between the strings
2055defined by `tex-start-of-header' and `tex-end-of-header' inclusive.
2056The header must start in the first 100 lines of the buffer.
2057
2058The value of `tex-trailer' is given to TeX as input after the region.
2059
2060The value of `tex-command' specifies the command to use to run TeX."
2061 (interactive "r")
2062 (if (tex-shell-running)
2063 (tex-kill-job)
2064 (tex-start-shell))
2065 (or tex-zap-file
2066 (setq tex-zap-file (tex-generate-zap-file-name)))
6d34c59f
RS
2067 ;; Temp file will be written and TeX will be run in zap-directory.
2068 ;; If the TEXINPUTS file has relative directories or if the region has
2069 ;; \input of files, this must be the same directory as the file for
2070 ;; TeX to access the correct inputs. That's why it's safest if
2071 ;; tex-directory is ".".
2072 (let* ((zap-directory
528415e7 2073 (file-name-as-directory (expand-file-name tex-directory)))
d6709b80
SM
2074 (tex-out-file (expand-file-name (concat tex-zap-file ".tex")
2075 zap-directory)))
0d548e5d
RS
2076 ;; Don't delete temp files if we do the same buffer twice in a row.
2077 (or (eq (current-buffer) tex-last-buffer-texed)
2078 (tex-delete-last-temp-files t))
869bff31 2079 ;; Write the new temp file.
2080 (save-excursion
2081 (save-restriction
2082 (widen)
2083 (goto-char (point-min))
2084 (forward-line 100)
2085 (let ((search-end (point))
6d34c59f
RS
2086 (default-directory zap-directory)
2087 (already-output 0))
869bff31 2088 (goto-char (point-min))
6d34c59f 2089
725b7428
RS
2090 ;; Maybe copy first line, such as `\input texinfo', to temp file.
2091 (and tex-first-line-header-regexp
2092 (looking-at tex-first-line-header-regexp)
bed1b0c8 2093 (write-region (point)
6d34c59f
RS
2094 (progn (forward-line 1)
2095 (setq already-output (point)))
725b7428
RS
2096 tex-out-file nil nil))
2097
6d34c59f
RS
2098 ;; Write out the header, if there is one,
2099 ;; and any of the specified region which extends before it.
2100 ;; But don't repeat anything already written.
898b9ac1 2101 (if (re-search-forward tex-start-of-header search-end t)
6d34c59f 2102 (let (hbeg)
869bff31 2103 (beginning-of-line)
2104 (setq hbeg (point)) ;mark beginning of header
898b9ac1 2105 (if (re-search-forward tex-end-of-header nil t)
6d34c59f
RS
2106 (let (hend)
2107 (forward-line 1)
bed1b0c8 2108 (setq hend (point)) ;mark end of header
6d34c59f
RS
2109 (write-region (max (min hbeg beg) already-output)
2110 hend
2111 tex-out-file
2112 (not (zerop already-output)) nil)
2113 (setq already-output hend)))))
2114
2115 ;; Write out the specified region
2116 ;; (but don't repeat anything already written).
2117 (write-region (max beg already-output) end
2118 tex-out-file
2119 (not (zerop already-output)) nil))
2120 ;; Write the trailer, if any.
2121 ;; Precede it with a newline to make sure it
2122 ;; is not hidden in a comment.
2123 (if tex-trailer
2124 (write-region (concat "\n" tex-trailer) nil
2125 tex-out-file t nil))))
528415e7
RS
2126 ;; Record the file name to be deleted afterward.
2127 (setq tex-last-temp-file tex-out-file)
f05bd645
RS
2128 ;; Use a relative file name here because (1) the proper dir
2129 ;; is already current, and (2) the abs file name is sometimes
2130 ;; too long and can make tex crash.
d6709b80
SM
2131 (tex-start-tex tex-command (concat tex-zap-file ".tex") zap-directory)
2132 (setq tex-print-file tex-out-file)))
869bff31 2133
2134(defun tex-buffer ()
2135 "Run TeX on current buffer. See \\[tex-region] for more information.
528415e7
RS
2136Does not save the buffer, so it's useful for trying experimental versions.
2137See \\[tex-file] for an alternative."
869bff31 2138 (interactive)
2139 (tex-region (point-min) (point-max)))
2140
2141(defun tex-file ()
2142 "Prompt to save all buffers and run TeX (or LaTeX) on current buffer's file.
2143This function is more useful than \\[tex-buffer] when you need the
2144`.aux' file of LaTeX to have the correct name."
2145 (interactive)
7abc9add
SS
2146 (when tex-offer-save
2147 (save-some-buffers))
d6709b80 2148 (let* ((source-file (tex-main-file))
07c16ec4 2149 (file-dir (file-name-directory (expand-file-name source-file))))
869bff31 2150 (if (tex-shell-running)
2151 (tex-kill-job)
2152 (tex-start-shell))
d6709b80 2153 (tex-start-tex tex-command source-file file-dir)
f05bd645 2154 (setq tex-print-file (expand-file-name source-file))))
869bff31 2155
2156(defun tex-generate-zap-file-name ()
2157 "Generate a unique name suitable for use as a file name."
2158 ;; Include the shell process number and host name
2159 ;; in case there are multiple shells (for same or different user).
f5cdb851
KH
2160 ;; Dec 1998: There is a report that some versions of xdvi
2161 ;; don't work with file names that start with #.
5616ee46 2162 (format "_TZ_%d-%s"
869bff31 2163 (process-id (get-buffer-process "*tex-shell*"))
07c16ec4 2164 (subst-char-in-string ?. ?- (system-name))))
869bff31 2165
2166;; This will perhaps be useful for modifying TEXINPUTS.
2167;; Expand each file name, separated by colons, in the string S.
2168(defun tex-expand-files (s)
2169 (let (elts (start 0))
2170 (while (string-match ":" s start)
2171 (setq elts (cons (substring s start (match-beginning 0)) elts))
2172 (setq start (match-end 0)))
2173 (or (= start 0)
2174 (setq elts (cons (substring s start) elts)))
c0df1972
SM
2175 (mapconcat (lambda (elt)
2176 (if (= (length elt) 0) elt (expand-file-name elt)))
5616ee46 2177 (nreverse elts) ":")))
869bff31 2178
2179(defun tex-shell-running ()
713f7b15 2180 (let ((proc (get-process "tex-shell")))
b781e739
SS
2181 (when proc
2182 (if (and (eq (process-status proc) 'run)
2183 (buffer-live-p (process-buffer proc)))
2184 ;; return the TeX process on success
2185 proc
2186 ;; get rid of the process permanently
2187 ;; this should get rid of the annoying w32 problem with
2188 ;; dead tex-shell buffer and live process
2189 (delete-process proc)))))
869bff31 2190
2191(defun tex-kill-job ()
2192 "Kill the currently running TeX job."
2193 (interactive)
b781e739 2194 ;; `quit-process' leads to core dumps of the tex process (except if
bed1b0c8
RS
2195 ;; coredumpsize has limit 0kb as on many environments). One would
2196 ;; like to use (kill-process proc 'lambda), however that construct
2197 ;; does not work on some systems and kills the shell itself.
b781e739
SS
2198 (let ((proc (get-process "tex-shell")))
2199 (when proc (quit-process proc t))))
869bff31 2200
2201(defun tex-recenter-output-buffer (linenum)
2202 "Redisplay buffer of TeX job output so that most recent output can be seen.
2203The last line of the buffer is displayed on
2204line LINE of the window, or centered if LINE is nil."
2205 (interactive "P")
2206 (let ((tex-shell (get-buffer "*tex-shell*"))
23b64225 2207 (window))
869bff31 2208 (if (null tex-shell)
2209 (message "No TeX output buffer")
23b64225
RS
2210 (setq window (display-buffer tex-shell))
2211 (save-selected-window
2212 (select-window window)
2213 (bury-buffer tex-shell)
2214 (goto-char (point-max))
2215 (recenter (if linenum
2216 (prefix-numeric-value linenum)
2217 (/ (window-height) 2)))))))
869bff31 2218
528415e7 2219(defun tex-print (&optional alt)
869bff31 2220 "Print the .dvi file made by \\[tex-region], \\[tex-buffer] or \\[tex-file].
1433a222
CZ
2221Runs the shell command defined by `tex-dvi-print-command'. If prefix argument
2222is provided, use the alternative command, `tex-alt-dvi-print-command'."
528415e7 2223 (interactive "P")
869bff31 2224 (let ((print-file-name-dvi (tex-append tex-print-file ".dvi"))
2225 test-name)
2226 (if (and (not (equal (current-buffer) tex-last-buffer-texed))
45c3304d
RS
2227 (buffer-file-name)
2228 ;; Check that this buffer's printed file is up to date.
869bff31 2229 (file-newer-than-file-p
2230 (setq test-name (tex-append (buffer-file-name) ".dvi"))
45c3304d 2231 (buffer-file-name)))
869bff31 2232 (setq print-file-name-dvi test-name))
528415e7
RS
2233 (if (not (file-exists-p print-file-name-dvi))
2234 (error "No appropriate `.dvi' file could be found")
460e1b7d
RS
2235 (if (tex-shell-running)
2236 (tex-kill-job)
2237 (tex-start-shell))
528415e7 2238 (tex-send-command
bed1b0c8 2239 (if alt tex-alt-dvi-print-command tex-dvi-print-command)
b5352ff5 2240 print-file-name-dvi
602503c5 2241 t))))
869bff31 2242
cf6d6e8a
RS
2243(defun tex-alt-print ()
2244 "Print the .dvi file made by \\[tex-region], \\[tex-buffer] or \\[tex-file].
002b0d00 2245Runs the shell command defined by `tex-alt-dvi-print-command'."
cf6d6e8a
RS
2246 (interactive)
2247 (tex-print t))
2248
869bff31 2249(defun tex-view ()
2250 "Preview the last `.dvi' file made by running TeX under Emacs.
2251This means, made using \\[tex-region], \\[tex-buffer] or \\[tex-file].
2b7971c9
RS
2252The variable `tex-dvi-view-command' specifies the shell command for preview.
2253You must set that variable yourself before using this command,
2254because there is no standard value that would generally work."
869bff31 2255 (interactive)
2b7971c9
RS
2256 (or tex-dvi-view-command
2257 (error "You must set `tex-dvi-view-command'"))
3356ce3b
EZ
2258 ;; Restart the TeX shell if necessary.
2259 (or (tex-shell-running)
2260 (tex-start-shell))
746c30e2 2261 (let ((tex-dvi-print-command (eval tex-dvi-view-command)))
869bff31 2262 (tex-print)))
2263
2264(defun tex-append (file-name suffix)
2265 "Append to FILENAME the suffix SUFFIX, using same algorithm TeX uses.
cf6d6e8a 2266Pascal-based TeX scans for the first period, C TeX uses the last.
869bff31 2267No period is retained immediately before SUFFIX,
2268so normally SUFFIX starts with one."
2269 (if (stringp file-name)
cf6d6e8a
RS
2270 (let ((file (file-name-nondirectory file-name))
2271 trial-name)
6da9bbd6 2272 ;; Try splitting on last period.
7d0ca249
RS
2273 ;; The first-period split can get fooled when two files
2274 ;; named a.tex and a.b.tex are both tex'd;
2275 ;; the last-period split must be right if it matches at all.
cf6d6e8a
RS
2276 (setq trial-name
2277 (concat (file-name-directory file-name)
2278 (substring file 0
7d0ca249 2279 (string-match "\\.[^.]*$" file))
cf6d6e8a
RS
2280 suffix))
2281 (if (or (file-exists-p trial-name)
2282 (file-exists-p (concat trial-name ".aux"))) ;for BibTeX files
2283 trial-name
7d0ca249 2284 ;; Not found, so split on first period.
cf6d6e8a
RS
2285 (concat (file-name-directory file-name)
2286 (substring file 0
7d0ca249 2287 (string-match "\\." file))
cf6d6e8a 2288 suffix)))
869bff31 2289 " "))
2290
2291(defun tex-show-print-queue ()
2292 "Show the print queue that \\[tex-print] put your job on.
1433a222 2293Runs the shell command defined by `tex-show-queue-command'."
869bff31 2294 (interactive)
2295 (if (tex-shell-running)
2296 (tex-kill-job)
2297 (tex-start-shell))
51b2c841
RS
2298 (tex-send-command tex-show-queue-command)
2299 (tex-display-shell))
869bff31 2300
2301(defun tex-bibtex-file ()
2302 "Run BibTeX on the current buffer's file."
2303 (interactive)
2304 (if (tex-shell-running)
2305 (tex-kill-job)
2306 (tex-start-shell))
e6b0b773
MR
2307 (let (shell-dirtrack-verbose
2308 (tex-out-file
869bff31 2309 (tex-append (file-name-nondirectory (buffer-file-name)) ""))
2310 (file-dir (file-name-directory (buffer-file-name))))
966e4990
EZ
2311 (tex-send-command tex-shell-cd-command
2312 (concat "\"" (convert-standard-filename file-dir) "\""))
51b2c841
RS
2313 (tex-send-command tex-bibtex-command tex-out-file))
2314 (tex-display-shell))
ea590e1c
SM
2315\f
2316;;;;
2317;;;; LaTeX indentation
2318;;;;
2319
2320(defvar tex-indent-allhanging t)
2321(defvar tex-indent-arg 4)
2322(defvar tex-indent-basic 2)
2323(defvar tex-indent-item tex-indent-basic)
2324(defvar tex-indent-item-re "\\\\\\(bib\\)?item\\>")
dd166d5f 2325(defvar latex-noindent-environments '("document"))
ea590e1c 2326
8a591d52
SM
2327(defvar tex-latex-indent-syntax-table
2328 (let ((st (make-syntax-table tex-mode-syntax-table)))
2329 (modify-syntax-entry ?$ "." st)
2330 (modify-syntax-entry ?\( "." st)
2331 (modify-syntax-entry ?\) "." st)
2332 st)
2333 "Syntax table used while computing indentation.")
ea590e1c
SM
2334
2335(defun latex-indent (&optional arg)
7afecb99
SM
2336 (if (and (eq (get-text-property (line-beginning-position) 'face)
2337 tex-verbatim-face))
a3d80d4a 2338 'noindent
7afecb99
SM
2339 (with-syntax-table tex-latex-indent-syntax-table
2340 ;; TODO: Rather than ignore $, we should try to be more clever about it.
2341 (let ((indent
2342 (save-excursion
2343 (beginning-of-line)
2344 (latex-find-indent))))
2345 (if (< indent 0) (setq indent 0))
2346 (if (<= (current-column) (current-indentation))
2347 (indent-line-to indent)
2348 (save-excursion (indent-line-to indent)))))))
ea590e1c
SM
2349
2350(defun latex-find-indent (&optional virtual)
2351 "Find the proper indentation of text after point.
2352VIRTUAL if non-nil indicates that we're only trying to find the indentation
2353 in order to determine the indentation of something else.
2354There might be text before point."
2355 (save-excursion
2356 (skip-chars-forward " \t")
2357 (or
7afecb99
SM
2358 ;; Stick the first line at column 0.
2359 (and (= (point-min) (line-beginning-position)) 0)
ea590e1c 2360 ;; Trust the current indentation, if such info is applicable.
7afecb99
SM
2361 (and virtual (save-excursion (skip-chars-backward " \t&") (bolp))
2362 (current-column))
2363 ;; Stick verbatim environments to the left margin.
2364 (and (looking-at "\\\\\\(begin\\|end\\) *{\\([^\n}]+\\)")
2365 (member (match-string 2) tex-verbatim-environments)
2366 0)
ea590e1c
SM
2367 ;; Put leading close-paren where the matching open brace would be.
2368 (and (eq (latex-syntax-after) ?\))
2369 (ignore-errors
2370 (save-excursion
2371 (latex-skip-close-parens)
2372 (latex-backward-sexp-1)
2373 (latex-find-indent 'virtual))))
2374 ;; Default (maybe an argument)
2375 (let ((pos (point))
ea590e1c
SM
2376 ;; Outdent \item if necessary.
2377 (indent (if (looking-at tex-indent-item-re) (- tex-indent-item) 0))
2378 up-list-pos)
2379 ;; Find the previous point which determines our current indentation.
2380 (condition-case err
2381 (progn
2382 (latex-backward-sexp-1)
2383 (while (> (current-column) (current-indentation))
2384 (latex-backward-sexp-1)))
2385 (scan-error
2386 (setq up-list-pos (nth 2 err))))
8908cf40
SM
2387 (cond
2388 ((= (point-min) pos) 0) ; We're really just indenting the first line.
2389 ((integerp up-list-pos)
2390 ;; Have to indent relative to the open-paren.
2391 (goto-char up-list-pos)
2392 (if (and (not tex-indent-allhanging)
dd166d5f
SM
2393 (save-excursion
2394 ;; Make sure we're an argument to a macro and
2395 ;; that the macro is at the beginning of a line.
2396 (condition-case nil
2397 (progn
2398 (while (eq (char-syntax (char-after)) ?\()
2399 (forward-sexp -1))
2400 (and (eq (char-syntax (char-after)) ?/)
2401 (progn (skip-chars-backward " \t&")
2402 (bolp))))
2403 (scan-error nil)))
8908cf40
SM
2404 (> pos (progn (latex-down-list)
2405 (forward-comment (point-max))
2406 (point))))
7afecb99 2407 ;; Align with the first element after the open-paren.
8908cf40
SM
2408 (current-column)
2409 ;; We're the first element after a hanging brace.
2410 (goto-char up-list-pos)
dd166d5f
SM
2411 (+ (if (and (looking-at "\\\\begin *{\\([^\n}]+\\)")
2412 (member (match-string 1)
2413 latex-noindent-environments))
2414 0 tex-indent-basic)
2415 indent (latex-find-indent 'virtual))))
8908cf40
SM
2416 ;; We're now at the "beginning" of a line.
2417 ((not (and (not virtual) (eq (char-after) ?\\)))
2418 ;; Nothing particular here: just keep the same indentation.
2419 (+ indent (current-column)))
2420 ;; We're now looking at a macro call.
dd166d5f
SM
2421 ((looking-at tex-indent-item-re)
2422 ;; Indenting relative to an item, have to re-add the outdenting.
8908cf40
SM
2423 (+ indent (current-column) tex-indent-item))
2424 (t
2425 (let ((col (current-column)))
d1218e3e 2426 (if (or (not (eq (char-syntax (or (char-after pos) ?\s)) ?\())
dd166d5f
SM
2427 ;; Can't be an arg if there's an empty line inbetween.
2428 (save-excursion (re-search-forward "^[ \t]*$" pos t)))
8908cf40
SM
2429 ;; If the first char was not an open-paren, there's
2430 ;; a risk that this is really not an argument to the
2431 ;; macro at all.
21749f14
RS
2432 (+ indent col)
2433 (forward-sexp 1)
2434 (if (< (line-end-position)
2435 (save-excursion (forward-comment (point-max))
2436 (point)))
8908cf40
SM
2437 ;; we're indenting the first argument.
2438 (min (current-column) (+ tex-indent-arg col))
2439 (skip-syntax-forward " ")
2440 (current-column))))))))))
a3d80d4a
SM
2441;;; DocTeX support
2442
2443(defun doctex-font-lock-^^A ()
2444 (if (eq (char-after (line-beginning-position)) ?\%)
2445 (progn
2446 (put-text-property
2447 (1- (match-beginning 1)) (match-beginning 1)
2448 'syntax-table
2449 (if (= (1+ (line-beginning-position)) (match-beginning 1))
2450 ;; The `%' is a single-char comment, which Emacs
2451 ;; syntax-table can't deal with. We could turn it
2452 ;; into a non-comment, or use `\n%' or `%^' as the comment.
2453 ;; Instead, we include it in the ^^A comment.
2454 (eval-when-compile (string-to-syntax "< b"))
2455 (eval-when-compile (string-to-syntax ">"))))
2456 (let ((end (line-end-position)))
2457 (if (< end (point-max))
2458 (put-text-property
2459 end (1+ end)
2460 'syntax-table
2461 (eval-when-compile (string-to-syntax "> b")))))
2462 (eval-when-compile (string-to-syntax "< b")))))
2463
2464(defun doctex-font-lock-syntactic-face-function (state)
2465 ;; Mark DocTeX documentation, which is parsed as a style A comment
2466 ;; starting in column 0.
2467 (if (or (nth 3 state) (nth 7 state)
2468 (not (memq (char-before (nth 8 state))
2469 '(?\n nil))))
2470 ;; Anything else is just as for LaTeX.
2471 (tex-font-lock-syntactic-face-function state)
2472 font-lock-doc-face))
2473
2474(defvar doctex-font-lock-syntactic-keywords
2475 (append
2476 tex-font-lock-syntactic-keywords
2477 ;; For DocTeX comment-in-doc.
2478 `(("\\(\\^\\)\\^A" (1 (doctex-font-lock-^^A))))))
2479
2480(defvar doctex-font-lock-keywords
2481 (append tex-font-lock-keywords
2482 '(("^%<[^>]*>" (0 font-lock-preprocessor-face t)))))
2483
2484;;;###autoload
2485(define-derived-mode doctex-mode latex-mode "DocTeX"
2486 "Major mode to edit DocTeX files."
2487 (setq font-lock-defaults
2488 (cons (append (car font-lock-defaults) '(doctex-font-lock-keywords))
2489 (mapcar
2490 (lambda (x)
2491 (case (car-safe x)
2492 (font-lock-syntactic-keywords
2493 (cons (car x) 'doctex-font-lock-syntactic-keywords))
2494 (font-lock-syntactic-face-function
2495 (cons (car x) 'doctex-font-lock-syntactic-face-function))
2496 (t x)))
2497 (cdr font-lock-defaults)))))
528415e7
RS
2498
2499(run-hooks 'tex-mode-load-hook)
869bff31 2500
49116ac0
JB
2501(provide 'tex-mode)
2502
dd166d5f 2503;; arch-tag: c0a680b1-63aa-4547-84b9-4193c29c0080
d501f516 2504;;; tex-mode.el ends here