;;; 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
;; 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)
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"
"\\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"
(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.
(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 $$
(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
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))
;; 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.")
(,(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)
(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)
(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)
(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}")
(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
'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)
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))
(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 ()
(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)))))
(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))))))))
(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)
(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)
(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
" " (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.??")
("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
(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)))
(when (file-newer-than-file-p f file)
(setq uptodate nil)))))
uptodate)))
-
+
(autoload 'format-spec "format-spec")
(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
(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))
(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)))))
(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
(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)
(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 ()
(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)))
(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.
(+ 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