;;; tex-mode.el --- TeX, LaTeX, and SliTeX mode commands -*- coding: utf-8 -*-
-;; Copyright (C) 1985,86,89,92,94,95,96,97,98,1999,2002,2003
-;; Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1989, 1992, 1994, 1995, 1996, 1997, 1998, 1999,
+;; 2002, 2003, 2004 Free Software Foundation, Inc.
;; Maintainer: FSF
;; Keywords: 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"
:group 'tex-view)
;;;###autoload
-(defcustom tex-dvi-view-command '(if (eq window-system 'x) "xdvi" "dvi2tty * | cat -s")
+(defcustom tex-dvi-view-command
+ '(cond
+ ((eq window-system 'x) "xdvi")
+ ((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.
If this string contains an asterisk (`*'), that is replaced by the file name;
'("input" "include" "includeonly" "bibliography"
"epsfig" "psfig" "epsf" "nofiles" "usepackage"
"documentstyle" "documentclass" "verbatiminput"
- "includegraphics" "includegraphics*")
+ "includegraphics" "includegraphics*"
+ "url" "nolinkurl")
t))
;; Miscellany.
(slash "\\\\")
;; (arg "\\(?:{\\(\\(?:[^{}\\]+\\|\\\\.\\|{[^}]*}\\)+\\)\\|\\\\[a-z*]+\\)"))
(arg "{\\(\\(?:[^{}\\]+\\|\\\\.\\|{[^}]*}\\)+\\)"))
(list
+ ;; font-lock-syntactic-keywords causes the \ of \end{verbatim} to be
+ ;; 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 $$
;; We only mark the match between $$ and $$ because the $$ delimiters
;; themselves have already been marked (along with $..$) by syntactic
1 font-lock-function-name-face))))
"Subdued expressions to highlight in TeX modes.")
+(defun tex-font-lock-append-prop (prop)
+ (unless (memq (get-text-property (match-end 1) 'face)
+ '(font-lock-comment-face tex-verbatim-face))
+ prop))
+
(defconst tex-font-lock-keywords-2
(append tex-font-lock-keywords-1
(eval-when-compile
;;
;; Font environments. It seems a bit dubious to use `bold' etc. faces
;; since we might not be able to display those fonts.
- (list (concat slash bold " *" arg) 2 '(quote bold) 'append)
- (list (concat slash italic " *" arg) 2 '(quote italic) 'append)
+ (list (concat slash bold " *" arg) 2
+ '(tex-font-lock-append-prop 'bold) 'append)
+ (list (concat slash italic " *" arg) 2
+ '(tex-font-lock-append-prop 'italic) 'append)
;; (list (concat slash type arg) 2 '(quote bold-italic) 'append)
;;
;; Old-style bf/em/it/sl. Stop at `\\' and un-escaped `&', for tables.
(list (concat "\\\\\\(em\\|it\\|sl\\)\\>" args)
- 2 '(quote italic) 'append)
+ 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) 1 '(quote bold) 'append)))))
+ (list (concat "\\\\\\(bf\\)\\>" args)
+ 2 '(tex-font-lock-append-prop 'bold) 'append)))))
"Gaudy expressions to highlight in TeX modes.")
(defun tex-font-lock-suscript (pos)
(defvar tex-font-lock-syntactic-keywords
(let ((verbs (regexp-opt tex-verbatim-environments t)))
`((,(concat "^\\\\begin *{" verbs "}.*\\(\n\\)") 2 "|")
- (,(concat "^\\\\end *{" verbs "}\\(.?\\)") 2
- (unless (<= (match-beginning 0) (point-min))
- (put-text-property (1- (match-beginning 0)) (match-beginning 0)
- 'syntax-table (string-to-syntax "|"))
- "<"))
+ ;; Technically, we'd like to put the "|" property on the \n preceding
+ ;; the \end, but this would have 2 disadvantages:
+ ;; 1 - it's wrong if the verbatim env is empty (the same \n is used to
+ ;; start and end the fenced-string).
+ ;; 2 - font-lock considers the preceding \n as being part of the
+ ;; preceding line, so things gets screwed every time the previous
+ ;; line is re-font-locked on its own.
+ ;; There's a hack in tex-font-lock-keywords-1 to remove the verbatim
+ ;; face from the \ but C-M-f still jumps to the wrong spot :-( --Stef
+ (,(concat "^\\(\\\\\\)end *{" verbs "}\\(.?\\)") (1 "|") (3 "<"))
;; ("^\\(\\\\\\)begin *{comment}" 1 "< b")
;; ("^\\\\end *{comment}.*\\(\n\\)" 1 "> b")
("\\\\verb\\**\\([^a-z@*]\\)" 1 "\""))))
"part" "chapter" "newcommand"
"renewcommand") 'words)
"\\|NeedsTeXFormat{LaTeX")))
- (if (looking-at
- "document\\(style\\|class\\)\\(\\[.*\\]\\)?{slides}")
+ (if (and (looking-at
+ "document\\(style\\|class\\)\\(\\[.*\\]\\)?{slides}")
+ ;; SliTeX is almost never used any more nowadays.
+ (tex-executable-exists-p slitex-run-command))
'slitex-mode
'latex-mode)
'plain-tex-mode))))
'occur-target tem)))))
(goto-char prev-end))))
(with-current-buffer standard-output
- (if (eq num-matches 0)
- (insert "None!\n"))
- (if (interactive-p)
- (message "%d mismatches found" num-matches))))))
+ (let ((no-matches (zerop num-matches)))
+ (if no-matches
+ (insert "None!\n"))
+ (if (interactive-p)
+ (message (cond (no-matches "No mismatches found")
+ ((= num-matches 1) "1 mismatch found")
+ (t "%d mismatches found"))
+ num-matches)))))))
(defun tex-validate-region (start end)
"Check for mismatched braces or $'s in region.
(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)))))
(defvar latex-block-default "enumerate")
(defvar latex-block-args-alist
- '(("array" nil ?\{ (skeleton-read "[options]: ") ?\})
- ("tabular" nil ?\{ (skeleton-read "[options]: ") ?\}))
+ '(("array" nil ?\{ (skeleton-read "Format: ") ?\})
+ ("tabular" nil ?\{ (skeleton-read "Format: ") ?\})
+ ("minipage" nil ?\{ (skeleton-read "Size: ") ?\})
+ ("picture" nil ?\( (skeleton-read "SizeX,SizeY: ") ?\))
+ ;; FIXME: This is right for Prosper, but not for seminar.
+ ;; ("slide" nil ?\{ (skeleton-read "Title: ") ?\})
+ )
"Skeleton element to use for arguments to particular environments.
Every element of the list has the form (NAME . SKEL-ELEM) where NAME is
the name of the environment and SKEL-ELEM is an element to use in
(defvar latex-block-body-alist
'(("enumerate" nil '(latex-insert-item) > _)
("itemize" nil '(latex-insert-item) > _)
- ("table" nil "\\caption{" > - "}" > \n _)
- ("figure" nil > _ \n "\\caption{" > _ "}" >))
+ ("table" nil "\\caption{" > (skeleton-read "Caption: ") "}" > \n
+ '(if (and (boundp 'reftex-mode) reftex-mode) (reftex-label "table"))
+ \n _)
+ ("figure" nil > _ \n "\\caption{" > (skeleton-read "Caption: ") "}" > \n
+ '(if (and (boundp 'reftex-mode) reftex-mode) (reftex-label "table"))))
"Skeleton element to use for the body of particular environments.
Every element of the list has the form (NAME . SKEL-ELEM) where NAME is
the name of the environment and SKEL-ELEM is an element to use in
choice)
\n "\\begin{" str "}"
(cdr (assoc str latex-block-args-alist))
- > \n (or (cdr (assoc str latex-block-body-alist)) '(nil > _)) \n
+ > \n (or (cdr (assoc str latex-block-body-alist)) '(nil > _))
+ (unless (bolp) '\n)
"\\end{" str "}" > \n)
(define-skeleton latex-insert-item
(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))))))))
;; The utility functions:
(define-derived-mode tex-shell shell-mode "TeX-Shell"
+ (set (make-local-variable 'compilation-parse-errors-function)
+ 'tex-compilation-parse-errors)
(compilation-shell-minor-mode t))
;;;###autoload
(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)
- (process-kill-without-query proc)
+ (set-process-query-on-exit-flag proc nil)
(tex-shell)
(while (zerop (buffer-size))
(sleep-for 1)))))
("texindex %r.??")
("dvipdfm %r" "%r.dvi" "%r.pdf")
("dvipdf %r" "%r.dvi" "%r.pdf")
- ("dvips %r" "%r.dvi" "%r.ps")
+ ("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")
(let* ((file (or tex-main-file
;; Compatibility with AUCTeX.
(with-no-warnings
- (when (and (boundp 'TeX-master) (stringp TeX-master))
- (make-local-variable 'tex-main-file)
- (setq tex-main-file TeX-master)))
+ (when (boundp 'TeX-master)
+ (cond ((stringp TeX-master)
+ (make-local-variable 'tex-main-file)
+ (setq tex-main-file TeX-master))
+ ((and (eq TeX-master t) buffer-file-name)
+ (file-relative-name buffer-file-name)))))
;; Try to guess the main file.
(if (not buffer-file-name)
(error "Buffer is not associated with any file")
(when (file-newer-than-file-p f file)
(setq uptodate nil)))))
uptodate)))
-
+
(autoload 'format-spec "format-spec")
(not (tex-uptodate-p (format-spec out fspec)))))))
(defun tex-compile-default (fspec)
- "Guess a default command given the format-spec FSPEC."
+ "Guess a default command given the `format-spec' FSPEC."
;; TODO: Learn to do latex+dvips!
(let ((cmds nil)
(unchanged-in nil))
(if (tex-command-active-p cmd fspec)
(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))))
;; 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
(let (shell-dirtrack-verbose)
(tex-send-command tex-shell-cd-command dir)))
(with-current-buffer (process-buffer (tex-send-command cmd))
- (make-local-variable 'compilation-parse-errors-function)
- (setq compilation-parse-errors-function 'tex-compilation-parse-errors)
(setq compilation-last-buffer (current-buffer))
(compilation-forget-errors)
;; Don't parse previous compilations.
for the error messages."
(require 'thingatpt)
(setq compilation-error-list nil)
- (message "Parsing error messages...")
(let ((default-directory ; Perhaps dir has changed meanwhile.
(file-name-directory (buffer-file-name tex-last-buffer-texed)))
found-desired (num-errors-found 0)
end-of-error (match-end 0)))
(re-search-forward
"^l\\.\\([0-9]+\\) \\(\\.\\.\\.\\)?\\(.*\\)$" nil 'move))
- (let* ((this-error (set-marker (make-marker) begin-of-error))
- (linenum (string-to-int (match-string 1)))
+ (let* ((this-error (copy-marker begin-of-error))
+ (linenum (string-to-number (match-string 1)))
(error-text (regexp-quote (match-string 3)))
(filename
(save-excursion
(or (null last-filename)
(not (string-equal last-filename filename))))
(error-location
- (save-excursion
- (if (equal filename (concat tex-zap-file ".tex"))
- (set-buffer tex-last-buffer-texed)
- (set-buffer (find-file-noselect filename)))
- (if new-file
- (progn (goto-line linenum) (setq last-position nil))
- (goto-char last-position)
- (forward-line (- linenum last-linenum)))
- ;; first try a forward search for the error text,
- ;; then a backward search limited by the last error.
- (let ((starting-point (point)))
- (or (re-search-forward error-text nil t)
- (re-search-backward error-text last-position t)
- (goto-char starting-point)))
- (point-marker))))
+ (with-current-buffer
+ (if (equal filename (concat tex-zap-file ".tex"))
+ tex-last-buffer-texed
+ (find-file-noselect filename))
+ (save-excursion
+ (if new-file
+ (progn (goto-line linenum) (setq last-position nil))
+ (goto-char last-position)
+ (forward-line (- linenum last-linenum)))
+ ;; first try a forward search for the error text,
+ ;; then a backward search limited by the last error.
+ (let ((starting-point (point)))
+ (or (re-search-forward error-text nil t)
+ (re-search-backward error-text last-position t)
+ (goto-char starting-point)))
+ (point-marker)))))
(goto-char this-error)
(if (and compilation-error-list
(or (and find-at-least
compilation-error-list))
(goto-char end-of-error)))))
(set-marker compilation-parsing-end (point))
- (setq compilation-error-list (nreverse compilation-error-list))
- (message "Parsing error messages...done"))
+ (setq compilation-error-list (nreverse compilation-error-list)))
\f
;;; The commands:
(defvar tex-indent-basic 2)
(defvar tex-indent-item tex-indent-basic)
(defvar tex-indent-item-re "\\\\\\(bib\\)?item\\>")
+(defvar latex-noindent-environments '("document"))
(defvar tex-latex-indent-syntax-table
(let ((st (make-syntax-table tex-mode-syntax-table)))
(latex-find-indent 'virtual))))
;; Default (maybe an argument)
(let ((pos (point))
- (char (char-after))
;; Outdent \item if necessary.
(indent (if (looking-at tex-indent-item-re) (- tex-indent-item) 0))
up-list-pos)
;; Have to indent relative to the open-paren.
(goto-char up-list-pos)
(if (and (not tex-indent-allhanging)
+ (save-excursion
+ ;; Make sure we're an argument to a macro and
+ ;; that the macro is at the beginning of a line.
+ (condition-case nil
+ (progn
+ (while (eq (char-syntax (char-after)) ?\()
+ (forward-sexp -1))
+ (and (eq (char-syntax (char-after)) ?/)
+ (progn (skip-chars-backward " \t&")
+ (bolp))))
+ (scan-error nil)))
(> pos (progn (latex-down-list)
(forward-comment (point-max))
(point))))
(current-column)
;; We're the first element after a hanging brace.
(goto-char up-list-pos)
- (+ indent tex-indent-basic (latex-find-indent 'virtual))))
+ (+ (if (and (looking-at "\\\\begin *{\\([^\n}]+\\)")
+ (member (match-string 1)
+ latex-noindent-environments))
+ 0 tex-indent-basic)
+ indent (latex-find-indent 'virtual))))
;; We're now at the "beginning" of a line.
((not (and (not virtual) (eq (char-after) ?\\)))
;; Nothing particular here: just keep the same indentation.
(+ indent (current-column)))
;; We're now looking at a macro call.
- ((looking-at tex-indent-item-re)
- ;; Indenting relative to an item, have to re-add the outdenting.
+ ((looking-at tex-indent-item-re)
+ ;; Indenting relative to an item, have to re-add the outdenting.
(+ indent (current-column) tex-indent-item))
(t
(let ((col (current-column)))
- (if (or (null char) (not (eq (char-syntax char) ?\()))
+ (if (or (not (eq (char-syntax (or (char-after pos) ?\ )) ?\())
+ ;; 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
;; a risk that this is really not an argument to the
;; macro at all.
(provide 'tex-mode)
-;;; arch-tag: c0a680b1-63aa-4547-84b9-4193c29c0080
+;; arch-tag: c0a680b1-63aa-4547-84b9-4193c29c0080
;;; tex-mode.el ends here