]> code.delx.au - gnu-emacs/blobdiff - lisp/textmodes/tex-mode.el
Update years in copyright notice; nfc.
[gnu-emacs] / lisp / textmodes / tex-mode.el
index 91b3d2afdfd6f20e60bb8885483b283efa6c1120..97153e31a25dc3081d45ef23a36f671700f9be32 100644 (file)
@@ -1,7 +1,7 @@
 ;;; tex-mode.el --- TeX, LaTeX, and SliTeX mode commands -*- coding: utf-8 -*-
 
 ;; Copyright (C) 1985, 1986, 1989, 1992, 1994, 1995, 1996, 1997, 1998, 1999,
-;;   2002, 2003, 2004  Free Software Foundation, Inc.
+;;   2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: tex
@@ -23,8 +23,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
   (require 'cl)
   (require 'skeleton))
 
+(defvar font-lock-comment-face)
+(defvar font-lock-doc-face)
+
 (require 'shell)
 (require 'compile)
 
 (defgroup tex-file nil
-  "TeX files and directories"
+  "TeX files and directories."
   :prefix "tex-"
   :group 'tex)
 
 (defgroup tex-run nil
-  "Running external commands from TeX mode"
+  "Running external commands from TeX mode."
   :prefix "tex-"
   :group 'tex)
 
 (defgroup tex-view nil
-  "Viewing and printing TeX files"
+  "Viewing and printing TeX files."
   :prefix "tex-"
   :group 'tex)
 
@@ -127,7 +130,7 @@ and the input file name, with no separating space and are not shell-quoted.
 If nil, TeX runs with no options.  See the documentation of `tex-command'."
   :type 'string
   :group 'tex-run
-  :version "21.4")
+  :version "22.1")
 
 ;;;###autoload
 (defcustom tex-start-commands "\\nonstopmode\\input"
@@ -139,7 +142,7 @@ If nil, no commands are used.  See the documentation of `tex-command'."
                       "\\nonstopmode\\input")
                (string :tag "String at your choice"))
   :group 'tex-run
-  :version "21.4")
+  :version "22.1")
 
 (defvar latex-standard-block-names
   '("abstract"         "array"         "center"        "description"
@@ -199,7 +202,7 @@ use."
 (defcustom tex-dvi-view-command
   '(cond
     ((eq window-system 'x) "xdvi")
-    ((eq window-system 'w32) "yap") 
+    ((eq window-system 'w32) "yap")
     (t "dvi2tty * | cat -s"))
   "*Command used by \\[tex-view] to display a `.dvi' file.
 If it is a string, that specifies the command directly.
@@ -469,7 +472,7 @@ An alternative value is \" . \", if you use a font with a narrow period."
           (arg "{\\(\\(?:[^{}\\]+\\|\\\\.\\|{[^}]*}\\)+\\)"))
       (list
        ;; font-lock-syntactic-keywords causes the \ of \end{verbatim} to be
-       ;; highlighted as tex-verbatim-face.  Let's undo that.
+       ;; highlighted as tex-verbatim face.  Let's undo that.
        ;; This is ugly and brittle :-(  --Stef
        '("^\\(\\\\\\)end" (1 (get-text-property (match-end 1) 'face) t))
        ;; display $$ math $$
@@ -506,7 +509,7 @@ An alternative value is \" . \", if you use a font with a narrow period."
 
 (defun tex-font-lock-append-prop (prop)
   (unless (memq (get-text-property (match-end 1) 'face)
-               '(font-lock-comment-face tex-verbatim-face))
+               '(font-lock-comment-face tex-verbatim))
     prop))
 
 (defconst tex-font-lock-keywords-2
@@ -573,14 +576,14 @@ An alternative value is \" . \", if you use a font with a narrow period."
              2 '(tex-font-lock-append-prop 'italic) 'append)
        ;; This is separate from the previous one because of cases like
        ;; {\em foo {\bf bar} bla} where both match.
-       (list (concat "\\\\\\(bf\\)\\>" args)
-             2 '(tex-font-lock-append-prop 'bold) 'append)))))
+       (list (concat "\\\\\\(bf\\(series\\)?\\)\\>" args)
+             3 '(tex-font-lock-append-prop 'bold) 'append)))))
    "Gaudy expressions to highlight in TeX modes.")
 
 (defun tex-font-lock-suscript (pos)
   (unless (or (memq (get-text-property pos 'face)
                    '(font-lock-constant-face font-lock-builtin-face
-                     font-lock-comment-face tex-verbatim-face))
+                     font-lock-comment-face tex-verbatim))
              ;; Check for backslash quoting
              (let ((odd nil)
                    (pos pos))
@@ -602,7 +605,7 @@ An alternative value is \" . \", if you use a font with a narrow period."
           ;; degenerate to nasty complexity (because we try to match the
           ;; closing brace, which forces trying all matching combinations).
           (arg "{\\(?:[^{}\\]\\|\\\\.\\|{[^}]*}\\)*"))
-       `((,(concat "[_^] *\\([^\n\\{}]\\|" slash general "\\|" arg "}\\)")
+       `((,(concat "[_^] *\\([^\n\\{}#]\\|" slash general "\\|#[0-9]\\|" arg "}\\)")
          (1 (tex-font-lock-suscript (match-beginning 0))
             append))))))
   "Experimental expressions to highlight in TeX modes.")
@@ -628,7 +631,10 @@ An alternative value is \" . \", if you use a font with a narrow period."
       (,(concat "^\\(\\\\\\)end *{" verbs "}\\(.?\\)") (1 "|") (3 "<"))
       ;; ("^\\(\\\\\\)begin *{comment}" 1 "< b")
       ;; ("^\\\\end *{comment}.*\\(\n\\)" 1 "> b")
-      ("\\\\verb\\**\\([^a-z@*]\\)" 1 "\""))))
+      ("\\\\verb\\**\\([^a-z@*]\\)"
+       ;; Do it last, because it uses syntax-ppss which needs the
+       ;; syntax-table properties of previous entries.
+       1 (tex-font-lock-verb (match-end 1))))))
 
 (defun tex-font-lock-unfontify-region (beg end)
   (font-lock-default-unfontify-region beg end)
@@ -643,20 +649,54 @@ An alternative value is \" . \", if you use a font with a narrow period."
 
 (defface superscript
   '((t :height 0.8)) ;; :raise 0.3
-  "Face used for superscripts.")
+  "Face used for superscripts."
+  :group 'tex)
 (defface subscript
   '((t :height 0.8)) ;; :raise -0.3
-  "Face used for subscripts.")
+  "Face used for subscripts."
+  :group 'tex)
 
-(defface tex-math-face
+(defface tex-math
   '((t :inherit font-lock-string-face))
-  "Face used to highlight TeX math expressions.")
-(defvar tex-math-face 'tex-math-face)
-(defface tex-verbatim-face
+  "Face used to highlight TeX math expressions."
+  :group 'tex)
+;; backward-compatibility alias
+(put 'tex-math-face 'face-alias 'tex-math)
+(defvar tex-math-face 'tex-math)
+
+(defface tex-verbatim
   ;; '((t :inherit font-lock-string-face))
   '((t :family "courier"))
-  "Face used to highlight TeX verbatim environments.")
-(defvar tex-verbatim-face 'tex-verbatim-face)
+  "Face used to highlight TeX verbatim environments."
+  :group 'tex)
+;; backward-compatibility alias
+(put 'tex-verbatim-face 'face-alias 'tex-verbatim)
+(defvar tex-verbatim-face 'tex-verbatim)
+
+(defun tex-font-lock-verb (end)
+  "Place syntax-table properties on the \verb construct.
+END is the position of the first delimiter after \verb."
+  (unless (nth 8 (syntax-ppss end))
+    ;; Do nothing if the \verb construct is itself inside a comment or
+    ;; verbatim env.
+    (save-excursion
+      ;; Let's find the end and mark it.
+      ;; We used to do it inside tex-font-lock-syntactic-face-function, but
+      ;; this leads to funny effects when jumping to the end of the buffer,
+      ;; because font-lock applies font-lock-syntactic-keywords to the whole
+      ;; preceding text but font-lock-syntactic-face-function only to the
+      ;; actually displayed text.
+      (goto-char end)
+      (let ((char (char-before)))
+        (skip-chars-forward (string ?^ char)) ;; Use `end' ?
+        (when (eq (char-syntax (preceding-char)) ?/)
+          (put-text-property (1- (point)) (point) 'syntax-table '(1)))
+        (unless (eobp)
+          (put-text-property (point) (1+ (point)) 'syntax-table '(7))
+          ;; Cause the rest of the buffer to be re-fontified.
+          ;; (remove-text-properties (1+ (point)) (point-max) '(fontified))
+          )))
+    "\""))
 
 ;; Use string syntax but math face for $...$.
 (defun tex-font-lock-syntactic-face-function (state)
@@ -664,16 +704,7 @@ An alternative value is \" . \", if you use a font with a narrow period."
     (cond
      ((not char) font-lock-comment-face)
      ((eq char ?$) tex-math-face)
-     (t
-      (when (char-valid-p char)
-       ;; This is a \verb?...? construct.  Let's find the end and mark it.
-       (save-excursion
-         (skip-chars-forward (string ?^ char)) ;; Use `end' ?
-         (when (eq (char-syntax (preceding-char)) ?/)
-           (put-text-property (1- (point)) (point) 'syntax-table '(1)))
-         (unless (eobp)
-           (put-text-property (point) (1+ (point)) 'syntax-table '(7)))))
-      tex-verbatim-face))))
+     (t tex-verbatim-face))))
 
 \f
 (defun tex-define-common-keys (keymap)
@@ -791,7 +822,7 @@ Inherits `shell-mode-map' with a few additions.")
                      (regexp-opt '("documentstyle" "documentclass"
                                    "begin" "subsection" "section"
                                    "part" "chapter" "newcommand"
-                                   "renewcommand") 'words)
+                                   "renewcommand" "RequirePackage") 'words)
                      "\\|NeedsTeXFormat{LaTeX")))
                  (if (and (looking-at
                            "document\\(style\\|class\\)\\(\\[.*\\]\\)?{slides}")
@@ -828,6 +859,14 @@ says which mode to use."
       (tex-mode-internal)
     (tex-guess-mode)))
 
+;; The following three autoloaded aliases appear to conflict with
+;; AUCTeX.  However, even though AUCTeX uses the mixed case variants
+;; for all mode relevant variables and hooks, the invocation function
+;; and setting of `major-mode' themselves need to be lowercase for
+;; AUCTeX to provide a fully functional user-level replacement.  So
+;; these aliases should remain as they are, in particular since AUCTeX
+;; users are likely to use them.
+
 ;;;###autoload
 (defalias 'TeX-mode 'tex-mode)
 ;;;###autoload
@@ -1027,10 +1066,8 @@ Entering SliTeX mode runs the hook `text-mode-hook', then the hook
        'tex-categorize-whitespace)
   (set (make-local-variable 'facemenu-add-face-function)
        (lambda (face end)
-        (let ((face-text (cdr (assq face tex-face-alist))))
-          (if face-text
-              face-text
-            (error "Face %s not configured for %s mode" face mode-name)))))
+        (or (cdr (assq face tex-face-alist))
+            (error "Face %s not configured for %s mode" face mode-name))))
   (set (make-local-variable 'facemenu-end-add-face) "}")
   (set (make-local-variable 'facemenu-remove-face-function) t)
   (set (make-local-variable 'font-lock-defaults)
@@ -1091,7 +1128,7 @@ Inserts the value of `tex-open-quote' (normally ``) or `tex-close-quote'
 inserts \" characters."
   (interactive "*P")
   (if (or arg (memq (char-syntax (preceding-char)) '(?/ ?\\))
-         (eq (get-text-property (point) 'face) 'tex-verbatim-face)
+         (eq (get-text-property (point) 'face) 'tex-verbatim)
          (save-excursion
            (backward-char (length tex-open-quote))
            (when (or (looking-at (regexp-quote tex-open-quote))
@@ -1099,7 +1136,7 @@ inserts \" characters."
              (delete-char (length tex-open-quote))
              t)))
       (self-insert-command (prefix-numeric-value arg))
-    (insert (if (memq (char-syntax (preceding-char)) '(?\( ?> ?\ ))
+    (insert (if (memq (char-syntax (preceding-char)) '(?\( ?> ?\s))
                tex-open-quote tex-close-quote))))
 
 (defun tex-validate-buffer ()
@@ -1190,14 +1227,14 @@ area if a mismatch is found."
              (forward-sexp 1))
            ;; Now check that like matches like.
            (goto-char start)
-           (while (progn (skip-syntax-forward "^(")
-                         (not (eobp)))
-             (let ((match (matching-paren (following-char))))
-               (save-excursion
+           (while (re-search-forward "\\s(" nil t)
+             (save-excursion
+               (let ((pos (match-beginning 0)))
+                 (goto-char pos)
                  (forward-sexp 1)
-                 (or (= (preceding-char) match)
-                     (error "Mismatched parentheses"))))
-             (forward-char 1)))
+                 (or (eq (preceding-char) (cdr (syntax-after pos)))
+                     (eq (char-after pos) (cdr (syntax-after (1- (point)))))
+                     (error "Mismatched parentheses"))))))
        (error
         (skip-syntax-forward " .>")
         (setq failure-point (point)))))
@@ -1351,7 +1388,9 @@ Mark is left at original location."
       (when (eq (char-after) ?{)
        (let ((newpos (point)))
          (when (ignore-errors (backward-sexp 1) t)
-           (if (looking-at "\\\\end\\>")
+           (if (or (looking-at "\\\\end\\>")
+                   ;; In case the \\ ends a verbatim section.
+                   (and (looking-at "end\\>") (eq (char-before) ?\\)))
                (tex-last-unended-begin)
              (goto-char newpos))))))))
 
@@ -1493,7 +1532,9 @@ Mark is left at original location."
       (make-comint
        "tex-shell"
        (or tex-shell-file-name (getenv "ESHELL") shell-file-name)
-       nil)
+       nil
+       ;; Specify an interactive shell, to make sure it prompts.
+       "-i")
     (let ((proc (get-process "tex-shell")))
       (set-process-sentinel proc 'tex-shell-sentinel)
       (set-process-query-on-exit-flag proc nil)
@@ -1558,11 +1599,14 @@ Return the process in which TeX is running."
            (star (string-match "\\*" cmd))
           (string
            (concat
-            (if file
-                (if star (concat (substring cmd 0 star)
-                                 file (substring cmd (1+ star)))
-                  (concat cmd " " file))
-              cmd)
+            (if (null file)
+                cmd
+               (if (file-name-absolute-p file)
+                   (setq file (convert-standard-filename file)))
+              (if star (concat (substring cmd 0 star)
+                                (shell-quote-argument file)
+                                (substring cmd (1+ star)))
+                 (concat cmd " " (shell-quote-argument file))))
             (if background "&" ""))))
       ;; Switch to buffer before checking for subproc output in it.
       (set-buffer buf)
@@ -1612,7 +1656,8 @@ If NOT-ALL is non-nil, save the `.dvi' file."
 
 (defcustom tex-use-reftex t
   "If non-nil, use RefTeX's list of files to determine what command to use."
-  :type 'boolean)
+  :type 'boolean
+  :group 'tex)
 
 (defvar tex-compile-commands
   '(((concat "pdf" tex-command
@@ -1623,9 +1668,12 @@ If NOT-ALL is non-nil, save the `.dvi' file."
             " " (if (< 0 (length tex-start-commands))
                     (shell-quote-argument tex-start-commands)) " %f")
      t "%r.dvi")
-    ("yap %r &" "%r.dvi")
     ("xdvi %r &" "%r.dvi")
+    ("xpdf %r.pdf &" "%r.pdf")
+    ("gv %r.ps &" "%r.ps")
+    ("yap %r &" "%r.dvi")
     ("advi %r &" "%r.dvi")
+    ("gv %r.pdf &" "%r.pdf")
     ("bibtex %r" "%r.aux" "%r.bbl")
     ("makeindex %r" "%r.idx" "%r.ind")
     ("texindex %r.??")
@@ -1633,9 +1681,6 @@ If NOT-ALL is non-nil, save the `.dvi' file."
     ("dvipdf %r" "%r.dvi" "%r.pdf")
     ("dvips -o %r.ps %r" "%r.dvi" "%r.ps")
     ("ps2pdf %r.ps" "%r.ps" "%r.pdf")
-    ("gv %r.ps &" "%r.ps")
-    ("gv %r.pdf &" "%r.pdf")
-    ("xpdf %r.pdf &" "%r.pdf")
     ("lpr %r.ps" "%r.ps"))
   "List of commands for `tex-compile'.
 Each element should be of the form (FORMAT IN OUT) where
@@ -1739,7 +1784,11 @@ FILE is typically the output DVI or PDF file."
         (save-excursion
           (goto-char (point-max))
           (and (re-search-backward
-                "(see the transcript file for additional information)" nil t)
+                 (concat
+                  "(see the transcript file for additional information)"
+                  "\\|^Output written on .*"
+                  (regexp-quote (file-name-nondirectory file))
+                  " (.*)\\.") nil t)
                (> (save-excursion
                     (or (re-search-backward "\\[[0-9]+\\]" nil t)
                         (point-min)))
@@ -1772,7 +1821,7 @@ FILE is typically the output DVI or PDF file."
           (when (file-newer-than-file-p f file)
             (setq uptodate nil)))))
      uptodate)))
-    
+
 
 (autoload 'format-spec "format-spec")
 
@@ -1814,8 +1863,7 @@ FILE is typically the output DVI or PDF file."
            (push cmd cmds)
          (push (nth 1 cmd) unchanged-in))))
     ;; If no command seems to be applicable, arbitrarily pick the first one.
-    (unless cmds
-      (setq cmds (list (car tex-compile-commands))))
+    (setq cmds (if cmds (nreverse cmds) (list (car tex-compile-commands))))
     ;; Remove those commands whose input was considered stable for
     ;; some other command (typically if (t . "%.pdf") is inactive
     ;; then we're using pdflatex and the fact that the dvi file
@@ -1825,7 +1873,7 @@ FILE is typically the output DVI or PDF file."
        (unless (member (nth 1 cmd) unchanged-in)
          (push cmd tmp)))
       ;; Only remove if there's something left.
-      (if tmp (setq cmds tmp)))
+      (if tmp (setq cmds (nreverse tmp))))
     ;; Remove commands whose input is not uptodate either.
     (let ((outs (delq nil (mapcar (lambda (x) (nth 2 x)) cmds)))
          (tmp nil))
@@ -1833,7 +1881,7 @@ FILE is typically the output DVI or PDF file."
        (unless (member (nth 1 cmd) outs)
          (push cmd tmp)))
       ;; Only remove if there's something left.
-      (if tmp (setq cmds tmp)))
+      (if tmp (setq cmds (nreverse tmp))))
     ;; Select which file we're going to operate on (the latest).
     (let ((latest (nth 1 (car cmds))))
       (dolist (cmd (prog1 (cdr cmds) (setq cmds (list (car cmds)))))
@@ -1884,8 +1932,8 @@ FILE is typically the output DVI or PDF file."
            (prog1 (file-name-directory (expand-file-name file))
              (setq file (file-name-nondirectory file))))
          (root (file-name-sans-extension file))
-         (fspec (list (cons ?r (comint-quote-filename root))
-                      (cons ?f (comint-quote-filename file))))
+         (fspec (list (cons ?r (shell-quote-argument root))
+                      (cons ?f (shell-quote-argument file))))
          (default (tex-compile-default fspec)))
      (list default-directory
           (completing-read
@@ -1906,14 +1954,14 @@ FILE is typically the output DVI or PDF file."
          (compile-command
           (if star
              (concat (substring command 0 star)
-                     (comint-quote-filename file)
+                     (shell-quote-argument file)
                      (substring command (1+ star)))
             (concat command " "
                    tex-start-options
                    (if (< 0 (length tex-start-commands))
                        (concat
                         (shell-quote-argument tex-start-commands) " "))
-                   (comint-quote-filename file)))))
+                   (shell-quote-argument file)))))
     (tex-send-tex-command compile-command dir)))
 
 (defun tex-send-tex-command (cmd &optional dir)
@@ -2216,8 +2264,7 @@ is provided, use the alternative command, `tex-alt-dvi-print-command'."
         (tex-start-shell))
       (tex-send-command
        (if alt tex-alt-dvi-print-command tex-dvi-print-command)
-       (shell-quote-argument
-       print-file-name-dvi)
+       print-file-name-dvi
        t))))
 
 (defun tex-alt-print ()
@@ -2235,6 +2282,9 @@ because there is no standard value that would generally work."
   (interactive)
   (or tex-dvi-view-command
       (error "You must set `tex-dvi-view-command'"))
+  ;; Restart the TeX shell if necessary.
+  (or (tex-shell-running)
+      (tex-start-shell))
   (let ((tex-dvi-print-command (eval tex-dvi-view-command)))
     (tex-print)))
 
@@ -2310,7 +2360,7 @@ Runs the shell command defined by `tex-show-queue-command'."
 
 (defun latex-indent (&optional arg)
   (if (and (eq (get-text-property (line-beginning-position) 'face)
-              tex-verbatim-face))
+              'tex-verbatim))
       'noindent
     (with-syntax-table tex-latex-indent-syntax-table
       ;; TODO: Rather than ignore $, we should try to be more clever about it.
@@ -2399,7 +2449,7 @@ There might be text before point."
         (+ indent (current-column) tex-indent-item))
        (t
         (let ((col (current-column)))
-          (if (or (not (eq (char-syntax (or (char-after pos) ?\ )) ?\())
+          (if (or (not (eq (char-syntax (or (char-after pos) ?\s)) ?\())
                   ;; Can't be an arg if there's an empty line inbetween.
                   (save-excursion (re-search-forward "^[ \t]*$" pos t)))
               ;; If the first char was not an open-paren, there's