;;; tex-mode.el --- TeX, LaTeX, and SliTeX mode commands -*- coding: utf-8 -*-
;; Copyright (C) 1985, 1986, 1989, 1992, 1994, 1995, 1996, 1997, 1998
-;; 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+;; 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
;; Free Software Foundation, Inc.
;; Maintainer: FSF
;; This file is part of GNU Emacs.
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; GNU General Public License for more details.
;; 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., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
:group 'tex-run)
;;;###autoload
-(defcustom tex-directory "."
+(defcustom tex-directory (purecopy ".")
"*Directory in which temporary files are written.
You can make this `/tmp' if your TEXINPUTS has no relative directories in it
and you don't try to apply \\[tex-region] or \\[tex-buffer] when there are
:group 'tex-file)
;;;###autoload
-(defcustom tex-run-command "tex"
+(defcustom tex-run-command (purecopy "tex")
"*Command used to run TeX subjob.
TeX Mode sets `tex-command' to this string.
See the documentation of that variable."
:group 'tex-run)
;;;###autoload
-(defcustom latex-run-command "latex"
+(defcustom latex-run-command (purecopy "latex")
"*Command used to run LaTeX subjob.
LaTeX Mode sets `tex-command' to this string.
See the documentation of that variable."
:group 'tex-run)
;;;###autoload
-(defcustom slitex-run-command "slitex"
+(defcustom slitex-run-command (purecopy "slitex")
"*Command used to run SliTeX subjob.
SliTeX Mode sets `tex-command' to this string.
See the documentation of that variable."
:group 'tex-run)
;;;###autoload
-(defcustom tex-start-options ""
+(defcustom tex-start-options (purecopy "")
"*TeX options to use when starting TeX.
These immediately precede the commands in `tex-start-commands'
and the input file name, with no separating space and are not shell-quoted.
:version "22.1")
;;;###autoload
-(defcustom tex-start-commands "\\nonstopmode\\input"
+(defcustom tex-start-commands (purecopy "\\nonstopmode\\input")
"*TeX commands to use when starting TeX.
They are shell-quoted and precede the input file name, with a separating space.
If nil, no commands are used. See the documentation of `tex-command'."
:group 'tex-run)
;;;###autoload
-(defcustom tex-bibtex-command "bibtex"
+(defcustom tex-bibtex-command (purecopy "bibtex")
"*Command used by `tex-bibtex-file' to gather bibliographic data.
If this string contains an asterisk (`*'), that is replaced by the file name;
otherwise, the file name, preceded by blank, is added at the end."
:group 'tex-run)
;;;###autoload
-(defcustom tex-dvi-print-command "lpr -d"
+(defcustom tex-dvi-print-command (purecopy "lpr -d")
"*Command used by \\[tex-print] to print a .dvi file.
If this string contains an asterisk (`*'), that is replaced by the file name;
otherwise, the file name, preceded by blank, is added at the end."
:group 'tex-view)
;;;###autoload
-(defcustom tex-alt-dvi-print-command "lpr -d"
+(defcustom tex-alt-dvi-print-command (purecopy "lpr -d")
"*Command used by \\[tex-print] with a prefix arg to print a .dvi file.
If this string contains an asterisk (`*'), that is replaced by the file name;
otherwise, the file name, preceded by blank, is added at the end.
;;;###autoload
(defcustom tex-dvi-view-command
- '(cond
- ((eq window-system 'x) "xdvi")
- ((eq window-system 'w32) "yap")
- (t "dvi2tty * | cat -s"))
+ `(cond
+ ((eq window-system 'x) ,(purecopy "xdvi"))
+ ((eq window-system 'w32) ,(purecopy "yap"))
+ (t ,(purecopy "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;
:group 'tex-view)
;;;###autoload
-(defcustom tex-show-queue-command "lpq"
+(defcustom tex-show-queue-command (purecopy "lpq")
"*Command used by \\[tex-show-print-queue] to show the print queue.
Should show the queue(s) that \\[tex-print] puts jobs on."
:type 'string
:group 'tex)
;;;###autoload
-(defcustom tex-open-quote "``"
+(defcustom tex-open-quote (purecopy "``")
"*String inserted by typing \\[tex-insert-quote] to open a quotation."
:type 'string
:options '("``" "\"<" "\"`" "<<" "«")
:group 'tex)
;;;###autoload
-(defcustom tex-close-quote "''"
+(defcustom tex-close-quote (purecopy "''")
"*String inserted by typing \\[tex-insert-quote] to close a quotation."
:type 'string
:options '("''" "\">" "\"'" ">>" "»")
(list "\\$\\$\\([^$]+\\)\\$\\$" 1 'tex-math-face)
;; Heading args.
(list (concat slash headings "\\*?" opt arg)
- ;; If ARG ends up matching too much (if the {} don't match, f.ex)
+ ;; If ARG ends up matching too much (if the {} don't match, e.g.)
;; jit-lock will do funny things: when updating the buffer
;; the re-highlighting is only done locally so it will just
;; match the local line, but defer-contextually will
'((t :inherit font-lock-string-face))
"Face used to highlight TeX math expressions."
:group 'tex)
-;; backward-compatibility alias
-(put 'tex-math-face 'face-alias 'tex-math)
+(define-obsolete-face-alias 'tex-math-face 'tex-math "22.1")
(defvar tex-math-face 'tex-math)
(defface tex-verbatim
'((t :family "courier"))
"Face used to highlight TeX verbatim environments."
:group 'tex)
-;; backward-compatibility alias
-(put 'tex-verbatim-face 'face-alias 'tex-verbatim)
+(define-obsolete-face-alias 'tex-verbatim-face 'tex-verbatim "22.1")
(defvar tex-verbatim-face 'tex-verbatim)
(defun tex-font-lock-verb (end)
,@tex-face-alist)
"Alist of face and LaTeX font name for facemenu.")
+(defun tex-facemenu-add-face-function (face end)
+ (or (cdr (assq face tex-face-alist))
+ (or (and (consp face)
+ (consp (car face))
+ (null (cdr face))
+ (eq major-mode 'latex-mode)
+ ;; This actually requires the `color' LaTeX package.
+ (cond ((eq (caar face) :foreground)
+ (format "{\\color{%s} " (cadr (car face))))
+ ((eq (caar face) :background)
+ (format "\\colorbox{%s}{" (cadr (car face))))))
+ (error "Face %s not configured for %s mode" face mode-name))))
+
;; This would be a lot simpler if we just used a regexp search,
;; but then it would be too slow.
(defun tex-guess-mode ()
;; and we need to define it a second time for `autoload' to get the
;; proper docstring.
(defalias 'tex-mode-internal (symbol-function 'tex-mode))
+
+;; Suppress the byte-compiler warning about multiple definitions.
+;; This is a) ugly, and b) cheating, but this was the last
+;; remaining warning from byte-compiling all of Emacs...
+(eval-when-compile
+ (setq byte-compile-function-environment
+ (delq (assq 'tex-mode byte-compile-function-environment)
+ byte-compile-function-environment)))
+
;;;###autoload
(defun tex-mode ()
"Major mode for editing files of input for TeX, LaTeX, or SliTeX.
"\\>\\|\\\\[a-z]*" (regexp-opt '("space" "skip" "page") t)
"\\>\\)"))
(setq paragraph-separate
- (concat "[\f%]\\|[ \t]*\\($\\|"
+ (concat "[\f]\\|[ \t]*\\($\\|"
"\\\\[][]\\|"
"\\\\" (regexp-opt (append
(mapcar 'car latex-section-alist)
(add-hook 'fill-nobreak-predicate 'latex-fill-nobreak-predicate nil t)
(set (make-local-variable 'indent-line-function) 'latex-indent)
(set (make-local-variable 'fill-indent-according-to-mode) t)
+ (add-hook 'completion-at-point-functions
+ 'latex-complete-data nil 'local)
(set (make-local-variable 'outline-regexp) latex-outline-regexp)
(set (make-local-variable 'outline-level) 'latex-outline-level)
(set (make-local-variable 'forward-sexp-function) 'latex-forward-sexp)
(set (make-local-variable 'compare-windows-whitespace)
'tex-categorize-whitespace)
(set (make-local-variable 'facemenu-add-face-function)
- (lambda (face end)
- (or (cdr (assq face tex-face-alist))
- (error "Face %s not configured for %s mode" face mode-name))))
+ 'tex-facemenu-add-face-function)
(set (make-local-variable 'facemenu-end-add-face) "}")
(set (make-local-variable 'facemenu-remove-face-function) t)
(set (make-local-variable 'font-lock-defaults)
(let ((no-matches (zerop num-matches)))
(if no-matches
(insert "None!\n"))
- (if (interactive-p)
+ (if (called-interactively-p 'interactive)
(message (cond (no-matches "No mismatches found")
((= num-matches 1) "1 mismatch found")
(t "%d mismatches found"))
\n "\\item " >)
\f
+;;;; LaTeX completion.
+
+(defvar latex-complete-bibtex-cache nil)
+
+(defun latex-string-prefix-p (str1 str2)
+ (eq t (compare-strings str1 nil nil str2 0 (length str1))))
+
+(defvar bibtex-reference-key)
+(declare-function reftex-get-bibfile-list "reftex-cite.el" ())
+
+(defun latex-complete-bibtex-keys ()
+ (when (bound-and-true-p reftex-mode)
+ (lambda (key pred action)
+ (let ((re (concat "^[ \t]*@\\([a-zA-Z]+\\)[ \t\n]*\\([{(][ \t\n]*\\)"
+ (regexp-quote key)))
+ (files (reftex-get-bibfile-list))
+ keys)
+ (if (and (eq (car latex-complete-bibtex-cache)
+ (reftex-get-bibfile-list))
+ (latex-string-prefix-p (nth 1 latex-complete-bibtex-cache)
+ key))
+ ;; Use the cache.
+ (setq keys (nth 2 latex-complete-bibtex-cache))
+ (dolist (file files)
+ (with-current-buffer (find-file-noselect file)
+ (goto-char (point-min))
+ (while (re-search-forward re nil t)
+ (goto-char (match-end 2))
+ (when (and (not (member-ignore-case (match-string 1)
+ '("c" "comment" "string")))
+ (looking-at bibtex-reference-key))
+ (push (match-string-no-properties 0) keys)))))
+ ;; Fill the cache.
+ (set (make-local-variable 'latex-complete-bibtex-cache)
+ (list files key keys)))
+ (complete-with-action action keys key pred)))))
+
+(defun latex-complete-envnames ()
+ (append latex-block-names latex-standard-block-names))
+
+(defun latex-complete-refkeys ()
+ (when (boundp 'reftex-docstruct-symbol)
+ (symbol-value reftex-docstruct-symbol)))
+
+(defvar latex-complete-alist
+ ;; TODO: Add \begin, \end, \ref, ...
+ '(("\\`\\\\\\(short\\)?cite\\'" . latex-complete-bibtex-keys)
+ ("\\`\\\\\\(begin\\|end\\)\\'" . latex-complete-envnames)
+ ("\\`\\\\[vf]?ref\\'" . latex-complete-refkeys)))
+
+(defun latex-complete-data ()
+ "Get completion-data at point."
+ (save-excursion
+ (let ((pt (point)))
+ (skip-chars-backward "^ {}\n\t\\\\")
+ (case (char-before)
+ ((nil ?\s ?\n ?\t ?\}) nil)
+ (?\\
+ ;; TODO: Complete commands.
+ nil)
+ (?\{
+ ;; Complete args to commands.
+ (let* ((cmd
+ (save-excursion
+ (forward-char -1)
+ (skip-chars-backward " \n")
+ (buffer-substring (point)
+ (progn
+ (skip-chars-backward "a-zA-Z@*")
+ (let ((n (skip-chars-backward "\\\\")))
+ (forward-char (* 2 (/ n 2))))
+ (point)))))
+ (start (point))
+ (_ (progn (goto-char pt) (skip-chars-backward "^," start)))
+ (comp-beg (point))
+ (_ (progn (goto-char pt) (skip-chars-forward "^, {}\n\t\\\\")))
+ (comp-end (point))
+ (table
+ (funcall
+ (let ((f (lambda () t)))
+ (dolist (comp latex-complete-alist)
+ (if (string-match (car comp) cmd)
+ (setq f (cdr comp))))
+ f))))
+ (if (eq table t)
+ ;; Unknown command.
+ nil
+ (list comp-beg comp-end table))))))))
+
;;;;
;;;; LaTeX syntax navigation
;;;;
(push-mark)
(goto-char spot)))
+(defvar latex-handle-escaped-parens t)
+
;; Don't think this one actually _needs_ (for the purposes of
;; tex-mode) to handle escaped parens.
+;; Does not handle escaped parens when latex-handle-escaped-parens is nil.
(defun latex-backward-sexp-1 ()
"Like (backward-sexp 1) but aware of multi-char elements and escaped parens."
(let ((pos (point))
(forward-sexp-function))
(backward-sexp 1)
- (cond ((looking-at "\\\\\\(begin\\>\\|[[({]\\)")
+ (cond ((looking-at
+ (if latex-handle-escaped-parens
+ "\\\\\\(begin\\>\\|[[({]\\)"
+ "\\\\begin\\>"))
(signal 'scan-error
(list "Containing expression ends prematurely"
(point) (prog1 (point) (goto-char pos)))))
- ((looking-at "\\\\\\([])}]\\)")
+ ((and latex-handle-escaped-parens
+ (looking-at "\\\\\\([])}]\\)"))
(tex-last-unended-eparen (match-string 1)))
((eq (char-after) ?{)
(let ((newpos (point)))
;; begin/end blocks.
;; Needs to handle escaped parens for tex-validate-*.
;; http://lists.gnu.org/archive/html/bug-gnu-emacs/2007-09/msg00038.html
+;; Does not handle escaped parens when latex-handle-escaped-parens is nil.
(defun latex-forward-sexp-1 ()
"Like (forward-sexp 1) but aware of multi-char elements and escaped parens."
(let ((pos (point))
(tex-next-unmatched-end))
;; A better way to handle this, \( .. \) etc, is probably to
;; temporarily change the syntax of the \ in \( to punctuation.
- ((looking-back "\\\\[])}]")
+ ((and latex-handle-escaped-parens
+ (looking-back "\\\\[])}]"))
(signal 'scan-error
(list "Containing expression ends prematurely"
(- (point) 2) (prog1 (point)
(goto-char pos)))))
- ((looking-back "\\\\\\([({[]\\)")
+ ((and latex-handle-escaped-parens
+ (looking-back "\\\\\\([({[]\\)"))
(tex-next-unmatched-eparen (match-string 1)))
(t (goto-char newpos))))))
(setq directory (file-name-as-directory (expand-file-name directory)))
(if (not (file-directory-p directory))
(error "%s is not a directory" directory)
- (save-excursion
- (set-buffer buffer)
+ (with-current-buffer buffer
(setq default-directory directory))))
(defvar tex-send-command-modified-tick 0)
(shell-quote-argument tex-start-commands)) " %f")
t "%r.dvi")
("xdvi %r &" "%r.dvi")
+ ("\\doc-view \"%r.pdf\"" "%r.pdf")
("xpdf %r.pdf &" "%r.pdf")
("gv %r.ps &" "%r.ps")
("yap %r &" "%r.dvi")
(save-excursion
(goto-char (point-max))
(and (re-search-backward
- (concat
- "(see the transcript file for additional information)"
- "\\|^Output written on .*"
- (regexp-quote (file-name-nondirectory file))
- " (.*)\\.") 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)
+ ;; Usually page numbers are output as [N], but
+ ;; I've already seen things like
+ ;; [1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}]
+ (or (re-search-backward "\\[[0-9]+\\({[^}]*}\\)?\\]"
+ nil t)
(point-min)))
(save-excursion
(or (re-search-backward "Rerun" nil t)
(defvar tex-executable-cache nil)
(defun tex-executable-exists-p (name)
"Like `executable-find' but with a cache."
- (let ((cache (assoc name tex-executable-cache)))
- (if cache (cdr cache)
- (let ((executable (executable-find name)))
- (push (cons name executable) tex-executable-cache)
- executable))))
+ (let ((f (and (string-match "^\\\\\\([^ \t\n]+\\)" name)
+ (intern-soft (concat "tex-cmd-" (match-string 1 name))))))
+ (if (fboundp f)
+ f
+ (let ((cache (assoc name tex-executable-cache)))
+ (if cache (cdr cache)
+ (let ((executable (executable-find name)))
+ (push (cons name executable) tex-executable-cache)
+ executable))))))
(defun tex-command-executable (cmd)
(let ((s (if (stringp cmd) cmd (eval (car cmd)))))
(when (and (eq in t) (stringp out))
(not (tex-uptodate-p (format-spec out fspec)))))))
+(defcustom tex-cmd-bibtex-args "--min-crossref=100"
+ "Extra args to pass to `bibtex' by default."
+ :type 'string
+ :version "23.1"
+ :group 'tex-run)
+
+(defun tex-format-cmd (format fspec)
+ "Like `format-spec' but adds user-specified args to the command.
+Only applies the FSPEC to the args part of FORMAT."
+ (if (not (string-match "\\([^ /\\]+\\) " format))
+ (format-spec format fspec)
+ (let* ((prefix (substring format 0 (match-beginning 0)))
+ (cmd (match-string 1 format))
+ (args (substring format (match-end 0)))
+ (sym (intern-soft (format "tex-cmd-%s-args" cmd)))
+ (extra-args (and sym (symbol-value sym))))
+ (concat prefix cmd
+ (if extra-args (concat " " extra-args))
+ " " (format-spec args fspec)))))
+
(defun tex-compile-default (fspec)
"Guess a default command given the `format-spec' FSPEC."
;; TODO: Learn to do latex+dvips!
;; The history command was already applied to the same file,
;; so just reuse it.
hist-cmd
- (if cmds (format-spec (caar cmds) fspec))))))
+ (if cmds (tex-format-cmd (caar cmds) fspec))))))
+
+(defun tex-cmd-doc-view (file)
+ (pop-to-buffer (find-file-noselect file)))
(defun tex-compile (dir cmd)
"Run a command CMD on current TeX buffer's file in DIR."
(completing-read
(format "Command [%s]: " (tex-summarize-command default))
(mapcar (lambda (x)
- (list (format-spec (eval (car x)) fspec)))
+ (list (tex-format-cmd (eval (car x)) fspec)))
tex-compile-commands)
nil nil nil 'tex-compile-history default))))
(save-some-buffers (not compilation-ask-about-save) nil)
- (if (tex-shell-running)
- (tex-kill-job)
- (tex-start-shell))
- (tex-send-tex-command cmd dir))
+ (let ((f (and (string-match "^\\\\\\([^ \t\n]+\\)" cmd)
+ (intern-soft (concat "tex-cmd-" (match-string 1 cmd))))))
+ (if (functionp f)
+ (condition-case nil
+ (let ((default-directory dir))
+ (apply f (split-string-and-unquote
+ (substring cmd (match-end 0)))))
+ (wrong-number-of-arguments
+ (error "Wrong number of arguments to %s"
+ (substring (symbol-name f) 8))))
+ (if (tex-shell-running)
+ (tex-kill-job)
+ (tex-start-shell))
+ (tex-send-tex-command cmd dir))))
(defun tex-start-tex (command file &optional dir)
"Start a TeX run, using COMMAND on FILE."
(let* ((this-error (copy-marker begin-of-error))
(linenum (string-to-number (match-string 1)))
(error-text (regexp-quote (match-string 3)))
+ try-filename
(filename
;; Prefer --file-liner-error filename if we have it.
(or errfilename
(with-syntax-table tex-error-parse-syntax-table
(backward-up-list 1)
(skip-syntax-forward "(_")
- (while (not (file-readable-p (thing-at-point 'filename)))
+ (while (not
+ (and (setq try-filename (thing-at-point
+ 'filename))
+ (not (string= "" try-filename))
+ (file-readable-p try-filename)))
(skip-syntax-backward "(_")
(backward-up-list 1)
(skip-syntax-forward "(_"))
(find-file-noselect filename))
(save-excursion
(if new-file
- (progn (goto-line linenum) (setq last-position nil))
+ (progn
+ (goto-char (point-min))
+ (forward-line (1- linenum))
+ (setq last-position nil))
(goto-char last-position)
(forward-line (- linenum last-linenum)))
;; first try a forward search for the error text,
(if (tex-shell-running)
(tex-kill-job)
(tex-start-shell))
- (let (shell-dirtrack-verbose
- (tex-out-file
- (tex-append (file-name-nondirectory (buffer-file-name)) ""))
- (file-dir (file-name-directory (buffer-file-name))))
+ (let* (shell-dirtrack-verbose
+ (source-file (tex-main-file))
+ (tex-out-file
+ (tex-append (file-name-nondirectory source-file) ""))
+ (file-dir (file-name-directory source-file)))
(tex-send-command tex-shell-cd-command file-dir)
(tex-send-command tex-bibtex-command tex-out-file))
(tex-display-shell))
(indent-line-to indent)
(save-excursion (indent-line-to indent)))))))
+(defcustom latex-indent-within-escaped-parens nil
+ "Non-nil means add extra indent to text within escaped parens.
+When this is non-nil, text within matching pairs of escaped
+parens is indented at the column following the open paren. The
+default value does not add any extra indent thus providing the
+behavior of Emacs 22 and earlier."
+ :type 'boolean
+ :group 'tex
+ :version "23.1")
+
(defun latex-find-indent (&optional virtual)
"Find the proper indentation of text after point.
VIRTUAL if non-nil indicates that we're only trying to find the indentation
in order to determine the indentation of something else.
There might be text before point."
- (save-excursion
- (skip-chars-forward " \t")
- (or
- ;; Stick the first line at column 0.
- (and (= (point-min) (line-beginning-position)) 0)
- ;; Trust the current indentation, if such info is applicable.
- (and virtual (save-excursion (skip-chars-backward " \t&") (bolp))
- (current-column))
- ;; Stick verbatim environments to the left margin.
- (and (looking-at "\\\\\\(begin\\|end\\) *{\\([^\n}]+\\)")
- (member (match-string 2) tex-verbatim-environments)
- 0)
- ;; Put leading close-paren where the matching open brace would be.
- (and (eq (latex-syntax-after) ?\))
- (ignore-errors
- (save-excursion
- (latex-skip-close-parens)
- (latex-backward-sexp-1)
- (latex-find-indent 'virtual))))
- ;; Default (maybe an argument)
- (let ((pos (point))
- ;; Outdent \item if necessary.
- (indent (if (looking-at tex-indent-item-re) (- tex-indent-item) 0))
- up-list-pos)
- ;; Find the previous point which determines our current indentation.
- (condition-case err
- (progn
- (latex-backward-sexp-1)
- (while (> (current-column) (current-indentation))
- (latex-backward-sexp-1)))
- (scan-error
- (setq up-list-pos (nth 2 err))))
- (cond
- ((= (point-min) pos) 0) ; We're really just indenting the first line.
- ((integerp 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))))
- ;; Align with the first element after the open-paren.
- (current-column)
- ;; We're the first element after a hanging brace.
+ (let ((latex-handle-escaped-parens latex-indent-within-escaped-parens))
+ (save-excursion
+ (skip-chars-forward " \t")
+ (or
+ ;; Stick the first line at column 0.
+ (and (= (point-min) (line-beginning-position)) 0)
+ ;; Trust the current indentation, if such info is applicable.
+ (and virtual (save-excursion (skip-chars-backward " \t&") (bolp))
+ (current-column))
+ ;; Stick verbatim environments to the left margin.
+ (and (looking-at "\\\\\\(begin\\|end\\) *{\\([^\n}]+\\)")
+ (member (match-string 2) tex-verbatim-environments)
+ 0)
+ ;; Put leading close-paren where the matching open paren would be.
+ (let (escaped)
+ (and (or (eq (latex-syntax-after) ?\))
+ ;; Try to handle escaped close parens but keep
+ ;; original position if it doesn't work out.
+ (and latex-handle-escaped-parens
+ (setq escaped (looking-at "\\\\\\([])}]\\)"))))
+ (ignore-errors
+ (save-excursion
+ (when escaped
+ (goto-char (match-beginning 1)))
+ (latex-skip-close-parens)
+ (latex-backward-sexp-1)
+ (latex-find-indent 'virtual)))))
+ ;; Default (maybe an argument)
+ (let ((pos (point))
+ ;; Outdent \item if necessary.
+ (indent (if (looking-at tex-indent-item-re) (- tex-indent-item) 0))
+ up-list-pos)
+ ;; Find the previous point which determines our current indentation.
+ (condition-case err
+ (progn
+ (latex-backward-sexp-1)
+ (while (> (current-column) (current-indentation))
+ (latex-backward-sexp-1)))
+ (scan-error
+ (setq up-list-pos (nth 2 err))))
+ (cond
+ ((= (point-min) pos) 0) ; We're really just indenting the first line.
+ ((integerp up-list-pos)
+ ;; Have to indent relative to the open-paren.
(goto-char up-list-pos)
- (+ (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.
- (+ indent (current-column) tex-indent-item))
- (t
- (let ((col (current-column)))
- (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
- ;; a risk that this is really not an argument to the
- ;; macro at all.
- (+ indent col)
- (forward-sexp 1)
- (if (< (line-end-position)
- (save-excursion (forward-comment (point-max))
- (point)))
- ;; we're indenting the first argument.
- (min (current-column) (+ tex-indent-arg col))
- (skip-syntax-forward " ")
- (current-column))))))))))
+ (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))))
+ ;; Align with the first element after the open-paren.
+ (current-column)
+ ;; We're the first element after a hanging brace.
+ (goto-char up-list-pos)
+ (+ (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.
+ (+ indent (current-column) tex-indent-item))
+ (t
+ (let ((col (current-column)))
+ (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
+ ;; a risk that this is really not an argument to the
+ ;; macro at all.
+ (+ indent col)
+ (forward-sexp 1)
+ (if (< (line-end-position)
+ (save-excursion (forward-comment (point-max))
+ (point)))
+ ;; we're indenting the first argument.
+ (min (current-column) (+ tex-indent-arg col))
+ (skip-syntax-forward " ")
+ (current-column)))))))))))
;;; DocTeX support
(defun doctex-font-lock-^^A ()