]> code.delx.au - gnu-emacs/blobdiff - lisp/textmodes/tex-mode.el
* indent.el (indent-for-tab-command): Fix typo in docstring.
[gnu-emacs] / lisp / textmodes / tex-mode.el
index 986c4fca20ba8bf3c7c2c5d6de7cda2e448eae41..312a081992e9b9ee3a6851596438242ce3d0ebcd 100644 (file)
@@ -1,7 +1,8 @@
 ;;; 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 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1989, 1992, 1994, 1995, 1996, 1997, 1998
+;;   1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+;;   Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: tex
 
 ;; 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
@@ -22,9 +23,7 @@
 ;; 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:
 
@@ -246,15 +245,20 @@ Normally set to either `plain-tex-mode' or `latex-mode'."
 (defcustom tex-fontify-script t
   "If non-nil, fontify subscript and superscript strings."
   :type 'boolean
-  :group 'tex)
+  :group 'tex
+  :version "23.1")
 (put 'tex-fontify-script 'safe-local-variable 'booleanp)
 
 (defcustom tex-font-script-display '(-0.2 0.2)
-  "Display specification for subscript and superscript content.
-The first is used for subscript, the second is used for superscripts."
+  "How much to lower and raise subscript and superscript content.
+This is a list of two floats.  The first is negative and
+specifies how much subscript is lowered, the second is positive
+and specifies how much superscript is raised.  Heights are
+measured relative to that of the normal text."
   :group 'tex
   :type '(list (float :tag "Subscript")
-               (float :tag "Superscript")))
+               (float :tag "Superscript"))
+  :version "23.1")
 
 (defvar tex-last-temp-file nil
   "Latest temporary file generated by \\[tex-region] and \\[tex-buffer].
@@ -496,7 +500,7 @@ An alternative value is \" . \", if you use a font with a narrow period."
        (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
@@ -636,7 +640,7 @@ An alternative value is \" . \", if you use a font with a narrow period."
 (defvar tex-verbatim-environments
   '("verbatim" "verbatim*"))
 (put 'tex-verbatim-environments 'safe-local-variable
-     (lambda (x) (require 'cl) (every 'stringp x)))
+     (lambda (x) (null (delq t (mapcar 'stringp x)))))
 
 (defvar tex-font-lock-syntactic-keywords
   '((eval . `(,(concat "^\\\\begin *{"
@@ -672,12 +676,42 @@ An alternative value is \" . \", if you use a font with a narrow period."
          (put-text-property beg next 'display nil))
       (setq beg next))))
 
+(defcustom tex-suscript-height-ratio 0.8
+  "Ratio of subscript/superscript height to that of the preceding text.
+In nested subscript/superscript, this factor is applied repeatedly,
+subject to the limit set by `tex-suscript-height-minimum'."
+  :type 'float
+  :group 'tex
+  :version "23.1")
+
+(defcustom tex-suscript-height-minimum 0.0
+  "Integer or float limiting the minimum size of subscript/superscript text.
+An integer is an absolute height in units of 1/10 point, a float
+is a height relative to that of the default font.  Zero means no minimum."
+  :type '(choice (integer :tag "Integer height in 1/10 point units")
+                (float :tag "Fraction of default font height"))
+  :group 'tex
+  :version "23.1")
+
+(defun tex-suscript-height (height)
+  "Return the integer height of subscript/superscript font in 1/10 points.
+Not smaller than the value set by `tex-suscript-height-minimum'."
+  (ceiling (max (if (integerp tex-suscript-height-minimum)
+                   tex-suscript-height-minimum
+                 ;; For bootstrapping.
+                 (condition-case nil
+                     (* tex-suscript-height-minimum
+                        (face-attribute 'default :height))
+                   (error 0)))
+               ;; NB assumes height is integer.
+               (* height tex-suscript-height-ratio))))
+
 (defface superscript
-  '((t :height 0.8)) ;; :raise 0.2
+  '((t :height tex-suscript-height)) ;; :raise 0.2
   "Face used for superscripts."
   :group 'tex)
 (defface subscript
-  '((t :height 0.8)) ;; :raise -0.2
+  '((t :height tex-suscript-height)) ;; :raise -0.2
   "Face used for subscripts."
   :group 'tex)
 
@@ -870,6 +904,15 @@ Inherits `shell-mode-map' with a few additions.")
 ;; 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.
@@ -1006,7 +1049,7 @@ subshell is initiated, `tex-shell-hook' is run."
                "\\>\\|\\\\[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)
@@ -1184,24 +1227,27 @@ on the line for the invalidity you want to see."
        (setq occur-revert-arguments (list nil 0 (list buffer))))
       (save-excursion
        (goto-char (point-max))
-       (while (and (not (bobp)))
-         (let ((end (point))
-               prev-end)
+       ;; Do a little shimmy to place point at the end of the last
+       ;; "real" paragraph. Need to avoid validating across an \end,
+       ;; because that blows up latex-forward-sexp.
+       (backward-paragraph)
+       (forward-paragraph)
+       (while (not (bobp))
            ;; Scan the previous paragraph for invalidities.
-           (if (search-backward "\n\n" nil t)
-               (progn
-                 (setq prev-end (point))
-                 (forward-char 2))
-             (goto-char (setq prev-end (point-min))))
-           (or (tex-validate-region (point) end)
-               (let* ((end (line-beginning-position 2))
+         (backward-paragraph)
+         (save-excursion
+           (or (tex-validate-region (point) (save-excursion
+                                              (forward-paragraph)
+                                              (point)))
+               (let ((end (line-beginning-position 2))
                       start tem)
                  (beginning-of-line)
                  (setq start (point))
                  ;; Keep track of line number as we scan,
                  ;; in a cumulative fashion.
                  (if linenum
-                     (setq linenum (- linenum (count-lines prevpos (point))))
+                     (setq linenum (- linenum
+                                      (count-lines prevpos (point))))
                    (setq linenum (1+ (count-lines 1 start))))
                  (setq prevpos (point))
                  ;; Mention this mismatch in *Occur*.
@@ -1222,10 +1268,10 @@ on the line for the invalidity you want to see."
                      (add-text-properties
                       text-beg (- text-end 1)
                       '(mouse-face highlight
-                        help-echo "mouse-2: go to this invalidity"))
+                                   help-echo
+                                   "mouse-2: go to this invalidity"))
                      (put-text-property text-beg (- text-end 1)
-                                        'occur-target tem)))))
-           (goto-char prev-end))))
+                                        'occur-target tem))))))))
       (with-current-buffer standard-output
        (let ((no-matches (zerop num-matches)))
          (if no-matches
@@ -1248,7 +1294,9 @@ area if a mismatch is found."
            (narrow-to-region start end)
            ;; First check that the open and close parens balance in numbers.
            (goto-char start)
-           (while (<= 0 (setq max-possible-sexps (1- max-possible-sexps)))
+           (while (and (not (eobp))
+                       (<= 0 (setq max-possible-sexps
+                                   (1- max-possible-sexps))))
              (forward-sexp 1))
            ;; Now check that like matches like.
            (goto-char start)
@@ -1256,6 +1304,7 @@ area if a mismatch is found."
              (save-excursion
                (let ((pos (match-beginning 0)))
                  (goto-char pos)
+                 (skip-chars-backward "\\\\") ; escaped parens
                  (forward-sexp 1)
                  (or (eq (preceding-char) (cdr (syntax-after pos)))
                      (eq (char-after pos) (cdr (syntax-after (1- (point)))))
@@ -1273,9 +1322,13 @@ A prefix arg inhibits the checking."
   (interactive "*P")
   (or inhibit-validation
       (save-excursion
+       ;; For the purposes of this, a "paragraph" is a block of text
+       ;; wherein all the brackets etc are expected to be balanced.  It
+       ;; may start after a blank line (ie a "proper" paragraph), or
+       ;; a begin{} or end{} block, etc.
        (tex-validate-region
         (save-excursion
-          (search-backward "\n\n" nil 'move)
+          (backward-paragraph)
           (point))
         (point)))
       (message "Paragraph being closed appears to contain a mismatch"))
@@ -1383,13 +1436,41 @@ Return the value returned by the last execution of BODY."
     (search-failed (error "Couldn't find unended \\begin"))))
 
 (defun tex-next-unmatched-end ()
-  "Leave point at the end of the next `\\end' that is unended."
+  "Leave point at the end of the next `\\end' that is unmatched."
   (while (and (tex-search-noncomment
               (re-search-forward "\\\\\\(begin\\|end\\)\\s *{[^}]+}"))
              (save-excursion (goto-char (match-beginning 0))
                              (looking-at "\\\\begin")))
     (tex-next-unmatched-end)))
 
+(defun tex-next-unmatched-eparen (otype)
+  "Leave point after the next unmatched escaped closing parenthesis.
+The string OTYPE is an opening parenthesis type: `(', `{', or `['."
+  (condition-case nil
+      (let ((ctype (char-to-string (cdr (aref (syntax-table)
+                                             (string-to-char otype))))))
+       (while (and (tex-search-noncomment
+                    (re-search-forward (format "\\\\[%s%s]" ctype otype)))
+                   (save-excursion
+                     (goto-char (match-beginning 0))
+                     (looking-at (format "\\\\%s" (regexp-quote otype)))))
+         (tex-next-unmatched-eparen otype)))
+    (wrong-type-argument (error "Unknown opening parenthesis type: %s" otype))
+    (search-failed (error "Couldn't find closing escaped paren"))))
+
+(defun tex-last-unended-eparen (ctype)
+  "Leave point at the start of the last unended escaped opening parenthesis.
+The string CTYPE is a closing parenthesis type:  `)', `}', or `]'."
+  (condition-case nil
+      (let ((otype (char-to-string (cdr (aref (syntax-table)
+                                             (string-to-char ctype))))))
+       (while (and (tex-search-noncomment
+                    (re-search-backward (format "\\\\[%s%s]" ctype otype)))
+                   (looking-at (format "\\\\%s" (regexp-quote ctype))))
+         (tex-last-unended-eparen ctype)))
+    (wrong-type-argument (error "Unknown opening parenthesis type: %s" ctype))
+    (search-failed (error "Couldn't find unended escaped paren"))))
+
 (defun tex-goto-last-unclosed-latex-block ()
   "Move point to the last unclosed \\begin{...}.
 Mark is left at original location."
@@ -1401,26 +1482,42 @@ Mark is left at original location."
     (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."
+  "Like (backward-sexp 1) but aware of multi-char elements and escaped parens."
   (let ((pos (point))
        (forward-sexp-function))
     (backward-sexp 1)
-    (if (looking-at "\\\\begin\\>")
-       (signal 'scan-error
-               (list "Containing expression ends prematurely"
-                     (point) (prog1 (point) (goto-char pos))))
-      (when (eq (char-after) ?{)
-       (let ((newpos (point)))
-         (when (ignore-errors (backward-sexp 1) t)
-           (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))))))))
-
+    (cond ((looking-at
+           (if latex-handle-escaped-parens
+               "\\\\\\(begin\\>\\|[[({]\\)"
+             "\\\\begin\\>"))
+          (signal 'scan-error
+                  (list "Containing expression ends prematurely"
+                        (point) (prog1 (point) (goto-char pos)))))
+         ((and latex-handle-escaped-parens
+               (looking-at "\\\\\\([])}]\\)"))
+          (tex-last-unended-eparen (match-string 1)))
+         ((eq (char-after) ?{)
+          (let ((newpos (point)))
+            (when (ignore-errors (backward-sexp 1) t)
+              (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))))))))
+
+;; Note this does not handle things like mismatched brackets inside
+;; 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."
+  "Like (forward-sexp 1) but aware of multi-char elements and escaped parens."
   (let ((pos (point))
        (forward-sexp-function))
     (forward-sexp 1)
@@ -1437,10 +1534,21 @@ Mark is left at original location."
        ((looking-at "\\\\begin\\>")
        (goto-char (match-end 0))
        (tex-next-unmatched-end))
+       ;; A better way to handle this, \( .. \) etc, is probably to
+       ;; temporarily change the syntax of the \ in \( to punctuation.
+       ((and latex-handle-escaped-parens
+            (looking-back "\\\\[])}]"))
+       (signal 'scan-error
+               (list "Containing expression ends prematurely"
+                     (- (point) 2) (prog1 (point)
+                                     (goto-char pos)))))
+       ((and latex-handle-escaped-parens
+            (looking-back "\\\\\\([({[]\\)"))
+       (tex-next-unmatched-eparen (match-string 1)))
        (t (goto-char newpos))))))
 
 (defun latex-forward-sexp (&optional arg)
-  "Like `forward-sexp' but aware of multi-char elements."
+  "Like `forward-sexp' but aware of multi-char elements and escaped parens."
   (interactive "P")
   (unless arg (setq arg 1))
   (let ((pos (point)))
@@ -1694,6 +1802,7 @@ If NOT-ALL is non-nil, save the `.dvi' file."
                     (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")
@@ -1809,11 +1918,11 @@ FILE is typically the output DVI or PDF file."
         (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)
                         (point-min)))
@@ -1841,7 +1950,8 @@ FILE is typically the output DVI or PDF file."
                  (not (file-symlink-p f)))
             (unless (string-match ignored-dirs-re f)
               (setq files (nconc
-                           (directory-files f t tex-input-files-re)
+                            (ignore-errors ;Not readable or something.
+                              (directory-files f t tex-input-files-re))
                            files)))
           (when (file-newer-than-file-p f file)
             (setq uptodate nil)))))
@@ -1853,11 +1963,15 @@ FILE is typically the output DVI or PDF file."
 (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)))))
@@ -1876,6 +1990,26 @@ FILE is typically the output DVI or PDF file."
       (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!
@@ -1946,7 +2080,10 @@ FILE is typically the output DVI or PDF file."
          ;; 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."
@@ -1964,14 +2101,24 @@ FILE is typically the output DVI or PDF file."
           (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."
@@ -2032,29 +2179,42 @@ for the error messages."
          (file-name-directory (buffer-file-name tex-last-buffer-texed)))
        found-desired (num-errors-found 0)
        last-filename last-linenum last-position
-       begin-of-error end-of-error)
+       begin-of-error end-of-error errfilename)
     ;; Don't reparse messages already seen at last parse.
     (goto-char compilation-parsing-end)
     ;; Parse messages.
     (while (and (not (or found-desired (eobp)))
-               (prog1 (re-search-forward "^! " nil 'move)
+               ;; First alternative handles the newer --file-line-error style:
+               ;; ./test2.tex:14: Too many }'s.
+               ;; Second handles the old-style:
+               ;; ! Too many }'s.
+               (prog1 (re-search-forward
+                       "^\\(?:\\([^:\n]+\\):[[:digit:]]+:\\|!\\) " nil 'move)
                  (setq begin-of-error (match-beginning 0)
-                       end-of-error (match-end 0)))
+                       end-of-error (match-end 0)
+                       errfilename (match-string 1)))
                (re-search-forward
                 "^l\\.\\([0-9]+\\) \\(\\.\\.\\.\\)?\\(.*\\)$" nil 'move))
       (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
-             (save-excursion
-               (with-syntax-table tex-error-parse-syntax-table
-                 (backward-up-list 1)
-                 (skip-syntax-forward "(_")
-                 (while (not (file-readable-p (thing-at-point 'filename)))
-                   (skip-syntax-backward "(_")
-                   (backward-up-list 1)
-                   (skip-syntax-forward "(_"))
-                 (thing-at-point 'filename))))
+             ;; Prefer --file-liner-error filename if we have it.
+             (or errfilename
+                 (save-excursion
+                   (with-syntax-table tex-error-parse-syntax-table
+                     (backward-up-list 1)
+                     (skip-syntax-forward "(_")
+                     (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 "(_"))
+                     (thing-at-point 'filename)))))
             (new-file
              (or (null last-filename)
                  (not (string-equal last-filename filename))))
@@ -2376,10 +2536,11 @@ Runs the shell command defined by `tex-show-queue-command'."
   (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))
@@ -2418,97 +2579,115 @@ Runs the shell command defined by `tex-show-queue-command'."
            (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 ()