summaryrefslogtreecommitdiff
path: root/elpa/auctex-13.1.3/tex.el
diff options
context:
space:
mode:
Diffstat (limited to 'elpa/auctex-13.1.3/tex.el')
-rw-r--r--elpa/auctex-13.1.3/tex.el10227
1 files changed, 10227 insertions, 0 deletions
diff --git a/elpa/auctex-13.1.3/tex.el b/elpa/auctex-13.1.3/tex.el
new file mode 100644
index 0000000..747753b
--- /dev/null
+++ b/elpa/auctex-13.1.3/tex.el
@@ -0,0 +1,10227 @@
+;;; tex.el --- Support for TeX documents. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 1985-2022 Free Software Foundation, Inc.
+
+;; Maintainer: auctex-devel@gnu.org
+;; Keywords: tex
+
+;; This file is part of AUCTeX.
+
+;; AUCTeX 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.
+
+;; AUCTeX is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with AUCTeX; see the file COPYING. If not, write to the Free
+;; Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+;; 02110-1301, USA.
+
+;;; Commentary:
+
+;; This file provides basic functions used by the AUCTeX modes.
+
+;;; Code:
+
+(when (< emacs-major-version 25)
+ (error "AUCTeX requires Emacs 25.1 or later"))
+
+(require 'custom)
+(require 'tex-site)
+(eval-when-compile
+ (require 'cl-lib))
+(require 'texmathp)
+;; Require dbus at compile time to get macro definition of
+;; `dbus-ignore-errors'.
+(eval-when-compile (require 'dbus))
+
+;; Silence the compiler for functions:
+(declare-function dbus-get-unique-name "ext:dbusbind.c"
+ (bus))
+(declare-function dbus-ping "ext:dbus"
+ (bus service &optional timeout))
+(declare-function dbus-introspect-get-method "ext:dbus"
+ (bus service path interface method))
+(declare-function dbus-call-method "ext:dbus"
+ (bus service path interface method &rest args))
+(declare-function dbus-register-signal "ext:dbus"
+ (bus service path interface signal handler &rest args))
+(declare-function LaTeX-environment-list "latex"
+ nil)
+(declare-function LaTeX-bibliography-list "latex"
+ nil)
+(declare-function comint-exec
+ (buffer name command startfile switches))
+(declare-function comint-mode
+ nil)
+(declare-function tex--prettify-symbols-compose-p "ext:tex-mode"
+ (start end match))
+(declare-function gnuserv-start "ext:gnuserv"
+ (&optional leave-dead) t)
+
+;; Silence the compiler for variables:
+;; tex.el: Variables defined somewhere in this file:
+(defvar TeX-PDF-from-DVI)
+(defvar TeX-PDF-mode)
+(defvar TeX-PDF-mode-parsed)
+(defvar TeX-all-extensions)
+(defvar TeX-command-default)
+(defvar TeX-default-extension)
+(defvar TeX-esc)
+(defvar TeX-interactive-mode)
+(defvar TeX-macro-global)
+(defvar TeX-mode-map)
+(defvar TeX-mode-p)
+(defvar TeX-output-extension)
+(defvar TeX-source-correlate-mode)
+(defvar TeX-source-specials-places)
+(defvar TeX-source-specials-tex-flags)
+(defvar TeX-synctex-tex-flags)
+(defvar TeX-current-process-region-p)
+(defvar TeX-region)
+(defvar TeX-region-orig-buffer)
+;; Variables defined in other AUCTeX libraries:
+;; latex.el:
+(defvar LaTeX-default-verb-delimiter)
+(defvar LaTeX-optcl)
+(defvar LaTeX-optop)
+(defvar LaTeX-largest-level)
+(defvar LaTeX-section-list)
+(defvar TeX-output-dir)
+;; tex-ispell.el
+(defvar TeX-ispell-verb-delimiters)
+;; Others:
+(defvar tex--prettify-symbols-alist) ; tex-mode.el
+(defvar Info-file-list-for-emacs) ; info.el
+(defvar ispell-parser) ; ispell.el
+(defvar compilation-error-regexp-alist) ; compile.el
+
+(defgroup TeX-file nil
+ "Files used by AUCTeX."
+ :group 'AUCTeX)
+
+(defgroup TeX-command nil
+ "Calling external commands from AUCTeX."
+ :group 'AUCTeX)
+
+(defgroup LaTeX nil
+ "LaTeX support in AUCTeX."
+ :tag "LaTeX"
+ :group 'AUCTeX
+ :prefix "LaTeX-")
+
+(defgroup TeX-misc nil
+ "Various AUCTeX settings."
+ :group 'AUCTeX)
+
+;;; Site Customization
+;;
+;; The following variables are likely to need to be changed for your
+;; site. You should do this with customize.
+
+(defcustom TeX-command "tex"
+ "Command to run plain TeX."
+ :group 'TeX-command
+ :type 'string)
+
+(defcustom TeX-Omega-command "omega"
+ "Command to run plain TeX on Omega."
+ :group 'TeX-command
+ :type '(choice (const :tag "Aleph" "aleph")
+ (const :tag "Omega" "omega")
+ (string :tag "Other command")))
+
+(defcustom LaTeX-command "latex"
+ "Command to run LaTeX."
+ :group 'TeX-command
+ :type 'string)
+
+(defcustom LaTeX-Omega-command "lambda"
+ "Command to run LaTeX on Omega."
+ :group 'TeX-command
+ :type '(choice (const :tag "Lamed" "lamed")
+ (const :tag "Lambda" "lambda")
+ (string :tag "Other command")))
+
+(defcustom TeX-file-line-error t
+ "Whether to have TeX produce file:line:error style error messages."
+ :group 'TeX-command
+ :type 'boolean)
+
+(defcustom ConTeXt-engine nil
+ "Engine to use for --engine in the texexec command.
+If nil, none is specified."
+ :group 'TeX-command
+ :type '(choice (const :tag "Unspecified" nil)
+ string))
+
+(defcustom ConTeXt-Omega-engine TeX-Omega-command
+ "Engine to use for --engine in the texexec command in Omega mode.
+If nil, none is specified."
+ :group 'TeX-command
+ :type '(choice (const :tag "Unspecified" nil)
+ string))
+;; At least in TeXLive 2009 ConTeXt does not support an omega option anymore.
+(make-obsolete-variable 'ConTeXt-Omega-engine 'TeX-engine-alist "11.86")
+
+(defcustom TeX-mode-hook nil
+ "A hook run in TeX mode buffers."
+ :type 'hook
+ :group 'TeX-misc)
+
+;; This is the major configuration variable. Most sites will only need to
+;; change the second string in each entry, which is the name of a command to
+;; send to the shell. If you use other formatters like AMSLaTeX or AMSTeX, you
+;; can add those to the list. See `TeX-expand-list' and
+;; `TeX-expand-list-builtin' for a description of the % escapes
+
+(defcustom TeX-command-list
+ '(("TeX" "%(PDF)%(tex) %(file-line-error) %`%(extraopts) %S%(PDFout)%(mode)%' %(output-dir) %t"
+ TeX-run-TeX nil
+ (plain-tex-mode ams-tex-mode texinfo-mode) :help "Run plain TeX")
+ ("LaTeX" "%`%l%(mode)%' %T"
+ TeX-run-TeX nil
+ (latex-mode doctex-mode) :help "Run LaTeX")
+ ;; Not part of standard TeX.
+ ("Makeinfo" "makeinfo %(extraopts) %(o-dir) %t" TeX-run-compile nil
+ (texinfo-mode) :help "Run Makeinfo with Info output")
+ ("Makeinfo HTML" "makeinfo %(extraopts) %(o-dir) --html %t" TeX-run-compile nil
+ (texinfo-mode) :help "Run Makeinfo with HTML output")
+ ("AmSTeX" "amstex %(PDFout) %`%(extraopts) %S%(mode)%' %(output-dir) %t"
+ TeX-run-TeX nil (ams-tex-mode) :help "Run AMSTeX")
+ ;; support for ConTeXt --pg
+ ;; first version of ConTeXt to support nonstopmode: 2003.2.10
+ ("ConTeXt" "%(cntxcom) --once --texutil %(extraopts) %(execopts)%t"
+ TeX-run-TeX nil (context-mode) :help "Run ConTeXt once")
+ ("ConTeXt Full" "%(cntxcom) %(extraopts) %(execopts)%t"
+ TeX-run-TeX nil
+ (context-mode) :help "Run ConTeXt until completion")
+ ("BibTeX" "bibtex %(O?aux)" TeX-run-BibTeX nil
+ (plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode
+ context-mode)
+ :help "Run BibTeX")
+ ("Biber" "biber %(output-dir) %s" TeX-run-Biber nil
+ (plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
+ :help "Run Biber")
+ ;; Not part of standard TeX.
+ ;; It seems that texindex doesn't support "--output-dir" option.
+ ("Texindex" "texindex %s.??" TeX-run-command nil
+ (texinfo-mode) :help "Run Texindex")
+ ;; TODO:
+ ;; 1. Supply "--dvipdf" option if `TeX-PDF-mode' and
+ ;; `TeX-PDF-from-DVI' are non-nil.
+ ;; 2. Supply "--build-dir=DIR" option when `TeX-output-dir' is
+ ;; non-nil.
+ ("Texi2dvi" "%(PDF)texi2dvi %t" TeX-run-command nil
+ (texinfo-mode) :help "Run Texi2dvi or Texi2pdf")
+ ("View" "%V" TeX-run-discard-or-function t t :help "Run Viewer")
+ ("Print" "%p" TeX-run-command t t :help "Print the file")
+ ("Queue" "%q" TeX-run-background nil t :help "View the printer queue"
+ :visible TeX-queue-command)
+ ("File" "%(o?)dvips %d -o %f " TeX-run-dvips t
+ (plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
+ :help "Generate PostScript file")
+ ("Dvips" "%(o?)dvips %d -o %f " TeX-run-dvips nil
+ (plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
+ :help "Convert DVI file to PostScript")
+ ("Dvipdfmx" "dvipdfmx -o %(O?pdf) %d" TeX-run-dvipdfmx nil
+ (plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
+ :help "Convert DVI file to PDF with dvipdfmx")
+ ("Ps2pdf" "ps2pdf %f %(O?pdf)" TeX-run-ps2pdf nil
+ (plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
+ :help "Convert PostScript file to PDF")
+ ("Glossaries" "makeglossaries %(d-dir) %s" TeX-run-command nil
+ (plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
+ :help "Run makeglossaries to create glossary file")
+ ("Index" "makeindex %(O?idx)" TeX-run-index nil
+ (plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
+ :help "Run makeindex to create index file")
+ ("upMendex" "upmendex %(O?idx)" TeX-run-index t
+ (plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
+ :help "Run upmendex to create index file")
+ ("Xindy" "texindy %s" TeX-run-command nil
+ (plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
+ :help "Run xindy to create index file")
+ ("Check" "lacheck %s" TeX-run-compile nil (latex-mode)
+ :help "Check LaTeX file for correctness")
+ ("ChkTeX" "chktex -v6 %s" TeX-run-compile nil (latex-mode)
+ :help "Check LaTeX file for common mistakes")
+ ("Spell" "(TeX-ispell-document \"\")" TeX-run-function nil t
+ :help "Spell-check the document")
+ ("Clean" "TeX-clean" TeX-run-function nil t
+ :help "Delete generated intermediate files")
+ ("Clean All" "(TeX-clean t)" TeX-run-function nil t
+ :help "Delete generated intermediate and output files")
+ ("Other" "" TeX-run-command t t :help "Run an arbitrary command"))
+ "List of commands to execute on the current document.
+
+Each element is a list, whose first element is the name of the command
+as it will be presented to the user.
+
+The second element is the string handed to the shell after being
+expanded. The expansion is done using the information found in
+`TeX-expand-list'.
+
+The third element is the function which actually start the process.
+Several such hooks have been defined:
+
+TeX-run-command: Start up the process and show the output in a
+separate buffer. Check that there is not two commands running for the
+same file. Return the process object.
+
+TeX-run-format: As `TeX-run-command', but assume the output is created
+by a TeX macro package. Return the process object.
+
+TeX-run-TeX: For TeX output.
+
+TeX-run-interactive: Run TeX or LaTeX interactively.
+
+TeX-run-BibTeX: For BibTeX output.
+
+TeX-run-Biber: For Biber output.
+
+TeX-run-compile: Use `compile' to run the process.
+
+TeX-run-shell: Use `shell-command' to run the process.
+
+TeX-run-discard: Start the process in the background, discarding its
+output.
+
+TeX-run-background: Start the process in the background, show output
+in other window.
+
+TeX-run-silent: Start the process in the background.
+
+TeX-run-discard-foreground: Start the process in the foreground,
+discarding its output.
+
+TeX-run-function: Execute the Lisp function or function call
+specified by the string in the second element. Consequently,
+this hook does not start a process.
+
+TeX-run-discard-or-function: If the command is a Lisp function,
+execute it as such, otherwise start the command as a process,
+discarding its output.
+
+To create your own hook, define a function taking three arguments: The
+name of the command, the command string, and the name of the file to
+process. It might be useful to use `TeX-run-command' in order to
+create an asynchronous process.
+
+If the fourth element is non-nil, the user will get a chance to
+modify the expanded string.
+
+The fifth element indicates in which mode(s) the command should be
+present in the Command menu. Use t if it should be active in any
+mode. If it should only be present in some modes, specify a list with
+the respective mode names.
+
+Any additional elements get just transferred to the respective menu entries."
+ :group 'TeX-command
+ :type '(repeat (group :value ("" "" TeX-run-command nil t)
+ (string :tag "Name")
+ (string :tag "Command")
+ (choice :tag "How"
+ :value TeX-run-command
+ (function-item TeX-run-command)
+ (function-item TeX-run-format)
+ (function-item TeX-run-TeX)
+ (function-item TeX-run-interactive)
+ (function-item TeX-run-BibTeX)
+ (function-item TeX-run-Biber)
+ (function-item TeX-run-compile)
+ (function-item TeX-run-shell)
+ (function-item TeX-run-discard)
+ (function-item TeX-run-background)
+ (function-item TeX-run-silent)
+ (function-item TeX-run-discard-foreground)
+ (function-item TeX-run-function)
+ (function-item TeX-run-discard-or-function)
+ (function :tag "Other"))
+ (boolean :tag "Prompt")
+ (choice :tag "Modes"
+ (const :tag "All" t)
+ (set (const :tag "Plain TeX" plain-tex-mode)
+ (const :tag "LaTeX" latex-mode)
+ (const :tag "DocTeX" doctex-mode)
+ (const :tag "ConTeXt" context-mode)
+ (const :tag "Texinfo" texinfo-mode)
+ (const :tag "AmSTeX" ams-tex-mode)))
+ (repeat :tag "Menu elements" :inline t sexp))))
+
+(defcustom TeX-command-output-list
+ '(
+ ; Add the following line if you want to use htlatex (tex4ht)
+ ; ("\\`htlatex" ("html"))
+ )
+ "List of regexps and file extensions.
+
+Each element is a list, whose first element is a regular expression to
+match against the name of the command that will be used to process the TeX
+file.
+
+The second element is either a string or a list with a string as element.
+If it is a string this is the default file extension that will be expected
+for output files that are produced by commands that match the first
+element. The real file extension will be obtained from the logging output
+if possible, defaulting to the given string.
+If it is a list, the element of the list will be the fixed extension used
+without looking at the logging output.
+
+If this list does not yield an extension, the default is either \"dvi\"
+or \"pdf\", depending on the setting of `TeX-PDF-mode'.
+Extensions must be given without the \".\"."
+
+ :group 'TeX-command
+ :type '(repeat (group (regexp :tag "Command Regexp")
+ (choice (string :tag "Default Extension")
+ (group (string :tag "Fixed Extension"))))))
+
+;; You may want to change the default LaTeX version for your site.
+(defcustom LaTeX-version "2e"
+ "Default LaTeX version. Currently recognized is \"2\" and \"2e\"."
+ :group 'LaTeX
+ :type '(radio (const :format "%v\n%h"
+ :doc "\
+The executable `latex' is LaTeX version 2."
+ "2")
+ (const :format "%v\n%h"
+ :doc "\
+The executable `latex' is LaTeX version 2e."
+ "2e")
+ (string :tag "Other")))
+
+
+;; Use different compilation commands depending on style.
+;; Only works if parsing is enabled.
+
+(defcustom LaTeX-command-style
+ ;; They have all been combined in LaTeX 2e.
+ '(("" "%(PDF)%(latex) %(file-line-error) %(extraopts) %(output-dir) %S%(PDFout)"))
+"List of style options and LaTeX commands.
+
+If the first element (a regular expression) matches the name of one of
+the style files, any occurrence of the string `%l' in a command in
+`TeX-command-list' will be replaced with the second element. The first
+match is used, if no match is found the `%l' is replaced with the empty
+string."
+ :group 'TeX-command
+ :type '(repeat (group :value ("" "")
+ regexp (string :tag "Style"))))
+
+;; Printing: If you want to print, TeX-print-command must be non-nil
+;; (if it is nil, you'll get a complaint when using the print menu).
+;; If you want to view the queue, TeX-queue-command needs to be
+;; non-nil (if it is nil, it won't get mentioned in the menu). If
+;; TeX-printer-list is nil, nothing else gets asked: the menu entries
+;; lead directly to the respective commands. If those commands
+;; contain %p, the value of TeX-printer-default gets inserted there,
+;; no questions asked. Now if TeX-printer-list is non-nil, you'll
+;; always get asked which printer you want to use. You can enter a
+;; configured printer from TeX-printer-list, or an unknown one. The
+;; respective menus will show all configured printers. Since you can
+;; enter unknown printers, the printer name _must_ be set with %p in
+;; TeX-print-command.
+
+(defcustom TeX-print-command
+ "{ test -e %d && %(o?)dvips -P%p %r %s; } || lpr -P%p %o"
+ "Command used to print a file.
+
+First `%p' is expanded to the printer name, then ordinary expansion is
+performed as specified in `TeX-expand-list'. If it is nil,
+then customization is requested."
+ :group 'TeX-command
+ :type '(choice (string :tag "Print command")
+ (const :tag "No print command customized" nil)))
+
+(defcustom TeX-queue-command "lpq -P%p"
+ "Command used to show the status of a printer queue.
+
+First `%p' is expanded to the printer name, then ordinary expansion is
+performed as specified in `TeX-expand-list'. If this is nil,
+the printer has no corresponding command."
+ :group 'TeX-command
+ :type '(choice (string :tag "Queue check command")
+ (const :tag "No such command" nil)))
+
+;; Enter the names of the printers available at your site, or nil if
+;; you only have one printer.
+
+(defcustom TeX-printer-list
+ '(("Default"
+ ;; Print to the (unnamed) default printer. If there is a DVI
+ ;; file print via Dvips. If not, pass the output file (which
+ ;; should then be a Postscript or PDF file) directly to lpr.
+ "{ test -e %d && %(o?)dvips -f %r %s | lpr; } || lpr %o"
+ ;; Show the queue for the (unnamed) default printer.
+ "lpq"))
+ "List of available printers.
+
+The first element of each entry is the printer name.
+
+The second element is the command used to print to this
+printer. It defaults to the value of `TeX-print-command' when nil.
+
+The third element is the command used to examine the print queue for
+this printer. It defaults to the value of `TeX-queue-command' similarly.
+
+Any occurrence of `%p' in the second or third element is expanded to
+the printer name given in the first element, then ordinary expansion
+is performed as specified in `TeX-expand-list'.
+
+If this list is empty, only `TeX-print-command' and `TeX-queue-command'
+get consulted."
+ :group 'TeX-command
+ :type '(repeat (group (string :tag "Name")
+ (option (group :inline t
+ :extra-offset -4
+ (choice :tag "Print"
+ (const :tag "default")
+ (string :format "%v"))
+ (option (choice :tag "Queue"
+ (const :tag "default")
+ (string
+ :format "%v"))))))))
+
+;; The name of the most used printer.
+
+(defcustom TeX-printer-default (or (getenv "PRINTER")
+ (and TeX-printer-list
+ (car (car TeX-printer-list)))
+ "lp")
+ "Default printer to use with `TeX-command'."
+ :group 'TeX-command
+ :type 'string)
+
+(defcustom TeX-print-style '(("^landscape$" "-t landscape"))
+ "List of style options and print options.
+
+If the first element (a regular expression) matches the name of one of
+the style files, any occurrence of the string `%r' in a command in
+`TeX-command-list' will be replaced with the second element. The first
+match is used, if no match is found the `%r' is replaced with the empty
+string."
+ :group 'TeX-command
+ :type '(repeat (group regexp (string :tag "Command"))))
+
+(defcustom TeX-command-extra-options ""
+ "String with the extra options to be given to the TeX processor."
+ :type 'string)
+(make-variable-buffer-local 'TeX-command-extra-options)
+
+(defvar TeX-command-text nil
+ "Dynamically bound by `TeX-command-expand'.")
+(defvar TeX-command-pos nil
+ "Dynamically bound by `TeX-command-expand'.")
+(defvar TeX-expand-pos nil
+ "Dynamically bound by `TeX-command-expand'.")
+(defvar TeX-expand-command nil
+ "Dynamically bound by `TeX-command-expand'.")
+
+;; This is the list of expansion for the commands in
+;; TeX-command-list. Not likely to be changed, but you may e.g. want
+;; to handle .ps files.
+
+(defvar TeX-expand-list-builtin
+ '(("%q" (lambda ()
+ (TeX-printer-query t)))
+ ("%V" (lambda ()
+ (TeX-source-correlate-start-server-maybe)
+ (TeX-view-command-raw)))
+ ("%r" (lambda ()
+ (TeX-style-check TeX-print-style)))
+ ("%l" (lambda ()
+ (TeX-style-check LaTeX-command-style)))
+ ("%(PDF)" (lambda ()
+ (if (and (eq TeX-engine 'default)
+ (if TeX-PDF-mode
+ (not (TeX-PDF-from-DVI))
+ TeX-DVI-via-PDFTeX))
+ "pdf"
+ "")))
+ ("%(PDFout)" (lambda ()
+ (cond ((eq major-mode 'ams-tex-mode)
+ (if TeX-PDF-mode
+ " -output-format=pdf"
+ " -output-format=dvi"))
+ ((and (eq TeX-engine 'xetex)
+ (not TeX-PDF-mode))
+ " -no-pdf")
+ ((and (eq TeX-engine 'luatex)
+ (not TeX-PDF-mode))
+ " --output-format=dvi")
+ ((and (eq TeX-engine 'default)
+ (not TeX-PDF-mode)
+ TeX-DVI-via-PDFTeX)
+ " \"\\pdfoutput=0 \"")
+ (t ""))))
+ ("%(mode)" (lambda ()
+ (if TeX-interactive-mode
+ ""
+ " -interaction=nonstopmode")))
+ ("%(file-line-error)"
+ (lambda () (if TeX-file-line-error " -file-line-error" "")))
+ ("%(o?)" (lambda () (if (eq TeX-engine 'omega) "o" "")))
+ ("%(tex)" (lambda () (eval (nth 2 (TeX-engine-in-engine-alist TeX-engine)))))
+ ("%(latex)" (lambda () (eval (nth 3 (TeX-engine-in-engine-alist TeX-engine)))))
+ ("%(cntxcom)" ConTeXt-expand-command)
+ ("%(execopts)" ConTeXt-expand-options)
+ ("%(extraopts)" (lambda () TeX-command-extra-options))
+ ("%(output-dir)" TeX--output-dir-arg "--output-directory=")
+ ("%(o-dir)" TeX--output-dir-arg "-o ")
+ ("%(d-dir)" TeX--output-dir-arg "-d ")
+ ("%S" TeX-source-correlate-expand-options)
+ ("%dS" TeX-source-specials-view-expand-options)
+ ("%cS" TeX-source-specials-view-expand-client)
+ ("%(outpage)" (lambda ()
+ ;; When `TeX-source-correlate-output-page-function' is nil
+ ;; and we are using synctex, fallback on
+ ;; `TeX-synctex-output-page'.
+ (and TeX-source-correlate-mode
+ (null TeX-source-correlate-output-page-function)
+ (eq (TeX-source-correlate-method-active) 'synctex)
+ (setq TeX-source-correlate-output-page-function
+ #'TeX-synctex-output-page))
+ (or (if TeX-source-correlate-output-page-function
+ (funcall TeX-source-correlate-output-page-function))
+ "1")))
+ ;; `TeX-active-master-with-quotes' calls either `TeX-master-file'
+ ;; or `TeX-region-file' returning the master or region file, and
+ ;; adds suitable quotes for use in shell command line.
+ ("%s" TeX-active-master-with-quotes nil t)
+ ("%t" TeX-active-master-with-quotes t t)
+ ("%(t-filename-only)" TeX-active-master-with-quotes t t nil nil file-name-nondirectory)
+ ;; If any TeX codes appear in the interval between %` and %', move
+ ;; all of them after the interval and supplement " \input". The
+ ;; appearance is marked by leaving the bind to `TeX-command-text'
+ ;; with the TeX codes.
+ ;; Rule:
+ ;; 1. %` and %' must appear in pair.
+ ;; 2. %` and %' must not appear more than once in one command
+ ;; line string (including the results of %-expansion).
+ ;; 3. Each TeX codes between %` and %' must be enclosed in
+ ;; double quotes and preceded by a space.
+ ("%`" (lambda nil
+ (setq TeX-command-pos t TeX-command-text nil)
+ ""))
+ (" \"\\" (lambda nil
+ (if (eq TeX-command-pos t)
+ (setq TeX-command-pos TeX-expand-pos
+ TeX-expand-pos (+ 3 TeX-expand-pos))
+ (setq TeX-expand-pos (1+ TeX-expand-pos)))))
+ ("\"" (lambda nil (if (numberp TeX-command-pos)
+ (setq TeX-command-text
+ (concat
+ TeX-command-text
+ (substring TeX-expand-command
+ TeX-command-pos
+ (1+ TeX-expand-pos)))
+ TeX-expand-command
+ (concat
+ (substring TeX-expand-command
+ 0
+ TeX-command-pos)
+ (substring TeX-expand-command
+ (1+ TeX-expand-pos)))
+ TeX-expand-pos TeX-command-pos
+ TeX-command-pos t)
+ (setq TeX-expand-pos (1+ TeX-expand-pos)))))
+ ("%'" (lambda nil
+ (setq TeX-command-pos nil)
+ (if (stringp TeX-command-text)
+ (progn
+ (setq TeX-expand-pos (+ TeX-expand-pos (length TeX-command-text) 9))
+ (concat TeX-command-text " \"\\input\""))
+ "")))
+ ;; The fourth argument of t directs to supply "\detokenize{}" when
+ ;; necessary. See doc string and comment of
+ ;; `TeX-active-master-with-quotes'.
+ ("%T" TeX-active-master-with-quotes t t nil t)
+ ("%n" TeX-current-line)
+ ("%d" TeX-active-master-with-quotes "dvi" t)
+ ("%f" TeX-active-master-with-quotes "ps" t)
+ ("%(O?aux)" TeX-active-master-with-quotes "aux" t)
+ ("%(O?idx)" TeX-active-master-with-quotes "idx" t)
+ ("%(O?pdf)" TeX-active-master-with-quotes "pdf" t)
+ ("%o" (lambda nil (TeX-active-master-with-quotes (TeX-output-extension) t)))
+ ;; for source specials the file name generated for the xdvi
+ ;; command needs to be relative to the master file, just in
+ ;; case the file is in a different subdirectory
+ ("%b" TeX-current-file-name-master-relative)
+ ;; Okular forward PDF search requires absolute path.
+ ("%a" (lambda nil (prin1-to-string (expand-file-name (buffer-file-name)))))
+ ;; the following is for preview-latex.
+ ("%m" preview-create-subdirectory))
+ "List of built-in expansion strings for TeX command names.
+
+This should not be changed by the user who can use
+`TeX-expand-list' variable. The latter variable also contains a
+description of the data format.
+
+Programs should not use these variables directly but the function
+`TeX-expand-list'.")
+
+(defcustom TeX-expand-list nil
+ "List of expansion strings for TeX command names defined by the user.
+
+Each entry is a list with two or more elements. The first
+element is the string to be expanded. The second element is the
+name of a function returning the expanded string when called with
+the remaining elements as arguments.
+The second element can also be a variable name whose value is
+such function.
+
+Built-in expansions provided in `TeX-expand-list-builtin' can be
+overwritten by defining expansions strings with the same
+expander. Only \"%p\" expander cannot be overwritten.
+
+Programs should not use these variables directly but the function
+`TeX-expand-list'."
+ :group 'TeX-command
+ :type '(repeat (group (string :tag "Key")
+ (sexp :tag "Expander")
+ (repeat :inline t
+ :tag "Arguments"
+ (sexp :format "%v")))))
+
+(defun TeX-expand-list ()
+ "Complete list of expansion strings for TeX command names.
+
+Concatenate `TeX-expand-list' and `TeX-expand-list-builtin' making
+sure \"%p\" is the first entry."
+ (append
+ ;; %p must be the first entry, see `TeX-print-command'.
+ '(("%p" TeX-printer-query))
+ TeX-expand-list
+ TeX-expand-list-builtin))
+
+;; This variable used to be defined in tex-buf.el. It is used in
+;; `TeX-mode-specific-command-menu-entries' in this file. It is now
+;; (June 2021) moved into this file to avoid `void-variable' errors
+;; with the "Command" menu if tex-buf.el is not loaded yet for reasons
+;; mentioned above.
+(defcustom TeX-parse-all-errors t
+ "Whether to automatically collect all warning and errors after running TeX.
+
+If t, it makes it possible to use `TeX-previous-error' with TeX
+commands."
+ :group 'TeX-command
+ :type 'boolean)
+
+;;; Portability.
+
+(defmacro TeX--if-macro-fboundp (name then &rest else)
+ "Execute THEN if macro NAME is bound and ELSE otherwise.
+Essentially,
+
+ (TeX--if-macro-fboundp name then else...)
+
+is equivalent to
+
+ (if (fboundp \\='name) then else...)
+
+but takes care of byte-compilation issues where the byte-code for
+the latter could signal an error if it has been compiled with
+emacs 24.1 and is then later run by emacs 24.5."
+ (declare (indent 2) (debug (symbolp form &rest form)))
+ (if (fboundp name) ;If macro exists at compile-time, just use it.
+ then
+ `(if (fboundp ',name) ;Else, check if it exists at run-time.
+ (eval ',then) ;If it does, then run the then code.
+ ,@else))) ;Otherwise, run the else code.
+
+(require 'easymenu)
+
+;;; Documentation for Info-goto-emacs-command-node and similar
+
+(eval-after-load 'info '(dolist (elt '("TeX" "LaTeX" "ConTeXt" "Texinfo"
+ "docTeX"))
+ (add-to-list 'Info-file-list-for-emacs
+ (cons elt "AUCTeX"))))
+
+(advice-add 'hack-one-local-variable :after #'TeX--call-minor-mode)
+(defun TeX--call-minor-mode (var val &rest _)
+ "Call minor mode function if minor mode variable is found."
+ ;; Instead of checking for each mode explicitly `minor-mode-list'
+ ;; could be used. But this may make the byte compiler pop up.
+ (when (memq var '(TeX-PDF-mode
+ TeX-source-correlate-mode TeX-interactive-mode
+ TeX-fold-mode LaTeX-math-mode))
+ (funcall var (if (symbol-value val) 1 0))))
+
+(defvar TeX-overlay-priority-step 16
+ "Numerical difference of priorities between nested overlays.
+The step should be big enough to allow setting a priority for new
+overlays between two existing ones.")
+
+;; require crm here, because we often do
+;;
+;; (let ((crm-separator ","))
+;; (TeX-completing-read-multiple ...))
+;;
+;; which results in a void-variable error if crm hasn't been loaded before.
+(require 'crm)
+
+(if (or (and (= emacs-major-version 24) (>= emacs-minor-version 4))
+ (>= emacs-major-version 25))
+ ;; For GNU Emacs 24.4 or later, based on `completing-read-multiple' of
+ ;; git commit b14abca9476cba2f500b5eda89441d593dd0f12b
+ ;; 2013-01-10 * lisp/emacs-lisp/crm.el: Allow any regexp for separators.
+ (defun TeX-completing-read-multiple
+ (prompt table &optional predicate require-match initial-input
+ hist def inherit-input-method)
+ "Like `completing-read-multiple' which see.
+Retain zero-length substrings but ensure that empty input results
+in nil across different emacs versions."
+ (unwind-protect
+ (progn
+ (add-hook 'choose-completion-string-functions
+ #'crm--choose-completion-string)
+ (let* ((minibuffer-completion-table #'crm--collection-fn)
+ (minibuffer-completion-predicate predicate)
+ ;; see completing_read in src/minibuf.c
+ (minibuffer-completion-confirm
+ (unless (eq require-match t) require-match))
+ (crm-completion-table table)
+ (map (if require-match
+ crm-local-must-match-map
+ crm-local-completion-map))
+ ;; If the user enters empty input, `read-from-minibuffer'
+ ;; returns the empty string, not DEF.
+ (input (read-from-minibuffer
+ prompt initial-input map
+ nil hist def inherit-input-method))
+ result)
+ (and def (string-equal input "") (setq input def))
+ (if (equal (setq result (split-string input crm-separator))
+ '(""))
+ nil
+ result)))
+ (remove-hook 'choose-completion-string-functions
+ #'crm--choose-completion-string)))
+ ;; For GNU Emacs <= 24.3.
+ (defun TeX-completing-read-multiple
+ (prompt table &optional predicate require-match initial-input
+ hist def inherit-input-method)
+ "Like `completing-read-multiple' which see.
+Ensures that empty input results in nil across different emacs versions."
+ (let ((result (completing-read-multiple prompt table predicate
+ require-match initial-input
+ hist def inherit-input-method)))
+ (if (equal result '("")) nil result))))
+
+(defun TeX-read-string (prompt &optional initial-input history default-value)
+ (read-string prompt initial-input history default-value t))
+
+(defun TeX-active-mark ()
+ (and transient-mark-mode mark-active))
+
+(defun TeX-activate-region ()
+ (setq deactivate-mark nil)
+ (activate-mark))
+
+(defun TeX-overlay-prioritize (start end)
+ "Calculate a priority for an overlay extending from START to END.
+The calculated priority is lower than the minimum of priorities
+of surrounding overlays and higher than the maximum of enclosed
+overlays."
+ (let (outer-priority inner-priority ov-priority)
+ (dolist (ov (overlays-in start end))
+ (when (or (eq (overlay-get ov 'category) 'TeX-fold)
+ (overlay-get ov 'preview-state))
+ (setq ov-priority (overlay-get ov 'priority))
+ (if (>= (overlay-start ov) start)
+ (setq inner-priority (max ov-priority (or inner-priority
+ ov-priority)))
+ (setq outer-priority (min ov-priority (or outer-priority
+ ov-priority))))))
+ (cond ((and inner-priority (not outer-priority))
+ (+ inner-priority TeX-overlay-priority-step))
+ ((and (not inner-priority) outer-priority)
+ (/ outer-priority 2))
+ ((and inner-priority outer-priority)
+ (+ (/ (- outer-priority inner-priority) 2) inner-priority))
+ (t TeX-overlay-priority-step))))
+
+(defun TeX-delete-dups-by-car (alist &optional keep-list)
+ "Return a list of all elements in ALIST, but each car only once.
+Elements of KEEP-LIST are not removed even if duplicate."
+ ;; Copy of `reftex-uniquify-by-car' (written by David Kastrup).
+ (setq keep-list (TeX-sort-strings keep-list))
+ (setq alist (sort (copy-sequence alist)
+ #'TeX-car-string-lessp))
+ (let ((new alist) elt)
+ (while (cdr new)
+ (setq elt (caar new))
+ (while (and keep-list (string< (car keep-list) elt))
+ (setq keep-list (cdr keep-list)))
+ (unless (and keep-list (string= elt (car keep-list)))
+ (while (string= elt (car (cadr new)))
+ (setcdr new (cddr new))))
+ (setq new (cdr new))))
+ alist)
+
+(defun TeX-delete-duplicate-strings (list)
+ "Return a list of all strings in LIST, but each only once."
+ (setq list (TeX-sort-strings list))
+ (let ((new list) elt)
+ (while (cdr new)
+ (setq elt (car new))
+ (while (string= elt (cadr new))
+ (setcdr new (cddr new)))
+ (setq new (cdr new))))
+ list)
+
+(defun TeX-sort-strings (list)
+ "Return sorted list of all strings in LIST."
+ (sort (copy-sequence list) #'string<))
+
+(defun TeX-car-string-lessp (s1 s2)
+ "Compare the cars of S1 and S2 in lexicographic order.
+Return t if first is less than second in lexicographic order."
+ (string-lessp (car s1) (car s2)))
+
+;;; Buffer
+
+(defgroup TeX-output nil
+ "Parsing TeX output."
+ :prefix "TeX-"
+ :group 'AUCTeX)
+
+(defcustom TeX-display-help t
+ "Control type of help display when stepping through errors with \\[TeX-next-error].
+If t display help buffer. If nil display message about error in
+echo area. If `expert' display output buffer with raw processor output."
+ :group 'TeX-output
+ :type '(choice (const :tag "Help buffer" t)
+ (const :tag "Echo area" nil)
+ (const :tag "Output buffer" expert)))
+
+(defcustom TeX-debug-bad-boxes nil
+ "Non-nil means also find overfull/underfull box warnings with \\[TeX-next-error]."
+ :group 'TeX-output
+ :type 'boolean)
+
+(defcustom TeX-debug-warnings nil
+ "Non-nil means also find LaTeX or package warnings with \\[TeX-next-error]."
+ :group 'TeX-output
+ :type 'boolean)
+
+(defcustom TeX-ignore-warnings nil
+ "Controls which warnings are to be ignored.
+
+It can be either a regexp matching warnings to be ignored, or a
+symbol with the name of a custom function taking as arguments all
+the information of the warning listed in `TeX-error-list', except
+the last one about whether to ignore the warning.
+
+If you want to use the custom function, see how it is used in the
+code of `TeX-warning'."
+ :group 'TeX-command
+ :type '(choice (const :tag "Do not ignore anything" nil)
+ (string :tag "Regexp")
+ (symbol :tag "Function name")))
+
+(defcustom TeX-suppress-ignored-warnings nil
+ "Whether to actually show ignored warnings.
+
+Note that `TeX-debug-warnings' always takes the precedence."
+ :group 'TeX-command
+ :type 'boolean)
+
+(defun TeX-toggle-debug-bad-boxes ()
+ "Toggle if the debugger should display \"bad boxes\" too."
+ (interactive)
+ (setq TeX-debug-bad-boxes (not TeX-debug-bad-boxes))
+ (message (concat "TeX-debug-bad-boxes: "
+ (if TeX-debug-bad-boxes "on" "off"))))
+
+(defun TeX-toggle-debug-warnings ()
+ "Toggle if the debugger should display warnings too."
+ (interactive)
+ (setq TeX-debug-warnings (not TeX-debug-warnings))
+ (message (concat "TeX-debug-warnings: "
+ (if TeX-debug-warnings "on" "off"))))
+
+(defun TeX-toggle-suppress-ignored-warnings ()
+ "Toggle if the debugger should display ignored warnings too.
+
+See `TeX-suppress-ignored-warnings' and `TeX-ignore-warnings' for
+more details."
+ (interactive)
+ (setq TeX-suppress-ignored-warnings (not TeX-suppress-ignored-warnings))
+ (message (concat "TeX-suppress-ignored-warnings: "
+ (if TeX-suppress-ignored-warnings "on" "off"))))
+
+;;; Mode names.
+
+(defvar TeX-base-mode-name nil
+ "Base name of mode.")
+(make-variable-buffer-local 'TeX-base-mode-name)
+
+(defun TeX-set-mode-name (&optional changed local reset)
+ "Build and set the mode name.
+The base mode name will be concatenated with indicators for
+helper modes where appropriate.
+
+If CHANGED is non-nil, it indicates which global mode
+may have changed so that all corresponding buffers
+without a local value might get their name updated.
+A value of t will thus update all buffer names.
+
+If LOCAL is non-nil and CHANGED is buffer-local, only
+a local change has been performed and only the local
+name is to be updated.
+
+If RESET is non-nil, `TeX-command-next' is reset to
+`TeX-command-default' in updated buffers."
+ (if (and changed
+ (not (and local (local-variable-p changed (current-buffer)))))
+ (dolist (buffer (buffer-list))
+ (and (local-variable-p 'TeX-mode-p buffer)
+ (not (local-variable-p changed buffer))
+ (with-current-buffer buffer (TeX-set-mode-name nil nil reset))))
+ (if TeX-mode-p
+ (let ((trailing-flags
+ (concat
+ (and (boundp 'TeX-fold-mode) TeX-fold-mode "F")
+ (and (boundp 'LaTeX-math-mode) LaTeX-math-mode "M")
+ (and TeX-PDF-mode "P")
+ (and TeX-interactive-mode "I")
+ (and TeX-source-correlate-mode "S"))))
+ (setq mode-name (concat TeX-base-mode-name
+ (when (> (length trailing-flags) 0)
+ (concat "/" trailing-flags))))
+ (when reset
+ (TeX-process-set-variable (TeX-master-file)
+ 'TeX-command-next TeX-command-default)
+ (TeX-process-set-variable (TeX-region-file)
+ 'TeX-command-next TeX-command-default))
+ (set-buffer-modified-p (buffer-modified-p))))))
+
+(defun TeX-mode-prefix (&optional mode)
+ "Return the prefix for the symbol MODE as string.
+If no mode is given the current major mode is used."
+ (cdr (assoc (or mode major-mode) '((plain-tex-mode . "plain-TeX")
+ (latex-mode . "LaTeX")
+ (ams-tex-mode . "AmSTeX")
+ (doctex-mode . "docTeX")
+ (texinfo-mode . "Texinfo")
+ (context-mode . "ConTeXt")))))
+
+;;; Viewing
+
+(defgroup TeX-view nil
+ "Calling viewers from AUCTeX."
+ :group 'TeX-command)
+
+(defvar TeX-view-predicate-list-builtin
+ '((output-dvi
+ (string-match "dvi" (TeX-output-extension)))
+ (output-pdf
+ (string-match "pdf" (TeX-output-extension)))
+ (output-html
+ (string-match "html" (TeX-output-extension)))
+ (has-no-display-manager
+ (not (display-graphic-p)))
+ (style-pstricks
+ (TeX-match-style "^pstricks$\\|^pst-\\|^psfrag$"))
+ (engine-omega
+ (eq TeX-engine 'omega))
+ (engine-xetex
+ (eq TeX-engine 'xetex))
+ (mode-io-correlate
+ TeX-source-correlate-mode)
+ (paper-landscape
+ (and (fboundp 'LaTeX-match-class-option)
+ (LaTeX-match-class-option "\\`landscape\\'")))
+ (paper-portrait
+ (not (and (fboundp 'LaTeX-match-class-option)
+ (LaTeX-match-class-option "\\`landscape\\'"))))
+ (paper-a4
+ (let ((regex "\\`\\(?:a4paper\\|a4dutch\\|a4wide\\|sem-a4\\)\\'"))
+ (or (TeX-match-style regex)
+ (and (fboundp 'LaTeX-match-class-option)
+ (LaTeX-match-class-option regex)))))
+ (paper-a5
+ (let ((regex "\\`\\(?:a5paper\\|a5comb\\)\\'"))
+ (or (TeX-match-style regex)
+ (and (fboundp 'LaTeX-match-class-option)
+ (LaTeX-match-class-option regex)))))
+ (paper-b5
+ (and (fboundp 'LaTeX-match-class-option)
+ (LaTeX-match-class-option "\\`b5paper\\'")))
+ (paper-letter
+ (and (fboundp 'LaTeX-match-class-option)
+ (LaTeX-match-class-option "\\`letterpaper\\'")))
+ (paper-legal
+ (and (fboundp 'LaTeX-match-class-option)
+ (LaTeX-match-class-option "\\`legalpaper\\'")))
+ (paper-executive
+ (and (fboundp 'LaTeX-match-class-option)
+ (LaTeX-match-class-option "\\`executivepaper\\'"))))
+ "Alist of built-in predicates for viewer selection and invocation.
+See the doc string of `TeX-view-predicate-list' for a short
+description of each predicate.")
+
+(defcustom TeX-view-predicate-list nil
+ "Alist of predicates for viewer selection and invocation.
+The key of each list item is a symbol and the value a Lisp form
+to be evaluated. The form should return nil if the predicate is
+not fulfilled.
+
+Built-in predicates provided in `TeX-view-predicate-list-builtin'
+can be overwritten by defining predicates with the same symbol.
+
+The following built-in predicates are available:
+ `output-dvi': The output is a DVI file.
+ `output-pdf': The output is a PDF file.
+ `output-html': The output is an HTML file.
+ `style-pstricks': The document loads a PSTricks package.
+ `engine-omega': The Omega engine is used for typesetting.
+ `engine-xetex': The XeTeX engine is used for typesetting.
+ `mode-io-correlate': TeX Source Correlate mode is active.
+ `paper-landscape': The document is typeset in landscape orientation.
+ `paper-portrait': The document is not typeset in landscape orientation.
+ `paper-a4': The paper format is A4.
+ `paper-a5': The paper format is A5.
+ `paper-b5': The paper format is B5.
+ `paper-letter': The paper format is letter.
+ `paper-legal': The paper format is legal.
+ `paper-executive': The paper format is executive."
+ :group 'TeX-view
+ :type '(alist :key-type symbol :value-type (group sexp)))
+
+;; XXX: Atril and xreader are forks of Evince and share an almost
+;; identical interface with it. Instead of having different functions
+;; for each program, we keep the original *-evince-* functions and
+;; make them accept arguments to specify the actual name of the
+;; program and the desktop environment, that will be used to set up
+;; DBUS communication.
+
+(defun TeX-evince-dbus-p (de app &rest options)
+ "Return non-nil, if an evince-compatible reader is accessible via DBUS.
+Additional OPTIONS may be given to extend the check. If none are
+given, only the minimal requirements needed by backward search
+are checked. If OPTIONS include `:forward', which is currently
+the only option, then additional requirements needed by forward
+search are checked, too.
+
+DE is the name of the desktop environment, APP is the name of viewer."
+ (let ((dbus-debug nil))
+ (and (featurep 'dbusbind)
+ (require 'dbus nil :no-error)
+ (dbus-ignore-errors (dbus-get-unique-name :session))
+ (dbus-ping :session (format "org.%s.%s.Daemon" de app))
+ (or (not (memq :forward options))
+ (let ((spec (dbus-introspect-get-method
+ :session (format "org.%s.%s.Daemon" de app)
+ (format "/org/%s/%s/Daemon" de app)
+ (format "org.%s.%s.Daemon" de app)
+ "FindDocument")))
+ ;; FindDocument must exist, and its signature must be (String,
+ ;; Boolean, String). Evince versions between 2.30 and 2.91.x
+ ;; didn't have the Boolean spawn argument we need to start evince
+ ;; initially.
+ (and spec
+ (equal '("s" "b" "s")
+ (delq nil (mapcar (lambda (elem)
+ (when (and (listp elem)
+ (eq (car elem) 'arg))
+ (cdr (caar (cdr elem)))))
+ spec)))))))))
+
+(defun TeX-pdf-tools-sync-view ()
+ "Focus the focused page/paragraph in `pdf-view-mode'.
+If `TeX-source-correlate-mode' is disabled, only find and pop to
+the output PDF file. Used by default for the PDF Tools viewer
+entry in `TeX-view-program-list-builtin'."
+ ;; Make sure `pdf-tools' is at least in the `load-path', but the user must
+ ;; take care of properly loading and installing the package. We used to test
+ ;; "(featurep 'pdf-tools)", but that doesn't play well with deferred loading.
+ (unless (fboundp 'pdf-tools-install)
+ (error "PDF Tools are not available"))
+ (unless TeX-PDF-mode
+ (error "PDF Tools only work with PDF output"))
+ (add-hook 'pdf-sync-backward-redirect-functions
+ #'TeX-source-correlate-handle-TeX-region)
+ (if (and TeX-source-correlate-mode
+ (fboundp 'pdf-sync-forward-search))
+ (with-current-buffer (or (when TeX-current-process-region-p
+ (get-file-buffer (TeX-region-file t)))
+ (current-buffer))
+ (pdf-sync-forward-search))
+ (let ((pdf (TeX-active-master (TeX-output-extension))))
+ (pop-to-buffer (or (find-buffer-visiting pdf)
+ (find-file-noselect pdf))))))
+
+(defcustom TeX-view-evince-keep-focus nil
+ "Whether Emacs retains the focus when viewing PDF files with Evince.
+
+When calling `TeX-evince-sync-view', Evince normally captures the
+focus. If this option is set to non-nil, Emacs will retain the
+focus."
+ :group 'TeX-view
+ :type 'boolean)
+
+(defun TeX-evince-sync-view-1 (de app)
+ "Focus the focused page/paragraph in Evince with the position
+of point in emacs by using Evince's DBUS API. Used by default
+for the Evince-compatible entries in
+`TeX-view-program-list-builtin' if the requirements are met.
+
+DE is the name of the desktop environment, APP is the name of
+viewer."
+ (require 'url-util)
+ (let* ((uri (concat "file://"
+ ;; bug#45510: ? in filenames must be escaped as
+ ;; %3F to be a proper URI.
+ (replace-regexp-in-string
+ "[?]" "%3F"
+ (url-encode-url
+ (expand-file-name
+ (TeX-active-master (TeX-output-extension)))))))
+ (owner (dbus-call-method
+ :session (format "org.%s.%s.Daemon" de app)
+ (format "/org/%s/%s/Daemon" de app)
+ (format "org.%s.%s.Daemon" de app)
+ "FindDocument"
+ uri
+ t)))
+ (if owner
+ (with-current-buffer (or (when TeX-current-process-region-p
+ (get-file-buffer (TeX-region-file t)))
+ (current-buffer))
+ (dbus-call-method
+ :session owner
+ (format "/org/%s/%s/Window/0" de app)
+ (format "org.%s.%s.Window" de app)
+ "SyncView"
+ (buffer-file-name)
+ (list :struct :int32 (1+ (TeX-current-offset))
+ ;; FIXME: Using `current-column' here is dubious.
+ ;; Most of CJK letters count as occupying 2 columns,
+ ;; so the column number is not equal to the number of
+ ;; the characters counting from the beginning of a
+ ;; line. What is the right number to specify here?
+ ;; number of letters? bytes in UTF8? or other?
+ :int32 (1+ (current-column)))
+ :uint32 0)
+ (when TeX-view-evince-keep-focus
+ (select-frame-set-input-focus (selected-frame))))
+ (error "Couldn't find the %s instance for %s" (capitalize app) uri))))
+
+(defun TeX-atril-sync-view ()
+ "Run `TeX-evince-sync-view-1', which see, set up for Atril."
+ (TeX-evince-sync-view-1 "mate" "atril"))
+
+(defun TeX-evince-sync-view ()
+ "Run `TeX-evince-sync-view-1', which see, set up for Evince."
+ (TeX-evince-sync-view-1 "gnome" "evince"))
+
+(defun TeX-reader-sync-view ()
+ "Run `TeX-evince-sync-view-1', which see, set up for Xreader."
+ (TeX-evince-sync-view-1 "x" "reader"))
+
+(defun TeX-view-program-select-evince (de app)
+ "Select how to call the Evince-like viewer.
+
+DE is the name of the desktop environment, APP is the name of
+viewer."
+ (if (TeX-evince-dbus-p de app :forward)
+ (intern (format "TeX-%s-sync-view" app))
+ `(,app (mode-io-correlate
+ ;; When tex.el is loaded as response to opening a tex file
+ ;; in a non-existent directory, we need to make sure
+ ;; `default-directory' exists, otherwise the shell-command
+ ;; below will error (bug#50225).
+ ,(let ((default-directory (file-name-as-directory
+ (expand-file-name "~"))))
+ ;; With evince 3, -p N opens the page *labeled* N,
+ ;; and -i,--page-index the physical page N.
+ (if (string-match "--page-index"
+ (shell-command-to-string (concat app " --help")))
+ " -i %(outpage)"
+ " -p %(outpage)"))) " %o")))
+
+(defvar TeX-view-program-list-builtin
+ (cond
+ ((eq system-type 'windows-nt)
+ '(("Yap" ("yap -1" (mode-io-correlate " -s %n%b") " %o") "yap")
+ ("dviout" ("dviout -1 "
+ ((paper-a4 paper-portrait) "-y=A4 ")
+ ((paper-a4 paper-landscape) "-y=A4L ")
+ ((paper-a5 paper-portrait) "-y=A5 ")
+ ((paper-a5 paper-landscape) "-y=A5L ")
+ ((paper-b5 paper-portrait) "-y=E5 ")
+ ((paper-b5 paper-landscape) "-y=E5L ")
+ ((paper-b4jis paper-portrait) "-y=B4 ")
+ ((paper-b4jis paper-landscape) "-y=B4L ")
+ ((paper-b5jis paper-portrait) "-y=B5 ")
+ ((paper-b5jis paper-landscape) "-y=B5L ")
+ (paper-legal "-y=Legal ")
+ (paper-letter "-y=Letter ")
+ (paper-executive "-y=Executive ")
+ "%d" (mode-io-correlate " \"# %n '%b'\"")) "dviout")
+ ("PDF Tools" TeX-pdf-tools-sync-view)
+ ("SumatraPDF"
+ ("SumatraPDF -reuse-instance"
+ (mode-io-correlate " -forward-search \"%b\" %n") " %o")
+ "SumatraPDF")
+ ("dvips and start" "dvips %d -o && start \"\" %f" "dvips")
+ ("start" "start \"\" %o")))
+ ((eq system-type 'darwin)
+ '(("Preview.app" "open -a Preview.app %o" "open")
+ ("Skim" "open -a Skim.app %o" "open")
+ ("PDF Tools" TeX-pdf-tools-sync-view)
+ ("displayline" "displayline %n %o %b" "displayline")
+ ("open" "open %o" "open")))
+ (t
+ `(("dvi2tty" ("dvi2tty -q -w 132 %o"))
+ ("xdvi" ("%(o?)xdvi"
+ (mode-io-correlate " -sourceposition \"%n %b\" -editor \"%cS\"")
+ ((paper-a4 paper-portrait) " -paper a4")
+ ((paper-a4 paper-landscape) " -paper a4r")
+ ((paper-a5 paper-portrait) " -paper a5")
+ ((paper-a5 paper-landscape) " -paper a5r")
+ (paper-b5 " -paper b5")
+ (paper-letter " -paper us")
+ (paper-legal " -paper legal")
+ (paper-executive " -paper 7.25x10.5in")
+ " %d") "%(o?)xdvi")
+ ("dvips and gv" "%(o?)dvips %d -o && gv %f" ,(list "%(o?)dvips" "gv"))
+ ("gv" "gv %o" "gv")
+ ("xpdf" ("xpdf -remote %s -raise %o" (mode-io-correlate " %(outpage)")) "xpdf")
+ ("Evince" ,(TeX-view-program-select-evince "gnome" "evince") "evince")
+ ("Atril" ,(TeX-view-program-select-evince "mate" "atril") "atril")
+ ("Xreader" ,(TeX-view-program-select-evince "x" "reader") "xreader")
+ ("Okular" ("okular --unique %o" (mode-io-correlate "#src:%n%a")) "okular")
+ ("xdg-open" "xdg-open %o" "xdg-open")
+ ("PDF Tools" TeX-pdf-tools-sync-view)
+ ("Zathura"
+ ("zathura %o"
+ (mode-io-correlate
+ " --synctex-forward %n:0:\"%b\" -x \"emacsclient +%{line} %{input}\""))
+ "zathura"))))
+ "Alist of built-in viewer specifications.
+This variable should not be changed by the user who can use
+`TeX-view-program-list' to add new viewers or overwrite the
+definition of built-in ones. The latter variable also contains a
+description of the data format.")
+
+(defcustom TeX-view-program-list nil
+ "List of viewer specifications.
+This variable can be used to specify how a viewer is to be
+invoked and thereby add new viewers on top of the built-in list
+of viewers defined in `TeX-view-program-list-builtin' or override
+entries in the latter.
+
+The car of each item is a string with a user-readable name. The
+second element can be a command line to be run as a process or a
+Lisp function to be executed. The command line can either be
+specified as a single string or a list of strings and two-part
+lists. The first element of the two-part lists is a symbol or a
+list of symbols referring to one or more of the predicates in
+`TeX-view-predicate-list' or `TeX-view-predicate-list-builtin'.
+The second part of the two-part lists is a command line part.
+The command line for the viewer is constructed by concatenating
+the command line parts. Parts with a predicate are only
+considered if the predicate was evaluated with a positive result.
+Note that the command line can contain placeholders as defined in
+`TeX-expand-list' which are expanded before the viewer is called.
+The third element of the item is optional and is a string, or a
+list of strings, with the name of the executable, or executables,
+needed to open the output file in the viewer. Placeholders
+defined in `TeX-expand-list' can be used here. This element is
+used to check whether the viewer is actually available on the
+system.
+
+The use of a function as the second element only works if the
+View command in `TeX-command-list' makes use of the hook
+`TeX-run-discard-or-function'.
+
+Note: Predicates defined in the current Emacs session will only
+show up in the customization interface for this variable after
+restarting Emacs."
+ :group 'TeX-view
+ :type
+ `(repeat
+ (list
+ (string :tag "Name")
+ (choice
+ (group :tag "Command" (string :tag "Command"))
+ (group :inline t :tag "Command parts"
+ (repeat
+ :tag "Command parts"
+ (choice
+ (string :tag "Command part")
+ (list :tag "Predicate and command part"
+ ,(let (list)
+ ;; Build the list of available predicates.
+ (mapc (lambda (spec)
+ (cl-pushnew `(const ,(car spec)) list :test #'equal))
+ (append TeX-view-predicate-list
+ TeX-view-predicate-list-builtin))
+ ;; Sort the list alphabetically.
+ (setq list (sort list
+ (lambda (a b)
+ (string<
+ (downcase (symbol-name (cadr a)))
+ (downcase (symbol-name (cadr b)))))))
+ `(choice
+ (choice :tag "Predicate" ,@list)
+ (repeat :tag "List of predicates"
+ (choice :tag "Predicate" ,@list))))
+ (string :tag "Command part")))))
+ (group :tag "Function" function))
+ (choice :tag "Viewer executable(s)"
+ (string :tag "One executable")
+ (repeat :tag "List of executables" (string :tag "Name"))
+ (const :tag "No executable" nil)))))
+
+(defcustom TeX-view-program-selection
+ (cond
+ ((eq system-type 'windows-nt)
+ '(((output-dvi style-pstricks) "dvips and start")
+ (output-dvi "Yap")
+ (output-pdf "start")
+ (output-html "start")))
+ ((eq system-type 'darwin)
+ '((output-dvi "open")
+ (output-pdf "open")
+ (output-html "open")))
+ (t
+ '(((output-dvi has-no-display-manager) "dvi2tty")
+ ((output-dvi style-pstricks) "dvips and gv")
+ (output-dvi "xdvi")
+ (output-pdf "Evince")
+ (output-html "xdg-open"))))
+ "Alist of predicates and viewers.
+Each entry consists of a list with two elements. The first
+element is a symbol or list of symbols referring to predicates as
+defined in `TeX-view-predicate-list' or
+`TeX-view-predicate-list-builtin'. The second element is a
+string referring to the name of a viewer as defined in
+`TeX-view-program-list' or `TeX-view-program-list-builtin'.
+\(Note: Viewers added to `TeX-view-program-list' in the current
+Emacs session will not show up in the customization interface of
+`TeX-view-program-selection' until you restart Emacs.)
+
+When a viewer is called for, the entries are evaluated in turn
+and the viewer related to the first entry all predicates of which
+are evaluated positively is chosen."
+ :group 'TeX-view
+ :type `(alist :key-type
+ ;; Offer list of defined predicates.
+ ,(let (list)
+ (mapc (lambda (spec)
+ (cl-pushnew `(const ,(car spec)) list :test #'equal))
+ (append TeX-view-predicate-list
+ TeX-view-predicate-list-builtin))
+ (setq list (sort list
+ (lambda (a b)
+ (string<
+ (downcase (symbol-name (cadr a)))
+ (downcase (symbol-name (cadr b)))))))
+ `(choice (choice :tag "Single predicate" ,@list)
+ (repeat :tag "Multiple predicates"
+ (choice ,@list))))
+ :value-type
+ ;; Offer list of defined viewers.
+ (group (choice :tag "Viewer"
+ ,@(let (list)
+ (mapc (lambda (spec)
+ (cl-pushnew `(const ,(car spec))
+ list :test #'equal))
+ (append TeX-view-program-list
+ TeX-view-program-list-builtin))
+ (sort list
+ (lambda (a b)
+ (string< (downcase (cadr a))
+ (downcase (cadr b))))))))))
+
+(defun TeX-match-style (regexp)
+ "Check if a style matching REGEXP is active."
+ (TeX-member regexp (TeX-style-list) #'string-match))
+
+(defun TeX-view-match-predicate (predicate)
+ "Check if PREDICATE is true.
+PREDICATE can be a symbol or a list of symbols defined in
+`TeX-view-predicate-list-builtin' or `TeX-view-predicate-list'.
+In case of a single symbol, return t if the predicate is true,
+nil otherwise. In case of a list of symbols, return t if all
+predicates are true, nil otherwise."
+ (let ((pred-symbols (if (listp predicate) predicate (list predicate)))
+ (pred-defs (append TeX-view-predicate-list
+ TeX-view-predicate-list-builtin))
+ (result t)
+ elt)
+ (while (and (setq elt (pop pred-symbols)) result)
+ (unless (eval (cadr (assq elt pred-defs)) t)
+ (setq result nil)))
+ result))
+
+(defun TeX-view-command-raw ()
+ "Choose a viewer and return its unexpanded command string."
+ (let ((selection TeX-view-program-selection)
+ entry viewer item executable spec command)
+ ;; Find the appropriate viewer.
+ (while (and (setq entry (pop selection)) (not viewer))
+ (when (TeX-view-match-predicate (car entry))
+ (setq viewer (cadr entry))))
+ (unless viewer
+ (error "No matching viewer found"))
+ (setq item (assoc viewer (append TeX-view-program-list
+ TeX-view-program-list-builtin))
+ ;; Get the command line or function spec.
+ spec (cadr item)
+ ;; Get the name of the executable(s) associated to the viewer.
+ executable (nth 2 item))
+ ;; Check the executable exists.
+ (unless (or (null executable)
+ (cond
+ ((stringp executable)
+ (executable-find (TeX-command-expand executable)))
+ ((listp executable)
+ (catch 'notfound
+ (dolist (exec executable t)
+ (unless (executable-find (TeX-command-expand exec))
+ (throw 'notfound nil)))))))
+ (error (format "Cannot find %S viewer. \
+Select another one in `TeX-view-program-selection'" viewer)))
+ (cond ((functionp spec)
+ ;; Converting the function call to a string is ugly, but
+ ;; the backend currently only supports strings.
+ (prin1-to-string spec))
+ ((stringp spec)
+ spec)
+ ((null spec)
+ (error
+ (format "Unknown %S viewer. \
+Check the `TeX-view-program-selection' variable" viewer)))
+ (t
+ ;; Build the unexpanded command line. Pieces with predicates are
+ ;; only added if the predicate is evaluated positively.
+ (dolist (elt spec)
+ (cond ((stringp elt)
+ (setq command (concat command elt)))
+ ((listp elt)
+ (when (TeX-view-match-predicate (car elt))
+ (setq command (concat command (cadr elt)))))))
+ (if (stringp command)
+ command
+ ;; Signal an error if `command' isn't a string. This prevents an
+ ;; infinite loop in `TeX-command-expand' if `command' is nil.
+ (error "Wrong viewer specification in `TeX-view-program-list'"))))))
+
+;;; Engine
+
+(defvar TeX-engine-alist-builtin
+ '((default "Default" TeX-command LaTeX-command ConTeXt-engine)
+ (xetex "XeTeX" "xetex" "xelatex" "xetex")
+ ;; Some lualatex versions before 0.71 would use "texput" as file
+ ;; name if --jobname were not supplied
+ (luatex "LuaTeX" "luatex" "lualatex --jobname=%s" "luatex")
+ (omega "Omega" TeX-Omega-command LaTeX-Omega-command ConTeXt-Omega-engine))
+ "Alist of built-in TeX engines and associated commands.
+For a description of the format see `TeX-engine-alist'.")
+
+(defcustom TeX-engine-alist nil
+ "Alist of TeX engines and associated commands.
+Each entry is a list with a maximum of five elements. The first
+element is a symbol used to identify the engine. The second is a
+string describing the engine. The third is the command to be
+used for plain TeX. The fourth is the command to be used for
+LaTeX. The fifth is the command to be used for the --engine
+parameter of ConTeXt's texexec program. Each command can either
+be a variable or a string. An empty string or nil means there is
+no command available.
+
+You can override a built-in engine defined in the variable
+`TeX-engine-alist-builtin' by adding an entry beginning with the
+same symbol as the built-in entry to `TeX-engine-alist'."
+ :group 'TeX-command
+ :type '(repeat (group symbol
+ (string :tag "Name")
+ (choice :tag "Plain TeX command" string variable)
+ (choice :tag "LaTeX command" string variable)
+ (choice :tag "ConTeXt command" string variable))))
+
+(defun TeX-engine-alist ()
+ "Return an alist of TeX engines.
+The function appends the built-in engine specs from
+`TeX-engine-alist-builtin' and the user-defined engines from
+`TeX-engine-alist' and deletes any entries from the built-in part
+where an entry with the same car exists in the user-defined part."
+ (TeX-delete-dups-by-car (append TeX-engine-alist TeX-engine-alist-builtin)))
+
+(defun TeX-engine-in-engine-alist (engine)
+ "Return the `engine' entry in `TeX-engine-alist'.
+
+Throw an error if `engine' is not present in the alist."
+ (or
+ (assq engine (TeX-engine-alist))
+ (error "Unknown engine `%s'. Valid values are: %s" engine
+ (mapconcat
+ (lambda (x) (prin1-to-string (car x)))
+ (TeX-engine-alist) ", "))))
+
+(defcustom TeX-engine 'default
+ (concat "Type of TeX engine to use.
+It should be one of the following symbols:\n\n"
+ (mapconcat (lambda (x) (format "* `%s'" (car x)))
+ (TeX-engine-alist) "\n"))
+ :group 'TeX-command
+ :type `(choice ,@(mapcar (lambda (x)
+ `(const :tag ,(nth 1 x) ,(car x)))
+ (TeX-engine-alist))))
+(make-variable-buffer-local 'TeX-engine)
+(put 'TeX-engine 'safe-local-variable
+ (lambda (arg) (memq arg (mapcar #'car TeX-engine-alist-builtin))))
+
+(defun TeX-engine-set (type)
+ "Set TeX engine to TYPE.
+For available TYPEs, see variable `TeX-engine'."
+ (interactive (list (completing-read "Engine: "
+ (mapcar (lambda (x)
+ (symbol-name (car x)))
+ (TeX-engine-alist))
+ nil t)))
+ (when (stringp type)
+ (setq type (intern type)))
+ (setq TeX-engine type)
+ ;; Automatically enable or disable TeX PDF mode as a convenience
+ (cond ((eq type 'xetex)
+ (TeX-PDF-mode 1)
+ (setq TeX-PDF-from-DVI nil))
+ ((eq type 'omega) (TeX-PDF-mode 0))))
+
+(define-minor-mode TeX-Omega-mode
+ "Minor mode for using the Omega engine."
+ :init-value nil :lighter nil :keymap nil
+ :group 'TeX-command
+ (TeX-engine-set (if TeX-Omega-mode 'omega 'default)))
+(defalias 'tex-omega-mode #'TeX-Omega-mode)
+(make-obsolete 'TeX-Omega-mode #'TeX-engine-set "11.86")
+(make-obsolete-variable 'TeX-Omega-mode 'TeX-engine "11.86")
+
+;;; Forward and inverse search
+
+(defcustom TeX-source-correlate-method
+ '((dvi . source-specials) (pdf . synctex))
+ "Method to use for enabling forward and inverse search.
+This can be `source-specials' if source specials should be used,
+`synctex' if SyncTeX should be used, or `auto' if AUCTeX should
+decide.
+
+The previous values determine the variable for both DVI and PDF
+mode. This variable can also be an alist of the kind
+
+ ((dvi . <source-specials or synctex>)
+ (pdf . <source-specials or synctex>))
+
+in which the CDR of each entry is a symbol specifying the method
+to be used in the corresponding mode.
+
+Programs should not use this variable directly but the function
+`TeX-source-correlate-method-active' which returns the method
+actually used for forward and inverse search."
+ :type '(choice (const auto)
+ (const synctex)
+ (const source-specials)
+ (list :tag "Different method for DVI and PDF"
+ (cons (const dvi)
+ (choice :tag "Method for DVI mode"
+ (const synctex)
+ (const source-specials)))
+ (cons (const pdf)
+ (choice :tag "Method for PDF mode"
+ (const synctex)
+ (const source-specials)))))
+ :group 'TeX-view)
+
+(defvar TeX-source-correlate-output-page-function nil
+ "Symbol of function returning an output page relating to buffer position.
+The function should take no arguments and return the page numer
+as a string.")
+(make-variable-buffer-local 'TeX-source-correlate-output-page-function)
+
+(define-obsolete-variable-alias 'TeX-source-specials-view-start-server
+ 'TeX-source-correlate-start-server "11.86")
+
+(defcustom TeX-source-correlate-start-server 'ask
+ "Control if server should be started for inverse search."
+ :type '(choice (const :tag "Always" t)
+ (const :tag "Never" nil)
+ (const :tag "Ask" ask))
+ :group 'TeX-view)
+
+(defvar TeX-source-correlate-start-server-asked nil
+ "Keep track if question about server start search was asked.")
+
+(defvar TeX-source-correlate-start-server-flag nil
+ "If non-nil, `TeX-source-correlate-start-server-maybe' will start a server.
+Code related to features requiring a server, for example, for inverse
+search, can set the variable.")
+
+(defun TeX-source-correlate-gnuserv-p ()
+ "Guess whether to use gnuserv when a server is requested."
+ (cond ((and (boundp 'gnuserv-process)
+ (processp gnuserv-process)))
+ ((and (boundp 'server-process)
+ (processp server-process))
+ nil)))
+
+(defun TeX-source-correlate-server-enabled-p ()
+ "Return non-nil if Emacs server or gnuserv is enabled."
+ (let* ((gnuserv-p (TeX-source-correlate-gnuserv-p))
+ (process (if gnuserv-p 'gnuserv-process 'server-process)))
+ (and (boundp process) (processp (symbol-value process)))))
+
+(defun TeX-source-correlate-start-server-maybe ()
+ "Start Emacs server or gnuserv if a feature using it is enabled.
+This is the case if `TeX-source-correlate-start-server-flag' is non-nil."
+ (when (and TeX-source-correlate-start-server-flag
+ (not (TeX-source-correlate-server-enabled-p)))
+ (let* ((gnuserv-p (TeX-source-correlate-gnuserv-p))
+ (start (if gnuserv-p #'gnuserv-start #'server-start)))
+ (cond
+ ;; Server should be started unconditionally
+ ((eq TeX-source-correlate-start-server t)
+ (funcall start))
+ ;; Ask user if server is to be started
+ ((and (eq TeX-source-correlate-start-server 'ask)
+ (not TeX-source-correlate-start-server-asked)
+ (prog1
+ (y-or-n-p (format "Start %s for inverse search in viewer? "
+ (if gnuserv-p
+ "gnuserv"
+ "Emacs server")))
+ (setq TeX-source-correlate-start-server-asked t)))
+ (funcall start))))))
+
+(defun TeX-source-correlate-determine-method ()
+ "Determine which method is available for forward and inverse search."
+ (let ((help (condition-case nil
+ (with-output-to-string
+ (call-process LaTeX-command
+ nil (list standard-output nil) nil "--help"))
+ (error ""))))
+ (if (string-match "^[ ]*-?-synctex" help)
+ 'synctex
+ 'source-specials)))
+
+(defun TeX-source-correlate-method-active ()
+ "Return the method actually used for forward and inverse search."
+ (cond
+ ((eq TeX-source-correlate-method 'auto)
+ (TeX-source-correlate-determine-method))
+ ((listp TeX-source-correlate-method)
+ (if TeX-PDF-mode
+ (cdr (assoc 'pdf TeX-source-correlate-method))
+ (cdr (assoc 'dvi TeX-source-correlate-method))))
+ (t
+ TeX-source-correlate-method)))
+
+(defun TeX-source-correlate-expand-options ()
+ "Return TeX engine command line option for forward search facilities.
+The return value depends on the value of `TeX-source-correlate-mode'.
+If this is nil, an empty string will be returned."
+ (if TeX-source-correlate-mode
+ (if (eq (TeX-source-correlate-method-active) 'source-specials)
+ (concat TeX-source-specials-tex-flags
+ (if TeX-source-specials-places
+ ;; -src-specials=WHERE: insert source specials
+ ;; in certain places of the DVI file. WHERE is a
+ ;; comma-separated value list: cr display hbox
+ ;; math par parend vbox
+ (concat "=" (mapconcat #'identity
+ TeX-source-specials-places ","))))
+ TeX-synctex-tex-flags)
+ ""))
+
+(defvar TeX-source-correlate-map (make-sparse-keymap)
+ "Keymap for `TeX-source-correlate-mode'.
+You could use this for unusual mouse bindings.")
+
+(defun TeX-source-correlate-handle-TeX-region (file line col)
+ "Translate backward search info with respect to `TeX-region'.
+That is, if FILE is `TeX-region', update FILE to the real tex
+file and LINE to (+ LINE offset-of-region), but retain COL as is.
+Else, return nil."
+ (when (string-equal TeX-region (file-name-sans-extension
+ (file-name-nondirectory file)))
+ (with-current-buffer (or (find-buffer-visiting file)
+ (find-file-noselect file))
+ (goto-char 0)
+ ;; Same regexp used in `preview-parse-messages'. XXX: XEmacs doesn't
+ ;; support regexp classes, so we can't use "[:digit:]" here.
+ (when (re-search-forward "!offset(\\([---0-9]+\\))" nil t)
+ (let ((offset (string-to-number (match-string-no-properties 1))))
+ (when TeX-region-orig-buffer
+ (list (expand-file-name (buffer-file-name TeX-region-orig-buffer))
+ (+ line offset) col)))))))
+
+(defcustom TeX-raise-frame-function #'raise-frame
+ "A function which will be called to raise the Emacs frame.
+The function is called after `TeX-source-correlate-sync-source'
+has processed an inverse search DBUS request from
+Evince-compatible viewers in order to raise the Emacs frame.
+
+The default value is `raise-frame', however, depending on window
+manager and focus stealing policies, it might very well be that
+Emacs doesn't pop into the foreground. So you can do whatever it
+takes here.
+
+For some users, `x-focus-frame' does the trick. For some
+users (on GNOME 3.20),
+
+ (lambda ()
+ (run-at-time 0.5 nil #\\='x-focus-frame))
+
+does the trick. Some other users use the external wmctrl tool to
+raise the Emacs frame like so:
+
+ (lambda ()
+ (call-process
+ \"wmctrl\" nil nil nil \"-i\" \"-R\"
+ (frame-parameter (selected-frame) \\='outer-window-id)))"
+ :type 'function
+ :group 'TeX-view)
+
+(defun TeX-source-correlate-sync-source (file linecol &rest _ignored)
+ "Show TeX FILE with point at LINECOL.
+This function is called when emacs receives a SyncSource signal
+emitted from the Evince document viewer. IGNORED absorbs an
+unused id field accompanying the DBUS signal sent by Evince-3.0.0
+or newer.
+
+If the Emacs frame isn't raised, customize
+`TeX-raise-frame-function'."
+ ;; FILE may be given as relative path to the TeX-master root document or as
+ ;; absolute file:// URL. In the former case, the tex file has to be already
+ ;; opened.
+ (let* ((file (progn
+ (require 'url-parse)
+ (require 'url-util)
+ (url-unhex-string (aref (url-generic-parse-url file) 6))))
+ (flc (or (apply #'TeX-source-correlate-handle-TeX-region file linecol)
+ (apply #'list file linecol)))
+ (file (car flc))
+ (line (cadr flc))
+ (col (nth 2 flc)))
+ (pop-to-buffer (or (find-buffer-visiting file)
+ (find-file-noselect file)))
+ (push-mark nil 'nomsg)
+ (let ((pos
+ (when (> line 0)
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char 1)
+ (forward-line (1- line))
+ (when (> col 0)
+ (forward-char (1- col)))
+ (point))))))
+ (when pos
+ (when (or (< pos (point-min))
+ (> pos (point-max)))
+ (widen))
+ (goto-char pos))
+ (when TeX-raise-frame-function
+ (funcall TeX-raise-frame-function)))))
+
+(define-minor-mode TeX-source-correlate-mode
+ "Minor mode for forward and inverse search.
+
+If enabled, the viewer can be advised to show the output page
+corresponding to the point in the source and vice versa.
+
+The method to be used can be controlled with the variable
+`TeX-source-correlate-method'. Currently source specials or
+SyncTeX are recognized."
+ :group 'TeX-view
+ ;; Since this is a global minor mode and we don't want to require
+ ;; tex.el when the mode variable is set, the mode function is called
+ ;; explicitly (if necessary) in `VirTeX-common-initialization'. We
+ ;; do it there because otherwise `kill-all-local-variables' would
+ ;; reset `TeX-source-correlate-output-page-function' which is
+ ;; buffer-local.
+ :global t
+ (set-keymap-parent TeX-mode-map (and TeX-source-correlate-mode
+ TeX-source-correlate-map))
+ (TeX-set-mode-name 'TeX-source-correlate-mode t t)
+ (setq TeX-source-correlate-start-server-flag TeX-source-correlate-mode)
+ ;; Register Emacs for the SyncSource DBUS signal emitted by
+ ;; Evince-compatible viewers.
+ (dolist (de-app '(("gnome" "evince") ("mate" "atril") ("x" "reader")))
+ (when (TeX-evince-dbus-p (car de-app) (cadr de-app))
+ (dbus-register-signal
+ :session nil (format "/org/%s/%s/Window/0" (car de-app) (cadr de-app))
+ (format "org.%s.%s.Window" (car de-app) (cadr de-app))
+ "SyncSource"
+ #'TeX-source-correlate-sync-source))))
+
+(defalias 'TeX-source-specials-mode #'TeX-source-correlate-mode)
+(make-obsolete 'TeX-source-specials-mode 'TeX-source-correlate-mode "11.86")
+(defalias 'tex-source-correlate-mode #'TeX-source-correlate-mode)
+(put 'TeX-source-correlate-mode 'safe-local-variable #'booleanp)
+(setq minor-mode-map-alist
+ (delq (assq 'TeX-source-correlate-mode minor-mode-map-alist)
+ minor-mode-map-alist))
+
+
+;;; Source Specials
+
+(defcustom TeX-source-specials-tex-flags "-src-specials"
+ "Extra flags to pass to TeX commands to generate source specials."
+ :group 'TeX-view
+ :type 'string)
+
+(defcustom TeX-source-specials-places nil
+ "List of places where to insert source specials into the DVI file.
+If nil, use (La)TeX's defaults."
+ :group 'TeX-view
+ :type '(list (set :inline t
+ ;; :tag "Options known to work"
+ ;; cr display hbox math par parend vbox
+ (const "cr")
+ (const "display")
+ (const "hbox")
+ (const "math")
+ (const "par")
+ (const "parend")
+ (const "vbox"))
+ (repeat :inline t
+ :tag "Other options"
+ (string))))
+
+(defcustom TeX-source-specials-view-position-flags
+ "-sourceposition \"%n %b\""
+ "Flags to pass to the DVI viewer commands for the position in the source."
+ :group 'TeX-view
+ :type 'string)
+
+(defcustom TeX-source-specials-view-editor-flags
+ "-editor \"%cS\""
+ "Flags to pass to DVI viewer commands for inverse search."
+ :group 'TeX-view
+ :type 'string)
+
+(defcustom TeX-source-specials-view-gnuclient-flags
+ "-q +%%l %%f"
+ "Flags to pass to gnuclient for inverse search."
+ :group 'TeX-view
+ :type 'string)
+
+(defcustom TeX-source-specials-view-emacsclient-flags
+ "--no-wait +%%l %%f"
+ "Flags to emacsclient for inverse search."
+ :group 'TeX-view
+ :type 'string)
+
+;; FIXME: Make client binaries configurable.
+(defun TeX-source-specials-view-expand-client ()
+ "Return gnuclient or emacslient executable with options.
+Return the full path to the executable if possible."
+ (let* ((gnuserv-p (TeX-source-correlate-gnuserv-p))
+ (client-base (if gnuserv-p
+ "gnuclient"
+ "emacsclient"))
+ (client-full (and invocation-directory
+ (expand-file-name client-base
+ invocation-directory)))
+ (options (if gnuserv-p
+ TeX-source-specials-view-gnuclient-flags
+ TeX-source-specials-view-emacsclient-flags)))
+ (if (and client-full (file-executable-p client-full))
+ (concat client-full " " options)
+ (concat client-base " " options))))
+
+(defun TeX-source-specials-view-expand-options (&optional _viewer)
+ "Return source specials command line option for viewer command.
+The return value depends on the values of
+`TeX-source-correlate-mode' and
+`TeX-source-correlate-method-active'. If those are nil or not
+`source-specials' respectively, an empty string will be
+returned."
+ (if (and TeX-source-correlate-mode
+ (eq (TeX-source-correlate-method-active) 'source-specials))
+ (concat TeX-source-specials-view-position-flags
+ (when (TeX-source-correlate-server-enabled-p)
+ (concat " " TeX-source-specials-view-editor-flags)))
+ ""))
+
+;;; SyncTeX
+
+(defvar TeX-synctex-tex-flags "--synctex=1"
+ "Extra flags to pass to TeX commands to enable SyncTeX.")
+
+(defun TeX-synctex-output-page-1 (file)
+ "Return the page corresponding to the current position in FILE.
+This method assumes that the document was compiled with SyncTeX
+enabled and the `synctex' binary is available."
+ (let ((synctex-output
+ (with-output-to-string
+ (call-process "synctex" nil (list standard-output nil) nil "view"
+ "-i" (format "%s:%s:%s" (1+ (TeX-current-offset))
+ ;; FIXME: Using `current-column'
+ ;; here is dubious. See comment in
+ ;; `TeX-evince-sync-view-1'.
+ (1+ (current-column))
+ file)
+ "-o" (TeX-active-master (TeX-output-extension))))))
+ (when (string-match "^Page:\\([0-9]+\\)" synctex-output)
+ (match-string 1 synctex-output))))
+
+(defun TeX-synctex-output-page ()
+ "Return the page corresponding to the position in the current buffer.
+This method assumes that the document was compiled with SyncTeX
+enabled and the `synctex' binary is available."
+ (let* ((file (file-relative-name (buffer-file-name)
+ (file-name-directory
+ (TeX-active-master))))
+ (abs-file (concat (expand-file-name (or (file-name-directory (TeX-active-master))
+ (file-name-directory (buffer-file-name))))
+ "./" file)))
+ ;; It's known that depending on synctex version one of
+ ;; /absolute/path/./foo/bar.tex, foo/bar.tex, or ./foo/bar.tex (relative to
+ ;; TeX-master, and the "." in the absolute path is important) are needed.
+ ;; So try all variants before falling back to page 1.
+ (or (TeX-synctex-output-page-1 abs-file)
+ (TeX-synctex-output-page-1 file)
+ (TeX-synctex-output-page-1 (concat "./" file))
+ "1")))
+
+;;; Miscellaneous minor modes
+
+(defvar TeX-mode-p nil
+ "This indicates a TeX mode being active.")
+(make-variable-buffer-local 'TeX-mode-p)
+
+(defun TeX-mode-set (var value)
+ (set-default var value)
+ (TeX-set-mode-name var nil t))
+
+(defcustom TeX-PDF-mode t nil
+ :group 'TeX-command
+ :set #'TeX-mode-set
+ :type 'boolean)
+(put 'TeX-PDF-mode 'safe-local-variable #'booleanp)
+
+(define-minor-mode TeX-PDF-mode
+ "Minor mode for using PDFTeX.
+
+If enabled, PDFTeX will be used as an executable by default.
+You can customize an initial value, and you can use the
+function `TeX-global-PDF-mode' for toggling this value."
+ :group 'TeX-command
+ (when (eq TeX-engine 'omega)
+ (setq TeX-PDF-mode nil))
+ (setq TeX-PDF-mode-parsed nil)
+ (TeX-set-mode-name nil nil t)
+ (setq TeX-output-extension
+ (if TeX-PDF-mode "pdf" "dvi")))
+(add-to-list 'minor-mode-alist '(TeX-PDF-mode ""))
+
+(defun TeX-global-PDF-mode (&optional arg)
+ "Toggle default for `TeX-PDF-mode'."
+ (interactive "P")
+ (prog1
+ (setq-default TeX-PDF-mode
+ (if arg (> (prefix-numeric-value arg) 0)
+ (not (default-value 'TeX-PDF-mode))))
+ (TeX-set-mode-name 'TeX-PDF-mode nil t)))
+
+(defalias 'tex-pdf-mode #'TeX-PDF-mode)
+
+(defvar TeX-PDF-mode-parsed nil
+ "Set if `TeX-PDF-mode' has come about by parsing.")
+
+(make-variable-buffer-local 'TeX-PDF-mode-parsed)
+
+(defun TeX-PDF-mode-parsed (arg)
+ "Change `TeX-PDF-mode' to ARG based on parsing.
+If this conflicts with previous parsed settings,
+just use the default. If an explicit setting is
+already established, don't do anything."
+
+;; Basically we have the following situations:
+;; TeX-PDF-mode-parsed (local-variable-p 'TeX-PDF-mode):
+;; nil nil : virgin state
+;; nil t : stably set state (possibly because of conflicting parse info)
+;; t t : non-conflicting parsed info
+
+ (if TeX-PDF-mode-parsed
+ (unless (eq TeX-PDF-mode arg)
+ (TeX-PDF-mode (if (default-value 'TeX-PDF-mode) 1 0)))
+ (unless (local-variable-p 'TeX-PDF-mode (current-buffer))
+ (TeX-PDF-mode (if arg 1 0))
+ (setq TeX-PDF-mode-parsed t))))
+
+(defun TeX-PDF-mode-on ()
+ "Use only from parsing routines."
+ (TeX-PDF-mode-parsed t))
+
+(defun TeX-PDF-mode-off ()
+ "Use only from parsing routines."
+ (TeX-PDF-mode-parsed nil))
+
+(defcustom TeX-DVI-via-PDFTeX nil
+ "Whether to use PDFTeX also for producing DVI files."
+ :group 'TeX-command
+ :type 'boolean)
+
+(defcustom TeX-PDF-from-DVI nil
+ "Specify if and how to produce PDF output from a DVI file.
+
+If non-nil, the default compiler produces DVI output. The value
+should be the name of the command used to convert the DVI file to
+PDF or to an intermediate type.
+
+Possible values are
+
+* \"Dvips\": the DVI file is converted to PS with dvips. After
+ successfully running it, ps2pdf will be the default command to
+ convert the PS file to PDF
+* \"Dvipdfmx\": the PDF is produced with dvipdfmx
+
+Programs should not use this variable directly but the function
+`TeX-PDF-from-DVI' which handles now obsolete variable
+`TeX-PDF-via-dvips-ps2pdf'."
+ :group 'TeX-command
+ :type '(choice
+ (const :tag "No DVI to PDF conversion" nil)
+ (const :tag "dvips - ps2pdf sequence" "Dvips")
+ (const :tag "dvipdfmx" "Dvipdfmx")))
+;; If you plan to support new values of `TeX-PDF-from-DVI' remember to update
+;; `TeX-command-default' accordingly.
+(make-variable-buffer-local 'TeX-PDF-from-DVI)
+(put 'TeX-PDF-from-DVI 'safe-local-variable
+ (lambda (x) (or (stringp x) (null x))))
+
+(defcustom TeX-PDF-via-dvips-ps2pdf nil
+ "Whether to produce PDF output through the (La)TeX - dvips - ps2pdf sequence."
+ :group 'TeX-command
+ :type 'boolean)
+(make-variable-buffer-local 'TeX-PDF-via-dvips-ps2pdf)
+(put 'TeX-PDF-via-dvips-ps2pdf 'safe-local-variable #'booleanp)
+(make-obsolete-variable 'TeX-PDF-via-dvips-ps2pdf 'TeX-PDF-from-DVI "11.90")
+
+(defun TeX-PDF-from-DVI ()
+ "Return the value of variable `TeX-PDF-from-DVI'.
+
+If `TeX-PDF-from-DVI' is not set and obsolete option
+`TeX-PDF-via-dvips-ps2pdf' is non-nil, return \"Dvips\"
+for backward compatibility."
+ (cond
+ (TeX-PDF-from-DVI)
+ (TeX-PDF-via-dvips-ps2pdf
+ "Dvips")))
+
+(define-minor-mode TeX-interactive-mode
+ "Minor mode for interactive runs of TeX."
+ :init-value nil :lighter nil :keymap nil
+ :group 'TeX-command
+ (TeX-set-mode-name 'TeX-interactive-mode t t))
+(defalias 'tex-interactive-mode #'TeX-interactive-mode)
+(add-to-list 'minor-mode-alist '(TeX-interactive-mode ""))
+
+;;; Commands
+
+(defgroup TeX-command-name nil
+ "Names for external commands in AUCTeX."
+ :group 'TeX-command)
+
+(defcustom TeX-command-BibTeX "BibTeX"
+ "The name of the BibTeX entry in `TeX-command-list'."
+ :group 'TeX-command-name
+ :type 'string)
+ (make-variable-buffer-local 'TeX-command-BibTeX)
+
+(defcustom TeX-command-Biber "Biber"
+ "The name of the Biber entry in `TeX-command-list'."
+ :group 'TeX-command-name
+ :type 'string)
+ (make-variable-buffer-local 'TeX-command-Biber)
+
+(defcustom TeX-command-Show "View"
+ "The default command to show (view or print) a TeX file.
+Must be the car of an entry in `TeX-command-list'."
+ :group 'TeX-command-name
+ :type 'string)
+ (make-variable-buffer-local 'TeX-command-Show)
+
+(defcustom TeX-command-Print "Print"
+ "The name of the Print entry in `TeX-command-Print'."
+ :group 'TeX-command-name
+ :type 'string)
+
+(defcustom TeX-command-Queue "Queue"
+ "The name of the Queue entry in `TeX-command-Queue'."
+ :group 'TeX-command-name
+ :type 'string)
+
+(defvar TeX-trailer-start nil
+ "Regular expression delimiting start of trailer in a TeX file.")
+
+ (make-variable-buffer-local 'TeX-trailer-start)
+
+(defvar TeX-header-end nil
+ "Regular expression delimiting end of header in a TeX file.")
+
+ (make-variable-buffer-local 'TeX-header-end)
+
+(defvar TeX-command-default nil
+ "The default command for `TeX-command' in the current major mode.")
+
+ (make-variable-buffer-local 'TeX-command-default)
+
+(put 'TeX-command-default 'safe-local-variable #'stringp)
+
+(defvar TeX-clean-default-intermediate-suffixes
+ '("\\.aux" "\\.bbl" "\\.blg" "\\.brf" "\\.fot"
+ "\\.glo" "\\.gls" "\\.idx" "\\.ilg" "\\.ind"
+ "\\.lof" "\\.log" "\\.lot" "\\.nav" "\\.out"
+ "\\.snm" "\\.toc" "\\.url" "\\.synctex\\.gz"
+ "\\.bcf" "\\.run\\.xml" "\\.fls" "-blx\\.bib")
+ "List of regexps matching suffixes of files to be cleaned.
+Used as a default in TeX, LaTeX and docTeX mode.")
+
+(defvar TeX-clean-default-output-suffixes
+ '("\\.dvi" "\\.pdf" "\\.ps" "\\.xdv")
+ "List of regexps matching suffixes of files to be cleaned.
+Used as a default in TeX, LaTeX and docTeX mode.")
+
+(defcustom TeX-clean-confirm t
+ "If non-nil, ask before deleting files."
+ :type 'boolean
+ :group 'TeX-command)
+
+(autoload 'dired-mark-pop-up "dired")
+
+(defun TeX-clean (&optional arg)
+ "Delete generated files associated with current master and region files.
+If prefix ARG is non-nil, not only remove intermediate but also
+output files."
+ (interactive "P")
+ (let* (;; Call with output extension then remove it, to make sure we
+ ;; get the correct directory in cases TeX-output-dir is
+ ;; non-nil
+ (master (file-name-sans-extension (TeX-active-master (TeX-output-extension))))
+ (master-dir (file-name-directory master))
+ (regexp (concat "\\("
+ (regexp-quote (file-name-nondirectory master)) "\\|"
+ (regexp-quote (file-name-nondirectory (TeX-region-file nil t)))
+ "\\)"
+ "\\("
+ (TeX--clean-extensions-regexp arg)
+ "\\)\\'"
+ "\\|" (regexp-quote (file-name-nondirectory (TeX-region-file t t)))))
+ (files (when (and regexp (or (not master-dir) (file-exists-p master-dir)))
+ (directory-files (or master-dir ".") nil regexp))))
+ (if files
+ (when (or (not TeX-clean-confirm)
+ (dired-mark-pop-up " *Deletions*" 'delete
+ (if (> (length files) 1)
+ files
+ (cons t files))
+ 'y-or-n-p "Delete files? "))
+ (dolist (file files)
+ (delete-file (concat master-dir file))))
+ (message "No files to be deleted"))))
+
+(defun TeX--clean-extensions-regexp (&optional arg)
+ "Return a regexp to match extensions that should be cleaned by `TeX-clean'.
+If the optional argument ARG is non-nil then output files are
+also included in the regexp."
+ (let* ((mode-prefix (TeX-mode-prefix))
+ (suffixes (and mode-prefix
+ (append (symbol-value
+ (intern (concat mode-prefix
+ "-clean-intermediate-suffixes")))
+ (when arg
+ (symbol-value
+ (intern (concat mode-prefix
+ "-clean-output-suffixes"))))))))
+ (when suffixes
+ (mapconcat #'identity suffixes "\\|"))))
+
+;;; Master File
+
+(defcustom TeX-master t
+ "The master file associated with the current buffer.
+If the file being edited is actually included from another file, you
+can tell AUCTeX the name of the master file by setting this variable.
+If there are multiple levels of nesting, specify the top level file.
+
+If this variable is nil, AUCTeX will query you for the name.
+
+If the variable is t, AUCTeX will assume the file is a master file
+itself.
+
+If the variable is `shared', AUCTeX will query for the name, but not
+change the file.
+
+If the variable is `dwim', AUCTeX will try to avoid querying by
+attempting to `do what I mean'; and then change the file.
+
+It is suggested that you use the File Variables (see the info node
+`File Variables') to set this variable permanently for each file."
+ :group 'TeX-command
+ :group 'TeX-parse
+ :type '(choice (const :tag "Query" nil)
+ (const :tag "This file" t)
+ (const :tag "Shared" shared)
+ (const :tag "Dwim" dwim)
+ (string :format "%v")))
+(make-variable-buffer-local 'TeX-master)
+(put 'TeX-master 'safe-local-variable
+ (lambda (x)
+ (or (stringp x)
+ (member x (quote (t nil shared dwim))))))
+
+(defcustom TeX-one-master "\\.\\(texi?\\|dtx\\)$"
+ "Regular expression matching ordinary TeX files.
+
+You should set this variable to match the name of all files, where
+automatically adding a file variable with the name of the master file
+is a good idea. When AUCTeX adds the name of the master file as a
+file variable, it does not need to ask next time you edit the file.
+
+If you dislike AUCTeX automatically modifying your files, you can set
+this variable to \"<none>\"."
+ :group 'TeX-command
+ :type 'regexp)
+
+;; Can be let-bound temporarily in order to inhibit the master file question
+;; by using its value instead in case `TeX-master' is nil or 'shared.
+(defvar TeX-transient-master nil)
+
+(defun TeX-dwim-master ()
+ "Find a likely `TeX-master'."
+ (let ((dir default-directory))
+ (cl-loop for buf in (buffer-list)
+ until
+ (when (with-current-buffer buf
+ (and (equal dir default-directory)
+ (stringp TeX-master)))
+ (cl-return (with-current-buffer buf TeX-master))))))
+
+(defun TeX-master-file-ask ()
+ "Ask for master file, set `TeX-master' and add local variables."
+ (interactive)
+ (if (TeX-local-master-p)
+ (error "Master file already set")
+ (let* ((default (TeX-dwim-master))
+ (name (or (and (eq 'dwim TeX-master) default)
+ (condition-case nil
+ (read-file-name (format "Master file (default %s): "
+ (or default "this file"))
+ nil default)
+ (quit "<quit>")))))
+ (cond ((string= name "<quit>")
+ (setq TeX-master t))
+ ((string= name default)
+ (setq TeX-master default)
+ (TeX-add-local-master))
+ ((or
+ ;; Default `read-file-name' proposes and buffer visits a file.
+ (string= (expand-file-name name) (buffer-file-name))
+ ;; Default of `read-file-name' and buffer does not visit a file.
+ (string= name default-directory)
+ ;; User typed <RET> in an empty minibuffer.
+ (string= name ""))
+ (setq TeX-master t)
+ (TeX-add-local-master))
+ (t
+ (setq TeX-master (TeX-strip-extension (file-relative-name name)
+ (list TeX-default-extension)
+ 'path))
+ (TeX-add-local-master))))))
+
+(defun TeX-master-file (&optional extension nondirectory ask)
+ "Set and return the name of the master file for the current document.
+
+If optional argument EXTENSION is non-nil, add that file extension to
+the name. Special value t means use `TeX-default-extension'.
+
+If optional second argument NONDIRECTORY is non-nil, do not include
+the directory.
+
+If optional third argument ASK is non-nil, ask the user for the
+name of master file if it cannot be determined otherwise."
+ (interactive)
+ (if (eq extension t)
+ (setq extension TeX-default-extension))
+ (let ((my-name (if (buffer-file-name)
+ (TeX-strip-extension nil (list TeX-default-extension) t)
+ "<none>")))
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (cond
+ ((and TeX-transient-master
+ (or (not TeX-master) (eq TeX-master 'shared)))
+ (setq TeX-master TeX-transient-master))
+ ;; Special value 't means it is own master (a free file).
+ ((equal TeX-master my-name)
+ (setq TeX-master t))
+
+ ;; For files shared between many documents.
+ ((and (eq 'shared TeX-master) ask)
+ (setq TeX-master
+ (let* ((default (TeX-dwim-master))
+ (name (read-file-name
+ (format "Master file (default %s): "
+ (or default "this file"))
+ nil default)))
+ (cond ((string= name default)
+ default)
+ ((or
+ ;; Default `read-file-name' proposes and
+ ;; buffer visits a file.
+ (string= (expand-file-name name)
+ (buffer-file-name))
+ ;; Default of `read-file-name' and
+ ;; buffer does not visit a file.
+ (string= name default-directory)
+ ;; User typed <RET> in an empty minibuffer.
+ (string= name ""))
+ t)
+ (t
+ (TeX-strip-extension
+ name (list TeX-default-extension) 'path))))))
+
+ ;; We might already know the name.
+ ((or (eq TeX-master t) (stringp TeX-master)) TeX-master)
+
+ ;; Ask the user (but add it as a local variable).
+ (ask (TeX-master-file-ask)))))
+
+ (let ((name (if (stringp TeX-master)
+ TeX-master
+ my-name)))
+
+ (if (TeX-match-extension name)
+ ;; If it already has an extension...
+ (if (equal extension TeX-default-extension)
+ ;; Use instead of the default extension
+ (setq extension nil)
+ ;; Otherwise drop it.
+ (setq name (TeX-strip-extension name))))
+
+ (let* ((reg (TeX--clean-extensions-regexp t))
+ (is-output-ext (and reg
+ (or (string-match-p reg (concat "." extension))
+ (string= "prv" extension))))
+ (output-dir (and is-output-ext
+ (TeX--master-output-dir
+ (file-name-directory name)
+ nondirectory))))
+ (if output-dir
+ (setq name (concat output-dir (file-name-nondirectory name)))
+ ;; Remove directory if needed.
+ (if nondirectory
+ (setq name (file-name-nondirectory name)))))
+ (if extension
+ (concat name "." extension)
+ name))))
+
+(defun TeX-master-directory ()
+ "Directory of master file."
+ (file-name-as-directory
+ (abbreviate-file-name
+ (substitute-in-file-name
+ (expand-file-name
+ (let ((dir (file-name-directory (TeX-master-file))))
+ (if dir (directory-file-name dir) "."))
+ (and buffer-file-name
+ (file-name-directory buffer-file-name)))))))
+
+(defun TeX-add-local-master ()
+ "Add local variable for `TeX-master'.
+
+Get `major-mode' from master file and enable it."
+ (when (and (buffer-file-name)
+ (string-match TeX-one-master
+ (file-name-nondirectory (buffer-file-name)))
+ (not buffer-read-only))
+ (goto-char (point-max))
+ (if (re-search-backward "^\\([^\n]+\\)Local Variables:"
+ (- (point-max) 3000) t)
+ (let ((prefix (TeX-match-buffer 1)))
+ (re-search-forward (regexp-quote (concat prefix
+ "End:")))
+ (beginning-of-line 1)
+ (insert prefix "TeX-master: " (prin1-to-string TeX-master) "\n"))
+ (let* ((mode (if (stringp TeX-master)
+ (with-current-buffer
+ (find-file-noselect
+ (TeX-master-file TeX-default-extension))
+ major-mode)
+ major-mode))
+ (comment-prefix (cond ((eq mode 'texinfo-mode) "@c ")
+ ((eq mode 'doctex-mode) "% ")
+ (t "%%% ")))
+ (mode-string (concat (and (boundp 'japanese-TeX-mode) japanese-TeX-mode
+ "japanese-")
+ (substring (symbol-name mode) 0 -5))))
+ (newline)
+ (when (eq major-mode 'doctex-mode)
+ (insert comment-prefix TeX-esc "endinput\n"))
+ (insert
+ comment-prefix "Local Variables:\n"
+ comment-prefix "mode: " mode-string "\n"
+ comment-prefix "TeX-master: " (prin1-to-string TeX-master) "\n"
+ comment-prefix "End:\n")
+ (unless (eq mode major-mode)
+ (funcall mode)
+ ;; TeX modes run `VirTeX-common-initialization' which kills all local
+ ;; variables, thus `TeX-master' will be forgotten after `(funcall
+ ;; mode)'. Reparse local variables in order to bring it back.
+ (hack-local-variables))))))
+
+(defun TeX-local-master-p ()
+ "Return non-nil if there is a `TeX-master' entry in local variables spec.
+Return nil otherwise."
+ (assq 'TeX-master file-local-variables-alist))
+
+;;; Style Paths
+
+(defcustom TeX-style-global (expand-file-name "style" TeX-data-directory)
+ "Directory containing hand generated TeX information.
+
+These correspond to TeX macros shared by all users of a site."
+ :group 'TeX-file
+ :type 'directory)
+
+(defcustom TeX-auto-local "auto"
+ "Directory containing automatically generated TeX information.
+
+This correspond to TeX macros found in the current directory, and must
+be relative to that."
+ :group 'TeX-file
+ :type 'string)
+
+(defcustom TeX-output-dir nil
+ "The path of the directory where output files should be placed.
+
+A relative path is interpreted as being relative to the master
+file in `TeX-master'. The path cannot contain a directory that
+starts with '.'. If this variable is nil, the output directory
+is assumed to be the same as the directory of `TeX-master'."
+ :group 'TeX-file
+ :safe #'string-or-null-p
+ :type '(choice (const :tag "Directory of master file" nil)
+ (string :tag "Custom" "build")))
+(make-variable-buffer-local 'TeX-output-dir)
+
+(defun TeX--master-output-dir (master-dir relative-to-master &optional ensure)
+ "Return the directory path where output files should be placed.
+If `TeX-output-dir' is nil, then return nil.
+
+MASTER-DIR is the directory path where the master file is
+located. If RELATIVE-TO-MASTER is non-nil, make the returned
+path relative to the directory in MASTER-DIR. If ENSURE is
+non-nil, the output directory is created if it does not exist."
+ (when TeX-output-dir
+ (let* ((master-dir (expand-file-name (or master-dir "")))
+ (out-dir (file-name-as-directory
+ (abbreviate-file-name
+ (substitute-in-file-name
+ (expand-file-name
+ TeX-output-dir
+ master-dir))))))
+ ;; Make sure the directory exists
+ (unless (or (not ensure) (file-exists-p out-dir))
+ (make-directory (file-name-as-directory out-dir) t))
+ (if relative-to-master
+ (file-relative-name out-dir master-dir)
+ out-dir))))
+
+(defun TeX--output-dir-arg (argname)
+ "Format the output directory as a command argument.
+ARGNAME is prepended to the quoted output directory. If
+`TeX-output-dir' is nil then return an empty string."
+ (let ((out-dir (TeX--master-output-dir (TeX-master-directory) t t)))
+ (if out-dir
+ (concat argname "\"" out-dir "\"")
+ "")))
+
+(defcustom TeX-style-local "style"
+ "Directory containing hand generated TeX information.
+
+These correspond to TeX macros found in the current directory, and must
+be relative to that."
+ :group 'TeX-file
+ :type 'string)
+
+;; Compatibility alias
+(defun TeX-split-string (regexp string)
+ (split-string string regexp))
+(make-obsolete 'TeX-split-string
+ "use (split-string STRING REGEXP) instead." "AUCTeX 13.0")
+
+(defun TeX-parse-path (env)
+ "Return a list if private TeX directories found in environment variable ENV."
+ (let* ((value (getenv env))
+ (entries (and value
+ (split-string
+ value
+ (if (string-match ";" value) ";" ":"))))
+ (global (append '("/" "\\")
+ (mapcar #'file-name-as-directory
+ TeX-macro-global)))
+ entry
+ answers)
+ (while entries
+ (setq entry (car entries))
+ (setq entries (cdr entries))
+ (setq entry (file-name-as-directory
+ (if (string-match "/?/?\\'" entry)
+ (substring entry 0 (match-beginning 0))
+ entry)))
+ (or (not (file-name-absolute-p entry))
+ (member entry global)
+ (setq answers (cons entry answers))))
+ answers))
+
+(defun TeX-kpathsea-detect-path-delimiter ()
+ "Auto detect the path delimiter for kpsewhich command.
+Usually return \":\" or \";\". If auto detect fails for some reason,
+return nil."
+ (let ((res (ignore-errors
+ (with-output-to-string
+ (call-process "kpsewhich" nil
+ (list standard-output nil) nil
+ "--expand-path" "{.,..}")))))
+ ;; kpsewhich expands "{.,..}" to ".:SOMEDIR" or ".;SOMEDIR"
+ ;; according to its environment.
+ ;; Don't use "{.,.}" instead because kpsewhich of MiKTeX 2.9
+ ;; simplifies it to just a ".", not ".;.".
+ (and (stringp res) (> (length res) 0)
+ ;; Check whether ; is contained. This should work even if
+ ;; some implementation of kpsewhich considers it sane to
+ ;; insert drive letters or directory separators or whatever
+ ;; else to the current directory.
+ (if (string-match ";" res) ";" ":"))))
+
+(defcustom TeX-kpathsea-path-delimiter
+ (TeX-kpathsea-detect-path-delimiter)
+ "Path delimiter for kpathsea output.
+t means autodetect, nil means kpathsea is disabled."
+ :group 'TeX-file
+ :type '(choice (const ":")
+ (const ";")
+ (const :tag "Autodetect" t)
+ (const :tag "Off" nil)))
+
+(defun TeX-tree-expand (vars program &optional subdirs)
+ "Return directories corresponding to the kpathsea variables VARS.
+This is done calling `kpsewhich --expand-path' for the variables.
+PROGRAM if non-nil is passed as the parameter for --progname.
+Optional argument SUBDIRS are subdirectories which are appended
+to the directories of the TeX trees. Only existing directories
+are returned."
+ ;; FIXME: The GNU convention only uses "path" to mean "list of directories"
+ ;; and uses "filename" for the name of a file even if it contains possibly
+ ;; several elements separated by "/".
+ (if (eq TeX-kpathsea-path-delimiter t)
+ (setq TeX-kpathsea-path-delimiter
+ (TeX-kpathsea-detect-path-delimiter)))
+ (when TeX-kpathsea-path-delimiter
+ (let* ((exit-status 1)
+ (args `(,@(if program `("--progname" ,program))
+ "--expand-path"
+ ,(mapconcat #'identity vars
+ TeX-kpathsea-path-delimiter)))
+ (path-list (ignore-errors
+ (with-output-to-string
+ (setq exit-status
+ (apply #'call-process
+ "kpsewhich" nil
+ (list standard-output nil) nil
+ args))))))
+ (if (not (zerop exit-status))
+ ;; kpsewhich is not available. Disable subsequent usage.
+ (setq TeX-kpathsea-path-delimiter nil)
+ (let ((separators (format "[\n\r%s]" TeX-kpathsea-path-delimiter))
+ path input-dir-list)
+ (dolist (item (split-string path-list separators t))
+ (if subdirs
+ (dolist (subdir subdirs)
+ (setq path (file-name-as-directory (concat item subdir)))
+ (when (file-exists-p path)
+ (cl-pushnew path input-dir-list :test #'equal)))
+ (setq path (file-name-as-directory item))
+ (when (file-exists-p path)
+ (cl-pushnew path input-dir-list :test #'equal))))
+ ;; No duplication in result is assured since `cl-pushnew' is
+ ;; used above. Should we introduce an option for speed just
+ ;; to accumulate all the results without care for
+ ;; duplicates?
+ (nreverse input-dir-list))))))
+
+(defun TeX-macro-global ()
+ "Return directories containing the site's TeX macro and style files."
+ (or (TeX-tree-expand '("$SYSTEXMF" "$TEXMFLOCAL" "$TEXMFMAIN" "$TEXMFDIST")
+ "latex" '("/tex/" "/bibtex/bst/"))
+ '("/usr/share/texmf/tex/" "/usr/share/texmf/bibtex/bst/")))
+
+(defun TeX-macro-private ()
+ "Return directories containing the user's TeX macro and style files."
+ (TeX-tree-expand '("$TEXMFHOME") "latex" '("/tex/" "/bibtex/bst/")))
+
+(defcustom TeX-macro-global (TeX-macro-global)
+ "Directories containing the site's TeX macro and style files."
+ :group 'TeX-file
+ :type '(repeat (directory :format "%v")))
+
+(defcustom TeX-macro-private (or (append (TeX-parse-path "TEXINPUTS")
+ (TeX-parse-path "BIBINPUTS"))
+ (TeX-macro-private))
+ "Directories where you store your personal TeX macros."
+ :group 'TeX-file
+ :type '(repeat (file :format "%v")))
+
+(defcustom TeX-auto-private
+ (list (expand-file-name TeX-auto-local
+ (or (concat user-emacs-directory "auctex/")
+ "~/.emacs.d/auctex/")))
+ "List of directories containing automatically generated AUCTeX style files.
+
+These correspond to the personal TeX macros."
+ :group 'TeX-file
+ :type '(repeat (file :format "%v")))
+
+(if (stringp TeX-auto-private) ;Backward compatibility
+ (setq TeX-auto-private (list TeX-auto-private)))
+
+(defcustom TeX-style-private
+ (list (expand-file-name TeX-style-local
+ (or (concat user-emacs-directory "auctex/")
+ "~/.emacs.d/auctex/")))
+ "List of directories containing hand-generated AUCTeX style files.
+
+These correspond to the personal TeX macros."
+ :group 'TeX-file
+ :type '(repeat (file :format "%v")))
+
+(if (stringp TeX-style-private) ;Backward compatibility
+ (setq TeX-style-private (list TeX-style-private)))
+
+(defcustom TeX-style-path
+ (let ((path))
+ ;; Put directories in an order where the more local files can
+ ;; override the more global ones.
+ (mapc (lambda (file)
+ (when (and file (not (member file path)))
+ (setq path (cons file path))))
+ (append (list TeX-auto-global TeX-style-global)
+ TeX-auto-private TeX-style-private
+ (list TeX-auto-local TeX-style-local)))
+ (nreverse path))
+ "List of directories to search for AUCTeX style files.
+Per default the list is built from the values of the variables
+`TeX-auto-global', `TeX-style-global', `TeX-auto-private',
+`TeX-style-private', `TeX-auto-local', and `TeX-style-local'."
+ :group 'TeX-file
+ :type '(repeat (file :format "%v")))
+
+(defcustom TeX-check-path
+ (append (list ".") TeX-macro-private TeX-macro-global)
+ "Directory path to search for dependencies.
+
+If nil, just check the current file.
+Used when checking if any files have changed."
+ :group 'TeX-file
+ :type '(repeat (file :format "%v")))
+
+;;; Style Files
+
+(define-obsolete-variable-alias 'LaTeX-dialect 'TeX-dialect "13.0")
+(defconst TeX-dialect :latex
+ "Default dialect for use with function `TeX-add-style-hook' for
+argument DIALECT-EXPR when the hook is to be run only on LaTeX
+file, or any mode derived thereof. See variable
+`TeX-style-hook-dialect'." )
+
+(defvar TeX-style-hook-list nil
+ "List of TeX style hooks currently loaded.
+
+Each entry is a list:
+
+ (STYLE HOOK1 HOOK2 ...)
+
+where the first element STYLE is the name of the style, and the
+remaining elements HOOKN, if any, are hooks to be run when that
+style is active.
+
+A hook HOOKN may be a hook function HOOK-FUN to be run in
+all TeX dialects (LaTeX, Texinfo, etc.), or a vector like:
+
+ [TeX-style-hook HOOK-FUN DIALECT-SET]
+
+where HOOK-FUN is the hook function to be run, and DIALECT-SET is
+a non-empty set of dialects in which the hook function may be
+run.
+
+This set is instantiated by function `TeX-add-style-hook' through
+functions manipulating style hook dialect expression named with a
+`TeX-shdex-' prefix.
+
+For supported dialects, see variables `TeX-style-hook-dialect'.")
+
+(defvar TeX-style-hook-dialect :latex
+ "Dialect for running hooks locally to the considered file.
+Supported values are described below:
+
+* `:bibtex' for files in BibTeX mode.
+* `:context' for files in ConTeXt mode.
+* `:latex' for files in LaTeX mode, or any mode derived
+ thereof.
+* `:plain-tex' for files in plain-TeX mode.
+* `:texinfo' for Texinfo files.
+* `:classopt' for class options of LaTeX document. Just
+ considered as a pseudo-dialect.
+
+Purpose is notably to prevent non-Texinfo hooks to be run in
+Texinfo files, due to ambiguous style name, as this may cause bad
+side effect for example on variable `TeX-font-list'.")
+
+(defcustom TeX-byte-compile nil
+ "Not nil means try to byte compile auto files before loading."
+ :group 'TeX-parse
+ :type 'boolean)
+
+(defun TeX-bibtex-set-BibTeX-dialect ()
+ "Set `TeX-style-hook-dialect' to `:bibtex' locally to BibTeX buffers."
+ (set (make-local-variable 'TeX-style-hook-dialect) :bibtex))
+
+(defun TeX-load-style (style)
+ "Search for and load each definition for STYLE in `TeX-style-path'."
+ (cond ((assoc style TeX-style-hook-list)) ; We already found it
+ ((string-match "\\`\\(.+[/\\]\\)\\([^/\\]*\\)\\'" style) ;Complex path
+ (let* ((dir (substring style (match-beginning 1) (match-end 1)))
+ (style (substring style (match-beginning 2) (match-end 2)))
+ (master-dir (if (stringp TeX-master)
+ (file-name-directory
+ (file-relative-name TeX-master))
+ "./"))
+ (TeX-style-path (append (list (expand-file-name
+ TeX-auto-local dir)
+ (expand-file-name
+ TeX-auto-local master-dir)
+ (expand-file-name
+ TeX-style-local dir)
+ (expand-file-name
+ TeX-style-local master-dir))
+ TeX-style-path)))
+ (TeX-load-style style)))
+ (t ;Relative path
+ ;; Insert empty list to mark the fact that we have searched.
+ (setq TeX-style-hook-list (cons (list style) TeX-style-hook-list))
+ ;; Now check each element of the path
+ (dolist (name TeX-style-path)
+ (TeX-load-style-file (expand-file-name style name))))))
+
+(defun TeX-load-style-file (file)
+ "Load FILE checking for a Lisp extensions."
+ (let ((el (concat file ".el"))
+ (elc (concat file ".elc")))
+ (cond ((file-newer-than-file-p el elc)
+ (if (file-readable-p el)
+ (if (and TeX-byte-compile
+ (file-writable-p elc)
+ (save-excursion
+ ;; `byte-compile-file' switches buffer in Emacs 20.3.
+ (byte-compile-file el))
+ (file-readable-p elc))
+ (load-file elc)
+ (load-file el))))
+ ((file-readable-p elc)
+ (load-file elc))
+ ((file-readable-p el)
+ (load-file el)))))
+
+(defconst TeX-style-hook-dialect-weight-alist
+ '((:latex . 1) (:texinfo . 2) (:bibtex . 4) (:plain-tex . 8) (:context . 16)
+ (:classopt . 32))
+ "Association list to map dialects to binary weight, in order to
+implement dialect sets as bitmaps." )
+
+(defun TeX-shdex-eval (dialect-expr)
+ "Evaluate a style hook dialect expression DIALECT-EXPR."
+ (cond
+ ((symbolp dialect-expr)
+ (let ((cell (assq dialect-expr TeX-style-hook-dialect-weight-alist)))
+ (if cell (cdr cell)
+ (error "Invalid dialect expression : %S" dialect-expr))))
+ ((and (consp dialect-expr)
+ (memq (car dialect-expr) '(or not and nor)))
+ (apply (intern
+ (concat "TeX-shdex-" (symbol-name (car dialect-expr))))
+ (cdr dialect-expr)))
+ (t
+ (error "Invalid dialect expression : %S" dialect-expr))))
+
+(defsubst TeX-shdex-or (&rest args)
+ "OR operator for style hook dialect expressions."
+ (apply #'logior (mapcar #'TeX-shdex-eval args)))
+
+(defsubst TeX-shdex-and (&rest args)
+ "AND operator for style hook dialect expressions."
+ (apply #'logand (mapcar #'TeX-shdex-eval args)))
+
+(defsubst TeX-shdex-nor (&rest args)
+ "NOR operator for style hook dialect expressions."
+ (lognot (apply #'TeX-shdex-or args)))
+
+(defsubst TeX-shdex-not (arg)
+ "NOT operator for style hook dialect expressions."
+ (lognot (TeX-shdex-eval arg)))
+
+(defsubst TeX-shdex-in-p (dialect dialect-set)
+ "Test whether dialect DIALECT is in dialect set DIALECT-SET."
+ (let ((cell (assq dialect TeX-style-hook-dialect-weight-alist)))
+ (if cell
+ (/= 0 (logand (cdr cell) dialect-set))
+ (error "Invalid dialect %S" dialect))))
+
+(defsubst TeX-shdex-listify (dialect-set)
+ "Converts a dialect set DIALECT-SET to a list of all dialect
+comprised in this set, where dialects are symbols"
+ (let (ret)
+ (dolist (c dialect-set)
+ (when (/= 0 (logand (cdr c) dialect-set))
+ (push (car c) ret)))
+ ret))
+
+(defun TeX-add-style-hook (style hook &optional dialect-expr)
+ "Give STYLE yet another HOOK to run.
+
+DIALECT-EXPR serves the purpose of marking the hook to be run only in
+that dicontext.
+
+DIALECT-EXPR may be a single symbol defining the dialect, see
+variable `TeX-style-hook-dialect' for supported dialects.
+
+DIALECT-EXPR can also be an expression like one of the following:
+
+* (or DIALECT1 DIALECT2 ...)
+* (nor DIALECT1 DIALECT2 ...)
+* (and DIALECT1 DIALECT2 ...)
+* (not DIALECT )
+
+When omitted DIALECT-EXPR is equivalent to `(nor )', ie all
+dialected are allowed."
+ (let ((entry (assoc-string style TeX-style-hook-list)))
+ (and dialect-expr (setq hook (vector 'TeX-style-hook hook
+ (TeX-shdex-eval dialect-expr))))
+ (cond ((null entry)
+ ;; New style, add entry.
+ (setq TeX-style-hook-list (cons (list style hook)
+ TeX-style-hook-list)))
+ ((member hook entry)
+ ;; Old style, hook already there, do nothing.
+ nil)
+ (t
+ ;; Old style, new hook.
+ (setcdr entry (cons hook (cdr entry)))))))
+
+(defun TeX-keep-hooks-in-dialect (hooks dialect-list)
+ "Scan HOOKS for all hooks the associated dialect of which is
+found in DIALECT-LIST and return the list thereof."
+ (let (ret dialect-list-1)
+ (dolist (hook hooks)
+ (setq dialect-list-1 (and (vectorp hook) (eq (aref hook 0) 'TeX-style-hook)
+ (TeX-shdex-listify (aref hook 2))))
+ (while dialect-list-1
+ (when (memq (pop dialect-list-1) dialect-list)
+ (push hook ret)
+ (setq dialect-list-1 nil)))
+ ret)))
+
+(defun TeX-unload-style (style &optional dialect-list)
+ "Forget that we once loaded STYLE. If DIALECT-LIST is provided
+the STYLE is only removed for those dialects in DIALECT-LIST.
+
+See variable `TeX-style-hook-dialect' for supported dialects."
+ (let ((style-data (assoc-string style TeX-style-hook-list)))
+ (if style-data
+ (let ((hooks (and dialect-list (TeX-keep-hooks-in-dialect (cdr style-data) dialect-list))))
+ (if hooks
+ (setcdr style-data hooks)
+ (setq TeX-style-hook-list (delq style-data TeX-style-hook-list)))))))
+
+(defcustom TeX-virgin-style (if (and TeX-auto-global
+ (file-directory-p TeX-auto-global))
+ "virtex"
+ "NoVirtexSymbols")
+ "Style all documents use."
+ :group 'TeX-parse
+ :type 'string)
+
+(defvar TeX-active-styles nil
+ "List of styles currently active in the document.")
+ (make-variable-buffer-local 'TeX-active-styles)
+
+(defun TeX-run-style-hooks (&rest styles)
+ "Run the TeX style hooks STYLES."
+ (mapcar (lambda (style)
+ ;; Avoid recursion.
+ (unless (TeX-member style TeX-active-styles #'string-equal)
+ (setq TeX-active-styles
+ (cons style TeX-active-styles))
+ (TeX-load-style style)
+ (let ((default-directory default-directory))
+ ;; Complex path.
+ (when (string-match "\\`\\(.+[/\\]\\)\\([^/\\]*\\)\\'" style)
+ ;; Set `default-directory' to directory of master
+ ;; file since style files not stored in the fixed
+ ;; style directories are usually located there.
+ (setq default-directory (save-match-data
+ (TeX-master-directory))
+ style (substring style
+ (match-beginning 2) (match-end 2))))
+ (condition-case nil
+ (mapcar (lambda (hook)
+ (cond
+ ((functionp hook)
+ (funcall hook))
+ ((and (vectorp hook)
+ (eq (aref hook 0) 'TeX-style-hook))
+ (and (TeX-shdex-in-p TeX-style-hook-dialect (aref hook 2))
+ (funcall (aref hook 1))))
+ (t (error "Invalid style hook %S" hook))))
+ ;; Reverse the list of style hooks in order to run
+ ;; styles in the order global, private, local
+ ;; (assuming TeX-style-path has that ordering,
+ ;; too).
+ (reverse (cdr-safe (assoc-string style TeX-style-hook-list))))
+ ;; This happens in case some style added a new parser, and
+ ;; now the style isn't used anymore (user deleted
+ ;; \usepackage{style}). Then we're left over with, e.g.,
+ ;; (LaTeX-add-siunitx-units "\\parsec"), but the function is
+ ;; defined in a style siunitx.el that's not loaded anymore.
+ (void-function nil)))))
+ styles))
+
+(defcustom TeX-parse-self nil
+ "Parse file after loading it if no style hook is found for it."
+ :group 'TeX-parse
+ :type 'boolean)
+
+(defvar TeX-style-hook-applied-p nil
+ "Non-nil means the style specific hooks have been applied.")
+ (make-variable-buffer-local 'TeX-style-hook-applied-p)
+
+(defvar TeX-update-style-hook nil
+ "Hook run as soon as style specific hooks were applied.")
+
+(defun TeX-update-style (&optional force)
+ "Run style specific hooks for the current document.
+
+Only do this if it has not been done before, or if optional argument
+FORCE is not nil."
+ (unless (or (eq major-mode 'bibtex-mode) ; Not a real TeX buffer
+ (and (not force)
+ TeX-style-hook-applied-p))
+ (setq TeX-style-hook-applied-p t)
+ (message "Applying style hooks...")
+ (TeX-run-style-hooks (TeX-strip-extension nil nil t))
+ ;; Run parent style hooks if it has a single parent that isn't itself.
+ (if (or (not (memq TeX-master '(nil t)))
+ (and (buffer-file-name)
+ (string-match TeX-one-master
+ (file-name-nondirectory (buffer-file-name)))))
+ (TeX-run-style-hooks (TeX-master-file)))
+ (if (and TeX-parse-self
+ (null (cdr-safe (assoc (TeX-strip-extension nil nil t)
+ TeX-style-hook-list))))
+ (TeX-auto-apply))
+ (run-hooks 'TeX-update-style-hook)
+ (message "Applying style hooks...done")))
+
+(defvar TeX-remove-style-hook nil
+ "List of hooks to call when we remove the style specific information.")
+
+(defun TeX-remove-style ()
+ "Remove all style specific information."
+ (setq TeX-style-hook-applied-p nil)
+ (run-hooks 'TeX-remove-style-hook)
+ (setq TeX-active-styles (list TeX-virgin-style)))
+
+(defun TeX-style-list ()
+ "Return a list of all styles (subfiles) used by the current document."
+ (TeX-update-style)
+ TeX-active-styles)
+
+;;; Special Characters
+
+(defvar TeX-esc "\\" "The TeX escape character.")
+ (make-variable-buffer-local 'TeX-esc)
+
+(defvar TeX-grop "{" "The TeX group opening character.")
+ (make-variable-buffer-local 'TeX-grop)
+
+(defvar TeX-grcl "}" "The TeX group closing character.")
+ (make-variable-buffer-local 'TeX-grcl)
+
+;;; Symbols
+
+;; Must be before keymaps.
+
+(defgroup TeX-macro nil
+ "Support for TeX macros in AUCTeX."
+ :prefix "TeX-"
+ :group 'AUCTeX)
+
+(defcustom TeX-complete-word #'ispell-complete-word
+ "Function to call for completing non-macros in `tex-mode'."
+ :type 'function
+ :group 'TeX-macro)
+
+(defcustom TeX-complete-expert-commands nil
+ "Complete macros and environments marked as expert commands.
+
+Possible values are nil, t, or a list of style names.
+
+ - nil Don't complete expert commands (default).
+ - t Always complete expert commands.
+ - (STYLES ...) Only complete expert commands of STYLES."
+ :group 'TeX-macro
+ :type '(choice (const :tag "Don't complete expert commands" nil)
+ (const :tag "Always complete expert commands" t)
+ (repeat :tag "Complete expert commands of certain styles" string)))
+
+(defmacro TeX-complete-make-expert-command-functions (thing list-var prefix)
+ (let* ((plural (concat thing "s"))
+ (upcase-plural (upcase plural))
+ (table-var (intern (format "%s-expert-%s-table" prefix thing))))
+ `(progn
+ (defvar ,table-var
+ (make-hash-table :test #'equal)
+ ,(format "A hash-table mapping %s names to the style name providing it.
+
+A %s occuring in this table is considered an expert %s and
+treated specially in the completion." thing thing thing))
+
+ (defun ,(intern (format "%s-declare-expert-%s" prefix plural)) (style &rest ,(intern plural))
+ ,(format "Declare %s as expert %s of STYLE.
+
+Expert %s are completed depending on `TeX-complete-expert-commands'."
+ upcase-plural plural plural)
+ (dolist (x ,(intern plural))
+ (if (null style)
+ (remhash x ,table-var)
+ (puthash x style ,table-var))))
+
+ (defun ,(intern (format "%s-filtered" list-var)) ()
+ ,(format "Filter (%s) depending on `TeX-complete-expert-commands'."
+ list-var)
+ (delq nil
+ (mapcar
+ (lambda (entry)
+ (if (eq t TeX-complete-expert-commands)
+ entry
+ (let* ((cmd (car entry))
+ (style (gethash cmd ,table-var)))
+ (when (or (null style)
+ (member style TeX-complete-expert-commands))
+ entry))))
+ (,list-var)))))))
+
+(TeX-complete-make-expert-command-functions "macro" TeX-symbol-list "TeX")
+(TeX-complete-make-expert-command-functions "environment" LaTeX-environment-list "LaTeX")
+
+(defvar TeX-complete-list nil
+ "List of ways to complete the preceding text.
+
+Each entry is a list with the following elements:
+
+0. Regexp matching the preceding text or a predicate of arity 0
+which returns non-nil and sets `match-data' appropriately if it
+is applicable.
+1. A number indicating the subgroup in the regexp containing the
+text.
+2. A function returning an alist of possible completions.
+3. Text to append after a succesful completion.
+
+Or alternatively:
+
+0. Regexp matching the preceding text.
+1. Function to do the actual completion.")
+
+(defun TeX--complete-find-entry ()
+ "Return the first applicable entry of `TeX-complete-list'."
+ (let ((list TeX-complete-list)
+ entry)
+ (while list
+ (setq entry (car list)
+ list (cdr list))
+ (when (if (functionp (car entry))
+ (funcall (car entry))
+ (TeX-looking-at-backward (car entry) 250))
+ (setq list nil)))
+ entry))
+
+(defun TeX-complete-symbol ()
+ "Perform completion on TeX/LaTeX symbol preceding point."
+ (interactive "*")
+ (let ((entry (TeX--complete-find-entry)))
+ (when entry
+ (if (numberp (nth 1 entry))
+ (let* ((sub (nth 1 entry))
+ (close (if (and (nth 3 entry)
+ (listp (nth 3 entry))
+ (symbolp (car (nth 3 entry))))
+ (eval (nth 3 entry) t)
+ (nth 3 entry)))
+ (begin (match-beginning sub))
+ (end (match-end sub))
+ (pattern (TeX-match-buffer 0))
+ (symbol (buffer-substring begin end))
+ (list (funcall (nth 2 entry)))
+ (completion (try-completion symbol list))
+ (buf-name "*Completions*"))
+ (cond ((eq completion t)
+ (and close
+ (not (looking-at (regexp-quote close)))
+ (insert close))
+ (let ((window (get-buffer-window buf-name)))
+ (when window (delete-window window))))
+ ((null completion)
+ (error "Can't find completion for \"%s\"" pattern))
+ ((not (string-equal symbol completion))
+ (delete-region begin end)
+ (insert completion)
+ (and close
+ (eq (try-completion completion list) t)
+ (not (looking-at (regexp-quote close)))
+ (insert close))
+ (let ((window (get-buffer-window buf-name)))
+ (when window (delete-window window))))
+ (t
+ (completion-in-region begin end
+ (all-completions symbol list nil)))))
+ (funcall (nth 1 entry))))))
+
+(defun TeX--completion-annotation-from-tex--prettify-symbols-alist (sym)
+ (when (boundp 'tex--prettify-symbols-alist)
+ (let ((ann (cdr (assoc (concat "\\" sym)
+ tex--prettify-symbols-alist))))
+ (when ann
+ (concat " " (char-to-string ann))))))
+
+(declare-function LaTeX--completion-annotation-from-math-menu
+ "latex" (sym))
+
+(defun TeX--completion-annotation-function (sym)
+ "Annotation function for symbol/macro completion.
+Used as `:annotation-function' in `completion-extra-properties'."
+ (or (TeX--completion-annotation-from-tex--prettify-symbols-alist sym)
+ (and (fboundp #'LaTeX--completion-annotation-from-math-menu)
+ (LaTeX--completion-annotation-from-math-menu sym))))
+
+(defun TeX--completion-at-point ()
+ "(La)TeX completion at point function.
+See `completion-at-point-functions'."
+ (let ((entry (TeX--complete-find-entry)))
+ (when entry
+ (if (numberp (nth 1 entry))
+ (let* ((sub (nth 1 entry))
+ (begin (match-beginning sub))
+ (end (match-end sub))
+ (symbol (buffer-substring-no-properties begin end))
+ (list (funcall (nth 2 entry))))
+ (list begin end (all-completions symbol list)
+ :annotation-function
+ #'TeX--completion-annotation-function))
+ ;; We intentionally don't call the fallback completion functions because
+ ;; they do completion on their own and don't work too well with things
+ ;; like company-mode. And the default function `ispell-complete-word'
+ ;; isn't so useful anyway.
+ nil))))
+
+(defcustom TeX-default-macro "ref"
+ "The default macro when creating new ones with `TeX-insert-macro'."
+ :group 'TeX-macro
+ :type 'string)
+
+(make-variable-buffer-local 'TeX-default-macro)
+
+(defcustom TeX-insert-braces t
+ "If non-nil, append a empty pair of braces after inserting a macro.
+
+See also `TeX-insert-braces-alist'."
+ :group 'TeX-macro
+ :type 'boolean)
+
+(defcustom TeX-insert-braces-alist nil
+ "Alist of macros to which braces should or should not be appended.
+
+Each element is a cons cell, whose CAR is the macro name, and the
+CDR is non-nil or nil, depending on whether a pair of braces
+should be, respectively, appended or not to the macro.
+
+If a macro has an element in this variable, `TeX-parse-macro'
+will use its value to decide what to do, whatever the value of
+the variable `TeX-insert-braces'."
+ :group 'TeX-macro
+ :type '(repeat (cons (string :tag "Macro name")
+ (boolean :tag "Append braces?"))))
+(make-variable-buffer-local 'TeX-insert-braces-alist)
+
+(defcustom TeX-insert-macro-default-style 'show-optional-args
+ "Specifies whether `TeX-insert-macro' will ask for all optional arguments.
+
+If set to the symbol `show-optional-args', `TeX-insert-macro'
+asks for optional arguments of TeX marcos, unless the previous
+optional argument has been rejected. If set to
+`show-all-optional-args', `TeX-insert-macro' asks for all
+optional arguments. If set to `mandatory-args-only',
+`TeX-insert-macro' asks only for mandatory argument.
+
+When `TeX-insert-macro' is called with \\[universal-argument], it's the other
+way round.
+
+Note that for some macros, there are special mechanisms, see for example
+`LaTeX-includegraphics-options-alist' and `TeX-arg-cite-note-p'."
+ :group 'TeX-macro
+ :type '(choice (const mandatory-args-only)
+ (const show-optional-args)
+ (const show-all-optional-args)))
+
+(defvar TeX-arg-opening-brace nil
+ "String used as an opening brace for argument insertion.
+The variable will be temporarily let-bound with the necessary value.")
+
+(defvar TeX-arg-closing-brace nil
+ "String used as a closing brace for argument insertion.
+The variable will be temporarily let-bound with the necessary value.")
+
+(defvar TeX-after-insert-macro-hook nil
+ "A hook run after `TeX-insert-macro'.")
+
+(defvar TeX-macro-history nil)
+
+(defun TeX--symbol-completion-table ()
+ (completion-table-dynamic
+ (lambda (_str)
+ (TeX-symbol-list-filtered))
+ t))
+
+(defun TeX-insert-macro (symbol)
+ "Insert TeX macro SYMBOL with completion.
+
+AUCTeX knows of some macros and may query for extra arguments, depending on
+the value of `TeX-insert-macro-default-style' and whether `TeX-insert-macro'
+is called with \\[universal-argument]."
+ ;; When called with a prefix (C-u), only ask for mandatory arguments,
+ ;; i.e. all optional arguments are skipped. See `TeX-parse-arguments' for
+ ;; details. Note that this behavior may be changed in favor of a more
+ ;; flexible solution in the future, therefore we don't document it at the
+ ;; moment.
+ (interactive (list
+ (let ((completion-extra-properties
+ (list :annotation-function
+ #'TeX--completion-annotation-function)))
+ (completing-read (concat "Macro (default "
+ TeX-default-macro
+ "): "
+ TeX-esc)
+ (TeX--symbol-completion-table) nil nil nil
+ 'TeX-macro-history TeX-default-macro))))
+ (when (called-interactively-p 'any)
+ (setq TeX-default-macro symbol))
+ (TeX-parse-macro symbol (cdr-safe (assoc symbol (TeX-symbol-list))))
+ (run-hooks 'TeX-after-insert-macro-hook))
+
+(defvar TeX-electric-macro-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map minibuffer-local-completion-map)
+ (define-key map " " #'minibuffer-complete-and-exit)
+ map))
+
+(defun TeX-electric-macro ()
+ "Insert TeX macro with completion.
+
+AUCTeX knows of some macros, and may query for extra arguments.
+Space will complete and exit."
+ (interactive)
+ (cond ((eq (preceding-char) last-command-event)
+ (call-interactively #'self-insert-command))
+ ((eq (preceding-char) ?.)
+ (let ((TeX-default-macro " ")
+ (minibuffer-local-completion-map TeX-electric-macro-map))
+ (call-interactively #'TeX-insert-macro)))
+ (t
+ (let ((minibuffer-local-completion-map TeX-electric-macro-map))
+ (call-interactively #'TeX-insert-macro)))))
+
+(defvar TeX-exit-mark nil
+ "Dynamically bound by `TeX-parse-macro' and `LaTeX-env-args'.")
+
+(defun TeX-parse-macro (symbol args)
+ "How to parse TeX macros which takes one or more arguments.
+
+First argument SYMBOL is the name of the macro.
+
+If ARGS is nil, insert macro with point inside braces.
+Otherwise, each element in ARGS should match an argument to the
+TeX macro. What is done depend on the type of the element:
+
+ string: Use the string as a prompt to prompt for the argument.
+
+ number: Insert that many braces, leave point inside the first.
+
+ nil: Insert empty braces.
+
+ t: Insert empty braces, leave point between the braces.
+
+ other symbols: Call the symbol as a function. You can define
+ your own hook, or use one of the predefined argument hooks. If
+ you add new hooks, you can assume that point is placed directly
+ after the previous argument, or after the macro name if this is
+ the first argument. Please leave point located after the
+ argument you are inserting. If you want point to be located
+ somewhere else after all hooks have been processed, set the
+ value of `TeX-exit-mark'. It will point nowhere, until the
+ argument hook set it. By convention, these hooks all start
+ with `TeX-arg-'.
+
+ list: If the car is a string, insert it as a prompt and the next
+ element as initial input. Otherwise, call the car of the list
+ with the remaining elements as arguments.
+
+ vector: Optional argument. If it has more than one element,
+ parse it as a list, otherwise parse the only element as above.
+ Use square brackets instead of curly braces, and is not inserted
+ on empty user input."
+ (let ((TeX-grop (if (and (or (atom args) (= (length args) 1))
+ (fboundp 'LaTeX-verbatim-macros-with-delims)
+ (member symbol (LaTeX-verbatim-macros-with-delims)))
+ LaTeX-default-verb-delimiter
+ TeX-grop))
+ (TeX-grcl (if (and (or (atom args) (= (length args) 1))
+ (fboundp 'LaTeX-verbatim-macros-with-delims)
+ (member symbol (LaTeX-verbatim-macros-with-delims)))
+ LaTeX-default-verb-delimiter
+ TeX-grcl)))
+ (if (and (TeX-active-mark)
+ (> (point) (mark)))
+ (exchange-point-and-mark))
+ (insert TeX-esc symbol)
+ (let ((TeX-exit-mark (make-marker))
+ (position (point)))
+ (TeX-parse-arguments args)
+ (cond ((marker-position TeX-exit-mark)
+ (goto-char (marker-position TeX-exit-mark))
+ (set-marker TeX-exit-mark nil))
+ ((let ((element (assoc symbol TeX-insert-braces-alist)))
+ ;; If in `TeX-insert-braces-alist' there is an element associated
+ ;; to the current macro, use its value to decide whether inserting
+ ;; a pair of braces, otherwise use the standard criterion.
+ (if element
+ (cdr element)
+ (and TeX-insert-braces
+ ;; Do not add braces if the argument is 0 or -1.
+ (not (and (= (safe-length args) 1)
+ (numberp (car args))
+ (<= (car args) 0)))
+ (equal position (point))
+ (string-match "[a-zA-Z]+" symbol))))
+ (if (texmathp)
+ (when (TeX-active-mark)
+ (insert TeX-grop)
+ (exchange-point-and-mark)
+ (insert TeX-grcl))
+ (insert TeX-grop)
+ (if (TeX-active-mark)
+ (progn
+ (exchange-point-and-mark)
+ (insert TeX-grcl))
+ (insert TeX-grcl)
+ (backward-char))))))))
+
+(defun TeX-arg-string (optional &optional prompt initial-input)
+ "Prompt for a string.
+
+If OPTIONAL is not nil then the PROMPT will start with ``(Optional) ''.
+INITIAL-INPUT is a string to insert before reading input."
+ (TeX-argument-insert
+ (if (and (not optional) (TeX-active-mark))
+ (let ((TeX-argument (buffer-substring (point) (mark))))
+ (delete-region (point) (mark))
+ TeX-argument)
+ (TeX-read-string (TeX-argument-prompt optional prompt "Text") initial-input))
+ optional))
+
+(defvar TeX-last-optional-rejected nil
+ "Dynamically bound by `TeX-parse-arguments'.")
+
+(defun TeX-parse-arguments (args)
+ "Parse TeX macro arguments ARGS.
+
+See `TeX-parse-macro' for details."
+ (let ((TeX-last-optional-rejected nil))
+ (while args
+ (if (vectorp (car args))
+ ;; Maybe get rid of all optional arguments. See `TeX-insert-macro'
+ ;; for more comments. See `TeX-insert-macro-default-style'.
+ ;; The macro `LaTeX-check-insert-macro-default-style' in
+ ;; `latex.el' uses the code inside (unless ...) This macro
+ ;; should be adapted if the code here changs.
+ (unless (if (eq TeX-insert-macro-default-style 'show-all-optional-args)
+ (equal current-prefix-arg '(4))
+ (or
+ (and (eq TeX-insert-macro-default-style 'show-optional-args)
+ (equal current-prefix-arg '(4)))
+ (and (eq TeX-insert-macro-default-style 'mandatory-args-only)
+ (null (equal current-prefix-arg '(4))))
+ TeX-last-optional-rejected))
+ (let ((TeX-arg-opening-brace LaTeX-optop)
+ (TeX-arg-closing-brace LaTeX-optcl))
+ (TeX-parse-argument t (if (equal (length (car args)) 1)
+ (aref (car args) 0)
+ (append (car args) nil)))))
+ (let ((TeX-arg-opening-brace TeX-grop)
+ (TeX-arg-closing-brace TeX-grcl))
+ (setq TeX-last-optional-rejected nil)
+ (TeX-parse-argument nil (car args))))
+ (setq args (cdr args)))))
+
+(defun TeX-parse-argument (optional arg)
+ "Depending on OPTIONAL, insert TeX macro argument ARG.
+If OPTIONAL is set, only insert if there is anything to insert, and
+then use square brackets instead of curly braces.
+
+See `TeX-parse-macro' for details."
+ (let (insert-flag)
+ (cond ((stringp arg)
+ (TeX-arg-string optional arg)
+ (setq insert-flag t))
+ ((numberp arg)
+ (cond ((< arg 0)
+ (when (TeX-active-mark)
+ ;; Put both the macro and the marked region in a TeX group.
+ (let ((beg (min (point) (mark)))
+ (end (set-marker (make-marker) (max (point) (mark)))))
+ (insert " ")
+ (goto-char beg)
+ (skip-chars-backward "^\\\\")
+ (backward-char)
+ (insert TeX-arg-opening-brace)
+ (goto-char (marker-position end))
+ (insert TeX-arg-closing-brace)
+ (setq insert-flag t)
+ (set-marker end nil))))
+ ((= arg 0)) ; nop for clarity
+ ((> arg 0)
+ (TeX-parse-argument optional t)
+ (while (> arg 1)
+ (TeX-parse-argument optional nil)
+ (setq arg (- arg 1))))))
+ ((null arg)
+ (insert TeX-arg-opening-brace)
+ (when (and (not optional) (TeX-active-mark))
+ (exchange-point-and-mark))
+ (insert TeX-arg-closing-brace)
+ (setq insert-flag t))
+ ((eq arg t)
+ (insert TeX-arg-opening-brace)
+ (if (and (not optional) (TeX-active-mark))
+ (progn
+ (exchange-point-and-mark))
+ (set-marker TeX-exit-mark (point)))
+ (insert TeX-arg-closing-brace)
+ (setq insert-flag t))
+ ((symbolp arg)
+ (funcall arg optional))
+ ((listp arg)
+ (let ((head (car arg))
+ (tail (cdr arg)))
+ (cond ((stringp head)
+ (apply #'TeX-arg-string optional arg))
+ ((symbolp head)
+ (apply head optional tail))
+ (t (error "Unknown list argument type %s"
+ (prin1-to-string head))))))
+ (t (error "Unknown argument type %s" (prin1-to-string arg))))
+ (when (and insert-flag (not optional) (TeX-active-mark))
+ (deactivate-mark))))
+
+(defun TeX-argument-insert (name optional &optional prefix)
+ "Insert NAME surrounded by curly braces.
+
+If OPTIONAL, only insert it if not empty, and then use square brackets.
+If PREFIX is given, insert it before NAME."
+ (if (and optional (string-equal name ""))
+ (setq TeX-last-optional-rejected t)
+ (insert TeX-arg-opening-brace)
+ (if prefix
+ (insert prefix))
+ (if (and (string-equal name "")
+ (null (marker-position TeX-exit-mark)))
+ (set-marker TeX-exit-mark (point))
+ (insert name))
+ (insert TeX-arg-closing-brace)))
+
+(defun TeX-argument-prompt (optional prompt default &optional complete)
+ "Return a argument prompt.
+
+If OPTIONAL is not nil then the prompt will start with ``(Optional) ''.
+
+PROMPT will be used if not nil, otherwise use DEFAULT.
+
+Unless optional argument COMPLETE is non-nil, ``: '' will be appended."
+ (concat (if optional "(Optional) " "")
+ (if prompt prompt default)
+ (if complete "" ": ")))
+
+(defun TeX-string-divide-number-unit (string)
+ "Divide number and unit in STRING and return a list (number unit)."
+ (if (string-match "[0-9]*\\.?[0-9]+" string)
+ (list (substring string 0 (string-match "[^.0-9]" string))
+ (substring string (if (string-match "[^.0-9]" string)
+ (string-match "[^.0-9]" string)
+ (length string))))
+ (list "" string)))
+
+(defcustom TeX-default-unit-for-image "cm"
+ "Default unit when prompting for an image size."
+ :group 'TeX-macro
+ :type '(choice (const "cm")
+ (const "in")
+ (const "\\linewidth")
+ (string :tag "Other")))
+
+(defun TeX-arg-maybe (symbol list form)
+ "Evaluate FORM, if SYMBOL is an element of LIST."
+ (when (memq symbol list)
+ (eval form t)))
+
+(defun TeX-arg-free (optional &rest args)
+ "Parse its arguments but use no braces when they are inserted."
+ (let ((TeX-arg-opening-brace "")
+ (TeX-arg-closing-brace ""))
+ (if (equal (length args) 1)
+ (TeX-parse-argument optional (car args))
+ (TeX-parse-argument optional args))))
+
+(defun TeX-arg-literal (_optional &rest args)
+ "Insert its arguments ARGS into the buffer.
+Used for specifying extra syntax for a macro. The compatibility
+argument OPTIONAL is ignored."
+ (apply #'insert args))
+
+
+;;; Font Locking
+
+(defcustom TeX-install-font-lock #'font-latex-setup
+ "Function to call to install font lock support.
+Choose `ignore' if you don't want AUCTeX to install support for font locking."
+ :group 'TeX-misc
+ :type '(radio (function-item font-latex-setup)
+ (function-item tex-font-setup)
+ (function-item ignore)
+ (function :tag "Other")))
+
+;;; The Mode
+
+(defvar TeX-format-list
+ '(("JLATEX" japanese-latex-mode
+ "\\\\\\(documentstyle\\|documentclass\\)[^%\n]*{u?\\(j[s-]?\\|t\\)\
+\\(article\\|report\\|book\\|slides\\)")
+ ("JTEX" japanese-plain-tex-mode
+ "-- string likely in Japanese TeX --")
+ ("AMSTEX" ams-tex-mode
+ "\\\\document\\b")
+ ("CONTEXT" context-mode
+ "\\\\\\(start\\(text\\|tekst\\|proje[ck]t\\|proiect\\|\
+produ[ck]t\\|produs\\|environment\\|omgeving\\|umgebung\\|prostredi\\|mediu\\|\
+component\\|onderdeel\\|komponent[ea]\\|componenta\\)\
+\\|inizia\\(testo\\|progetto\\|prodotto\\|ambiente\\|componente\\)\
+\\)\\|%.*?interface=")
+ ("LATEX" latex-mode
+ "\\\\\\(begin\\|\\(?:sub\\)\\{0,2\\}section\\|chapter\\|documentstyle\\|\
+documentclass\\)\\b")
+ ("TEX" plain-tex-mode "."))
+ "List of format packages to consider when choosing a TeX mode.
+
+A list with an entry for each format package available at the site.
+
+Each entry is a list with three elements.
+
+1. The name of the format package.
+2. The name of the major mode.
+3. A regexp typically matched in the beginning of the file.
+
+When entering `tex-mode', each regexp is tried in turn in order to find
+the major mode to be used.")
+
+(defcustom TeX-default-mode #'latex-mode
+ "Mode to enter for a new file when it can't be determined otherwise."
+ :group 'TeX-misc
+ :type '(radio (function-item latex-mode)
+ (function-item plain-tex-mode)
+ (function :tag "Other")))
+
+(defcustom TeX-force-default-mode nil
+ "If set to nil, try to infer the mode of the file from its content."
+ :group 'TeX-misc
+ :type 'boolean)
+
+;;;###autoload
+(defun TeX-tex-mode ()
+ "Major mode in AUCTeX for editing TeX or LaTeX files.
+Tries to guess whether this file is for plain TeX or LaTeX.
+
+The algorithm is as follows:
+
+ 1) if the file is empty or `TeX-force-default-mode' is not set to nil,
+ `TeX-default-mode' is chosen
+ 2) If \\documentstyle or \\begin{, \\section{, \\part{ or \\chapter{ is
+ found, `latex-mode' is selected.
+ 3) Otherwise, use `plain-tex-mode'"
+ (interactive)
+
+ (funcall (if (or (equal (buffer-size) 0)
+ TeX-force-default-mode)
+ TeX-default-mode
+ (save-excursion
+ (goto-char (point-min))
+ (let ((comment-start-skip ;Used by TeX-in-comment
+ (concat
+ "\\(\\(^\\|[^\\\n]\\)\\("
+ (regexp-quote TeX-esc)
+ (regexp-quote TeX-esc)
+ "\\)*\\)\\(%+ *\\)"))
+ (entry TeX-format-list)
+ answer case-fold-search)
+ (while (and entry (not answer))
+ (if (re-search-forward (nth 2 (car entry))
+ 10000 t)
+ (if (not (TeX-in-comment))
+ (setq answer (nth 1 (car entry))))
+ (setq entry (cdr entry))))
+ (if answer
+ answer
+ TeX-default-mode))))))
+
+(defun TeX--prettify-symbols-compose-p (start end match)
+ (and (tex--prettify-symbols-compose-p start end match)
+ (not (let ((face (get-text-property end 'face)))
+ (if (consp face)
+ (memq 'font-latex-verbatim-face face)
+ (eq face 'font-latex-verbatim-face))))))
+
+(defun VirTeX-common-initialization ()
+ "Perform basic initialization."
+ (kill-all-local-variables)
+ (setq TeX-mode-p t)
+ (setq TeX-output-extension (if TeX-PDF-mode "pdf" "dvi"))
+ (setq indent-tabs-mode nil)
+
+ ;; Ispell support
+ (set (make-local-variable 'ispell-parser) 'tex)
+
+ ;; Redefine some standard variables
+ (make-local-variable 'paragraph-start)
+ (make-local-variable 'paragraph-separate)
+ (set (make-local-variable 'comment-start) "%")
+ (set (make-local-variable 'comment-start-skip)
+ (concat
+ "\\(\\(^\\|[^\\\n]\\)\\("
+ (regexp-quote TeX-esc)
+ (regexp-quote TeX-esc)
+ "\\)*\\)\\(%+[ \t]*\\)"))
+ (set (make-local-variable 'comment-end-skip) "[ \t]*\\(\\s>\\|\n\\)")
+ (set (make-local-variable 'comment-use-syntax) t)
+ (set (make-local-variable 'comment-padding) " ")
+ ;; Removed as commenting in (La)TeX is done with one `%' not two
+ ;; (make-local-variable 'comment-add)
+ ;; (setq comment-add 1) ;default to `%%' in comment-region
+ (set (make-local-variable 'comment-indent-function) #'TeX-comment-indent)
+ (set (make-local-variable 'comment-multi-line) nil)
+ (make-local-variable 'compile-command)
+ (unless (boundp 'compile-command)
+ (setq compile-command "make"))
+ (set (make-local-variable 'words-include-escapes) nil)
+
+ ;; Make TAB stand out
+ ;; (make-local-variable 'buffer-display-table)
+ ;; (setq buffer-display-table (if standard-display-table
+ ;; (copy-sequence standard-display-table)
+ ;; (make-display-table)))
+ ;; (aset buffer-display-table ?\t (apply 'vector (append "<TAB>" nil)))
+
+ ;; Symbol completion.
+ (set (make-local-variable 'TeX-complete-list)
+ (list (list "\\\\\\([a-zA-Z]*\\)"
+ 1 'TeX-symbol-list-filtered
+ (if TeX-insert-braces "{}"))
+ (list "" TeX-complete-word)))
+
+ (funcall TeX-install-font-lock)
+
+ ;; We want this to be early in the list, so we do not add it before
+ ;; we enter TeX mode the first time.
+ (add-hook 'write-contents-functions #'TeX-safe-auto-write nil t)
+
+ ;; Minor modes
+ (when TeX-source-correlate-mode
+ (TeX-source-correlate-mode 1))
+
+ ;; Prettify Symbols mode
+ (require 'tex-mode)
+ (setq-local prettify-symbols-alist tex--prettify-symbols-alist)
+ (add-function :override (local 'prettify-symbols-compose-predicate)
+ #'TeX--prettify-symbols-compose-p)
+
+ ;; Standard Emacs completion-at-point support
+ (add-hook 'completion-at-point-functions
+ #'TeX--completion-at-point nil t)
+
+ ;; Let `TeX-master-file' be called after a new file was opened and
+ ;; call `TeX-update-style' on any file opened. (The addition to the
+ ;; hook has to be made here because its local value will be deleted
+ ;; by `kill-all-local-variables' if it is added e.g. in `tex-mode'.)
+ ;;
+ ;; `TeX-update-style' has to be called before
+ ;; `global-font-lock-mode', which may also be specified in
+ ;; `find-file-hook', gets called. Otherwise style-based
+ ;; fontification will break (in XEmacs). That means, `add-hook'
+ ;; cannot be called with a non-nil value of the APPEND argument.
+ ;;
+ ;; `(TeX-master-file nil nil t)' has to be called *before*
+ ;; `TeX-update-style' as the latter will call `TeX-master-file'
+ ;; without the `ask' bit set.
+ (add-hook 'find-file-hook
+ (lambda ()
+ ;; Check if we are looking at a new or shared file.
+ (when (or (not (file-exists-p (buffer-file-name)))
+ (eq TeX-master 'shared))
+ (TeX-master-file nil nil t))
+ (TeX-update-style t)) nil t))
+
+
+;;; Hilighting
+
+;; FIXME: It's likely that `hilit-patterns-alist' is much obsolete.
+(if (boundp 'hilit-patterns-alist)
+ (let ((latex-patterns (cdr-safe (assq 'latex-mode hilit-patterns-alist)))
+ (plain-tex-patterns (cdr-safe (assq 'plain-tex-mode
+ hilit-patterns-alist))))
+ (if (and latex-patterns plain-tex-patterns)
+ (setq hilit-patterns-alist
+ (append (list (cons 'ams-tex-mode plain-tex-patterns))
+ hilit-patterns-alist)))))
+
+;;; Parsing
+
+(defgroup TeX-parse nil
+ "Parsing TeX files from AUCTeX."
+ :group 'AUCTeX)
+
+(defvar TeX-auto-parser '((styles TeX-auto-file TeX-run-style-hooks)))
+;; Alist of parsed information.
+;; Each entry is a list with the following elements:
+;;
+;; 0. Name of information type.
+;; 1. Name of temporary variable used when parsing.
+;; 2. Name of function to add information to add to #3.
+;; 3. Name of variable holding buffer local information.
+;; 4. Name of variable indicating that #3 has changed.
+
+
+(defconst TeX-auto-parser-temporary 1)
+(defconst TeX-auto-parser-add 2)
+(defconst TeX-auto-parser-local 3)
+(defconst TeX-auto-parser-change 4)
+
+(defun TeX-auto-add-information (name entries)
+ "For NAME in `TeX-auto-parser' add ENTRIES."
+ (let* ((entry (assoc name TeX-auto-parser))
+ (change (nth TeX-auto-parser-change entry))
+ (change-value (symbol-value change))
+ (local (nth TeX-auto-parser-local entry))
+ (local-value (symbol-value local)))
+ (if change-value
+ (set local (cons entries local-value))
+ (set change t)
+ (set local (list entries local-value)))))
+
+(defun TeX-auto-list-information (name)
+ "Return information in `TeX-auto-parser' about NAME."
+ (TeX-update-style)
+ (let* ((entry (assoc name TeX-auto-parser))
+ (change (nth TeX-auto-parser-change entry))
+ (change-value (symbol-value change))
+ (local (nth TeX-auto-parser-local entry)))
+ (if (not change-value)
+ ()
+ (set change nil)
+ ;; Sort it
+ (message "Sorting %s..." name)
+ (set local
+ (sort (mapcar #'TeX-listify (apply #'append (symbol-value local)))
+ #'TeX-car-string-lessp))
+ (message "Sorting %s...done" name)
+ ;; Make it unique
+ (message "Removing duplicates...")
+ (let ((entry (symbol-value local)))
+ (while (and entry (cdr entry))
+ (let ((this (car entry))
+ (next (car (cdr entry))))
+ (if (not (string-equal (car this) (car next)))
+ (setq entry (cdr entry))
+ ;; We have two equal symbols. Use the one with
+ ;; most arguments.
+ (if (> (length next) (length this))
+ (setcdr this (cdr next)))
+ (setcdr entry (cdr (cdr entry)))))))
+ (message "Removing duplicates...done"))
+ (symbol-value local)))
+
+(defmacro TeX-auto-add-type (name prefix &optional plural)
+ "Add information about NAME to the parser using PREFIX.
+
+Optional third argument PLURAL is the plural form of NAME.
+By default just add an `s'.
+
+This macro creates a set of variables and functions to maintain a
+separate type of information in the parser."
+ (let* ((names (or plural (concat name "s")))
+ (tmp (intern (concat prefix "-auto-" name)))
+ (add (intern (concat prefix "-add-" names)))
+ (local (intern (concat prefix "-" name "-list")))
+ (change (intern (concat prefix "-" name "-changed")))
+ (vardoc (concat "Information about " names
+ " in the current buffer.
+Generated by `TeX-auto-add-type'.")))
+ `(progn
+ (defvar ,tmp nil ,vardoc)
+ (defvar ,local nil ,vardoc)
+ (make-variable-buffer-local ',local)
+ (defvar ,change nil ,vardoc)
+ (make-variable-buffer-local ',change)
+ (defun ,add (&rest ,(intern names))
+ ,(concat "Add information about " (upcase names)
+ " to the current buffer.
+Generated by `TeX-auto-add-type'.")
+ (TeX-auto-add-information ,name ,(intern names)))
+ (defun ,local ()
+ ,(concat "List of " names
+ " active in the current buffer.
+Generated by `TeX-auto-add-type'.")
+ (TeX-auto-list-information ,name))
+ ;; Append new type to `TeX-auto-parser' in order to make `style' type
+ ;; always the first.
+ (add-to-list 'TeX-auto-parser ',(list name tmp add local change) t)
+ (add-hook 'TeX-remove-style-hook
+ (lambda ()
+ (setq ,local nil))))))
+
+(TeX-auto-add-type "symbol" "TeX")
+
+(defvar TeX-auto-apply-hook nil
+ "Hook run when a buffer is parsed and the information is applied.")
+
+(defun TeX-auto-apply ()
+ "Parse and apply TeX information in the current buffer."
+ (TeX-auto-parse)
+ (run-hooks 'TeX-auto-apply-hook)
+ (mapcar #'TeX-auto-apply-entry TeX-auto-parser))
+
+(defun TeX-auto-apply-entry (entry)
+ "Apply the information in ENTRY in `TeX-auto-parser'."
+ (let ((value (symbol-value (nth TeX-auto-parser-temporary entry)))
+ (add (nth TeX-auto-parser-add entry)))
+ (if value (apply add value))))
+
+(defun TeX-safe-auto-write ()
+ "Call `TeX-auto-write' safely."
+ (condition-case _ignored
+ (TeX-auto-write)
+ (error nil))
+ ;; Continue with the other write file hooks.
+ nil)
+
+(defcustom TeX-auto-save nil
+ "Automatically save style information when saving the buffer."
+ :group 'TeX-parse
+ :type 'boolean)
+
+(defcustom TeX-auto-untabify nil
+ "Automatically untabify when saving the buffer."
+ :group 'TeX-parse
+ :type 'boolean)
+
+(defun TeX-auto-write ()
+ "Save all relevant TeX information from the current buffer."
+ (if TeX-auto-untabify
+ (untabify (point-min) (point-max)))
+ (if (and TeX-auto-save TeX-auto-local)
+ (let* ((file (expand-file-name
+ (concat
+ (file-name-as-directory TeX-auto-local)
+ (TeX-strip-extension nil TeX-all-extensions t)
+ ".el")
+ (TeX-master-directory)))
+ (dir (file-name-directory file)))
+ ;; Create auto directory if possible.
+ (if (not (file-exists-p dir))
+ (condition-case _ignored
+ (make-directory dir)
+ (error nil)))
+ (if (file-writable-p file)
+ (save-excursion
+ (TeX-update-style)
+ (TeX-auto-store file))
+ (message "Can't write style information.")))))
+
+(defcustom TeX-macro-default (car-safe TeX-macro-private)
+ "Default directory to search for TeX macros."
+ :group 'TeX-file
+ :type 'directory)
+
+(defcustom TeX-auto-default (car-safe TeX-auto-private)
+ "Default directory to place automatically generated TeX information."
+ :group 'TeX-file
+ :type 'directory)
+
+(defcustom TeX-ignore-file
+ "\\(^\\|[/\\]\\)\\(\\.\\|\\.\\.\\|RCS\\|SCCS\\|CVS\\|babel\\..*\\)$"
+ "Regular expression matching file names to ignore.
+
+These files or directories will not be considered when searching for
+TeX files in a directory."
+ :group 'TeX-parse
+ :type 'regexp)
+
+(defcustom TeX-file-recurse t
+ "Whether to search TeX directories recursively.
+nil means do not recurse, a positive integer means go that far deep in the
+directory hierarchy, t means recurse indefinitely."
+ :group 'TeX-parse
+ :type '(choice (const :tag "On" t)
+ (const :tag "Off" nil)
+ (integer :tag "Depth" :value 1)))
+
+(defvar TeX-file-extensions)
+(defvar BibTeX-file-extensions)
+(defvar TeX-Biber-file-extensions)
+
+;;;###autoload
+(defun TeX-auto-generate (tex auto)
+ "Generate style file for TEX and store it in AUTO.
+If TEX is a directory, generate style files for all files in the directory."
+ (interactive (list (setq TeX-macro-default
+ (expand-file-name (read-file-name
+ "TeX file or directory: "
+ TeX-macro-default
+ TeX-macro-default 'confirm)))
+ (setq TeX-auto-default
+ (expand-file-name (read-file-name
+ "AUTO lisp directory: "
+ TeX-auto-default
+ TeX-auto-default 'confirm)))))
+ (cond ((not (file-readable-p tex)))
+ ((string-match TeX-ignore-file tex))
+ ((file-directory-p tex)
+ (let ((files (directory-files (expand-file-name tex)))
+ (default-directory (file-name-as-directory
+ (expand-file-name tex)))
+ (TeX-file-recurse (cond ((symbolp TeX-file-recurse)
+ TeX-file-recurse)
+ ((zerop TeX-file-recurse)
+ nil)
+ ((1- TeX-file-recurse)))))
+ (mapcar (lambda (file)
+ (if (or TeX-file-recurse
+ (not (file-directory-p file)))
+ (TeX-auto-generate file auto)))
+ files)))
+ ((not (file-newer-than-file-p
+ tex
+ (concat (file-name-as-directory auto)
+ (TeX-strip-extension tex TeX-all-extensions t)
+ ".el"))))
+ ((TeX-match-extension tex (TeX-delete-duplicate-strings
+ (append TeX-file-extensions
+ BibTeX-file-extensions
+ TeX-Biber-file-extensions)))
+ (with-current-buffer (let (enable-local-eval)
+ (find-file-noselect tex))
+ (message "Parsing %s..." tex)
+ (TeX-auto-store (concat (file-name-as-directory auto)
+ (TeX-strip-extension tex
+ TeX-all-extensions
+ t)
+ ".el"))
+ (kill-buffer (current-buffer))
+ (message "Parsing %s...done" tex)))))
+
+;;;###autoload
+(defun TeX-auto-generate-global ()
+ "Create global auto directory for global TeX macro definitions."
+ (interactive)
+ (unless (file-directory-p TeX-auto-global)
+ (make-directory TeX-auto-global))
+ (let ((TeX-file-extensions '("cls" "sty"))
+ (BibTeX-file-extensions nil)
+ (TeX-Biber-file-extensions nil))
+ (mapc (lambda (macro) (TeX-auto-generate macro TeX-auto-global))
+ TeX-macro-global))
+ (byte-recompile-directory TeX-auto-global 0))
+
+(defun TeX-auto-store (file)
+ "Extract information for AUCTeX from current buffer and store it in FILE."
+ (TeX-auto-parse)
+
+ (if (member nil (mapcar #'TeX-auto-entry-clear-p TeX-auto-parser))
+ (let ((style (TeX-strip-extension nil TeX-all-extensions t))
+ (class-opts (if (boundp 'LaTeX-provided-class-options)
+ LaTeX-provided-class-options))
+ (pkg-opts (if (boundp 'LaTeX-provided-package-options)
+ LaTeX-provided-package-options))
+ (tex-cmd-opts TeX-command-extra-options)
+ (verb-envs (when (boundp 'LaTeX-verbatim-environments-local)
+ LaTeX-verbatim-environments-local))
+ (verb-macros-delims (when (boundp 'LaTeX-verbatim-macros-with-delims-local)
+ LaTeX-verbatim-macros-with-delims-local))
+ (verb-macros-braces (when (boundp 'LaTeX-verbatim-macros-with-braces-local)
+ LaTeX-verbatim-macros-with-braces-local))
+ (dialect TeX-style-hook-dialect)
+ (bibtex-p (eq major-mode 'bibtex-mode)))
+ (TeX-unload-style style)
+ (with-current-buffer (generate-new-buffer file)
+ (erase-buffer)
+ (insert "(TeX-add-style-hook\n \""
+ style "\"\n (lambda ()")
+ (unless (string= tex-cmd-opts "")
+ (insert "\n (setq TeX-command-extra-options\n"
+ " " (prin1-to-string tex-cmd-opts) ")"))
+ (when class-opts
+ (insert "\n (TeX-add-to-alist 'LaTeX-provided-class-options\n"
+ " '" (prin1-to-string class-opts) ")"))
+ (when pkg-opts
+ (insert "\n (TeX-add-to-alist 'LaTeX-provided-package-options\n"
+ " '" (prin1-to-string pkg-opts) ")"))
+ (dolist (env verb-envs)
+ (insert
+ (format "\n (add-to-list 'LaTeX-verbatim-environments-local \"%s\")"
+ env)))
+ (dolist (env verb-macros-braces)
+ (insert
+ (format "\n (add-to-list 'LaTeX-verbatim-macros-with-braces-local \"%s\")"
+ env)))
+ (dolist (env verb-macros-delims)
+ (insert
+ (format "\n (add-to-list 'LaTeX-verbatim-macros-with-delims-local \"%s\")"
+ env)))
+ (mapc (lambda (el) (TeX-auto-insert el style))
+ TeX-auto-parser)
+ (insert ")")
+ (if dialect (insert (concat
+ "\n "
+ (prin1-to-string
+ (if bibtex-p
+ ;; Add :latex since functions such
+ ;; as `LaTeX-add-bibitems' are
+ ;; only meaningful in LaTeX
+ ;; document buffer.
+ ;; FIXME: BibTeX is available to
+ ;; plain TeX through eplain
+ ;; (<URL:https://tug.org/eplain/doc/eplain.html#Citations>).
+ ;; It would be nice if AUCTeX
+ ;; supports such usage.
+ `'(or ,dialect :latex)
+ dialect)))))
+ (insert ")\n\n")
+ (write-region (point-min) (point-max) file nil 'silent)
+ (kill-buffer (current-buffer))))
+ (if (file-exists-p (concat file "c"))
+ (delete-file (concat file "c")))
+ (if (file-exists-p file)
+ (delete-file file))))
+
+(defun TeX-auto-entry-clear-p (entry)
+ "Check if the temporary for `TeX-auto-parser' entry ENTRY is clear."
+ ;; FIXME: This doc-string isn't clear to me. -- rs
+ (null (symbol-value (nth TeX-auto-parser-temporary entry))))
+
+(defun TeX-auto-insert (entry &optional skip)
+ "Insert code to initialize ENTRY from `TeX-auto-parser'.
+
+If SKIP is not-nil, don't insert code for SKIP."
+ (let ((name (symbol-name (nth TeX-auto-parser-add entry)))
+ (list (symbol-value (nth TeX-auto-parser-temporary entry))))
+ (unless (null list)
+ (insert "\n (" name)
+ (dolist (el list)
+ (cond ((and (stringp el) (not (string= el skip)))
+ (insert "\n ")
+ (insert (prin1-to-string el)))
+ ((not (stringp el))
+ (insert "\n ")
+ (insert "'" (prin1-to-string el)))))
+ (insert ")"))))
+
+(defvar TeX-auto-ignore
+ '("csname" "filedate" "fileversion" "docdate" "next" "labelitemi"
+ "labelitemii" "labelitemiii" "labelitemiv" "labelitemv"
+ "labelenumi" "labelenumii" "labelenumiii" "labelenumiv"
+ "labelenumv" "theenumi" "theenumii" "theenumiii" "theenumiv"
+ "theenumv" "document" "par" "do" "expandafter")
+ "List of symbols to ignore when scanning a TeX style file.")
+
+(defcustom TeX-auto-regexp-list 'TeX-auto-full-regexp-list
+ "List of regular expressions used for parsing the current file.
+It can also be a name of a variable having such value."
+ :type '(radio (variable-item TeX-auto-empty-regexp-list)
+ (variable-item TeX-auto-full-regexp-list)
+ (variable-item plain-TeX-auto-regexp-list)
+ (variable-item LaTeX-auto-minimal-regexp-list)
+ (variable-item LaTeX-auto-label-regexp-list)
+ (variable-item LaTeX-auto-regexp-list)
+ (variable :tag "Other")
+ (repeat :tag "Specify"
+ (group (regexp :tag "Match")
+ (sexp :tag "Groups")
+ symbol)))
+ :group 'TeX-parse)
+ (make-variable-buffer-local 'TeX-auto-regexp-list)
+
+(defun TeX-auto-add-regexp (regexp)
+ "Add REGEXP to `TeX-auto-regexp-list' if not already a member."
+ (if (symbolp TeX-auto-regexp-list)
+ (setq TeX-auto-regexp-list (symbol-value TeX-auto-regexp-list)))
+ (or (member regexp TeX-auto-regexp-list)
+ (setq TeX-auto-regexp-list (cons regexp TeX-auto-regexp-list))))
+
+(defvar TeX-auto-empty-regexp-list
+ '(("<IMPOSSIBLE>\\(\\'\\`\\)" 1 ignore))
+ "List of regular expressions guaranteed to match nothing.")
+
+(defvar TeX-token-char
+ "\\(?:[a-zA-Z]\\|\\cj\\)"
+ "Regexp matching a character in a TeX macro.
+
+Please use a shy group if you use a grouping construct, because
+the functions/variables which use `TeX-token-char' expect not to
+alter the numbering of any ordinary, non-shy groups.")
+
+(defvar plain-TeX-auto-regexp-list
+ (let ((token TeX-token-char))
+ `((,(concat "\\\\def\\\\\\(" token "+\\)[^a-zA-Z@]")
+ 1 TeX-auto-symbol-check)
+ (,(concat "\\\\let\\\\\\(" token "+\\)[^a-zA-Z@]")
+ 1 TeX-auto-symbol-check)
+ (,(concat "\\\\font\\\\\\(" token "+\\)[^a-zA-Z@]") 1 TeX-auto-symbol)
+ (,(concat "\\\\chardef\\\\\\(" token "+\\)[^a-zA-Z@]") 1 TeX-auto-symbol)
+ (,(concat "\\\\new\\(?:count\\|dimen\\|muskip\\|skip\\)\\\\\\(" token
+ "+\\)[^a-zA-Z@]")
+ 1 TeX-auto-symbol)
+ (,(concat "\\\\newfont{?\\\\\\(" token "+\\)}?") 1 TeX-auto-symbol)
+ (,(concat "\\\\typein\\[\\\\\\(" token "+\\)\\]") 1 TeX-auto-symbol)
+ ("\\\\input +\\(\\.*[^#%\\\\\\.\n\r]+\\)\\(\\.[^#%\\\\\\.\n\r]+\\)?"
+ 1 TeX-auto-file)
+ (,(concat "\\\\mathchardef\\\\\\(" token "+\\)[^a-zA-Z@]")
+ 1 TeX-auto-symbol)))
+ "List of regular expression matching common plain TeX macro definitions.")
+
+(defvar TeX-auto-full-regexp-list plain-TeX-auto-regexp-list
+ "Full list of regular expression matching TeX macro definitions.")
+
+(defvar TeX-auto-prepare-hook nil
+ "List of hooks to be called before parsing a TeX file.")
+
+(defvar TeX-auto-cleanup-hook nil
+ "List of hooks to be called after parsing a TeX file.")
+
+(defcustom TeX-auto-parse-length 999999
+ "Maximal length of TeX file (in characters) that will be parsed."
+ :group 'TeX-parse
+ :type 'integer)
+ (make-variable-buffer-local 'TeX-auto-parse-length)
+
+(defcustom TeX-auto-x-parse-length 0
+ "Maximum length of TeX file that will be parsed additionally.
+Use `TeX-auto-x-regexp-list' for parsing the region between
+`TeX-auto-parse-length' and this value."
+ :group 'TeX-parse
+ :type 'integer)
+ (make-variable-buffer-local 'TeX-auto-x-parse-length)
+
+(defcustom TeX-auto-x-regexp-list 'LaTeX-auto-label-regexp-list
+ "List of regular expressions used for additional parsing.
+It can also be a name of a variable having such value.
+See `TeX-auto-x-parse-length'."
+ :type '(radio (variable-item TeX-auto-empty-regexp-list)
+ (variable-item TeX-auto-full-regexp-list)
+ (variable-item plain-TeX-auto-regexp-list)
+ (variable-item LaTeX-auto-minimal-regexp-list)
+ (variable-item LaTeX-auto-label-regexp-list)
+ (variable-item LaTeX-auto-regexp-list)
+ (variable :tag "Other")
+ (repeat :tag "Specify"
+ (group (regexp :tag "Match")
+ (sexp :tag "Groups")
+ symbol)))
+ :group 'TeX-parse)
+ (make-variable-buffer-local 'TeX-auto-x-regexp-list)
+
+(defun TeX-regexp-group-count (regexp)
+ "Return number of groups in a REGEXP. This is not foolproof:
+you should not use something like `[\\(]' for a character range."
+ (let (start (n 0))
+ (while (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\([^?]"
+ regexp start)
+ (setq start (- (match-end 0) 2)
+ n (1+ n)))
+ n))
+
+(defun TeX-auto-parse-region (regexp-list beg end)
+ "Parse TeX information according to REGEXP-LIST between BEG and END."
+ (if (symbolp regexp-list)
+ (setq regexp-list (and (boundp regexp-list) (symbol-value regexp-list))))
+ (if regexp-list
+ ;; Extract the information.
+ (let* (groups
+ (count 1)
+ (regexp (concat "\\("
+ (mapconcat
+ (lambda(x)
+ (push (cons count x) groups)
+ (setq count
+ (+ 1 count
+ (TeX-regexp-group-count (car x))))
+ (car x))
+ regexp-list "\\)\\|\\(")
+ "\\)"))
+ syms
+ lst)
+ ;; TODO: Emacs allows at most 255 groups in a regexp, see the
+ ;; "#define MAX_REGNUM 255" in regex-emacs.c. If our regex
+ ;; has more groups, bad things may happen, e.g.,
+ ;; (match-beginning 271) returns nil although the regexp that
+ ;; matched contains group number 271. Sadly, MAX_REGNUM is
+ ;; not exposed to Lisp, so we need to hard-code it here (and
+ ;; sometimes check if it increased in newer Emacs versions).
+ (when (> count 255)
+ (error "The TeX auto-parser's regexp has too many groups (%d)" count))
+ (setq count 0)
+ (goto-char (if end (min end (point-max)) (point-max)))
+ (while (re-search-backward regexp beg t)
+ (let* ((entry (cdr (TeX-member nil groups
+ (lambda (_a b)
+ (match-beginning (car b))))))
+ (symbol (nth 2 entry))
+ (match (nth 1 entry)))
+ (unless (TeX-in-comment)
+ (looking-at (nth 0 entry))
+ (if (fboundp symbol)
+ (funcall symbol match)
+ (puthash (if (listp match)
+ (mapcar #'TeX-match-buffer match)
+ (TeX-match-buffer match))
+ (setq count (1- count))
+ (cdr (or (assq symbol syms)
+ (car (push
+ (cons symbol
+ (make-hash-table :test #'equal))
+ syms)))))))))
+ (setq count 0)
+ (dolist (symbol syms)
+ (setq lst (symbol-value (car symbol)))
+ (while lst
+ (puthash (pop lst)
+ (setq count (1+ count))
+ (cdr symbol)))
+ (maphash (lambda (key value)
+ (push (cons value key) lst))
+ (cdr symbol))
+ (clrhash (cdr symbol))
+ (set (car symbol) (mapcar #'cdr (sort lst #'car-less-than-car)))))))
+
+(defun TeX-auto-parse ()
+ "Parse TeX information in current buffer.
+
+Call the functions in `TeX-auto-prepare-hook' before parsing, and the
+functions in `TeX-auto-cleanup-hook' after parsing."
+
+ (let ((case-fold-search nil))
+
+ (mapc #'TeX-auto-clear-entry TeX-auto-parser)
+ (run-hooks 'TeX-auto-prepare-hook)
+
+ (save-excursion
+ (and (> TeX-auto-x-parse-length TeX-auto-parse-length)
+ (> (point-max) TeX-auto-parse-length)
+ (TeX-auto-parse-region TeX-auto-x-regexp-list
+ TeX-auto-parse-length
+ TeX-auto-x-parse-length))
+ (TeX-auto-parse-region TeX-auto-regexp-list
+ nil TeX-auto-parse-length))
+
+ ;; Cleanup ignored symbols.
+
+ ;; NOTE: This is O(N M) where it could be O(N log N + M log M) if we
+ ;; sorted the lists first.
+ (while (member (car TeX-auto-symbol) TeX-auto-ignore)
+ (setq TeX-auto-symbol (cdr TeX-auto-symbol)))
+ (let ((list TeX-auto-symbol))
+ (while (and list (cdr list))
+ (if (member (car (cdr list)) TeX-auto-ignore)
+ (setcdr list (cdr (cdr list)))
+ (setq list (cdr list)))))
+
+ (run-hooks 'TeX-auto-cleanup-hook)))
+
+(defun TeX-auto-clear-entry (entry)
+ "Set the temporary variable in ENTRY to nil."
+ (set (nth TeX-auto-parser-temporary entry) nil))
+
+(defvar LaTeX-auto-end-symbol nil)
+
+(defun TeX-auto-symbol-check (match)
+ "Add MATCH to TeX-auto-symbols.
+Check for potential LaTeX environments."
+ (let ((symbol (if (listp match)
+ (mapcar #'TeX-match-buffer match)
+ (TeX-match-buffer match))))
+ (if (and (stringp symbol)
+ (string-match "^end\\(.+\\)$" symbol))
+ (add-to-list 'LaTeX-auto-end-symbol
+ (substring symbol (match-beginning 1) (match-end 1)))
+ (if (listp symbol)
+ (dolist (elt symbol)
+ (add-to-list 'TeX-auto-symbol elt))
+ (add-to-list 'TeX-auto-symbol symbol)))))
+
+
+;;; File Extensions
+
+(defgroup TeX-file-extension nil
+ "File extensions recognized by AUCTeX."
+ :group 'TeX-file)
+
+(defcustom TeX-file-extensions '("tex" "sty" "cls" "ltx" "texi" "txi" "texinfo" "dtx")
+ "File extensions used by manually generated TeX files."
+ :group 'TeX-file-extension
+ :type '(repeat (regexp :format "%v")))
+
+(defcustom TeX-all-extensions '("[^.\n]+")
+ "All possible file extensions."
+ :group 'TeX-file-extension
+ :type '(repeat (regexp :format "%v")))
+
+(defcustom TeX-default-extension "tex"
+ "Default extension for TeX files."
+ :group 'TeX-file-extension
+ :type 'string)
+
+ (make-variable-buffer-local 'TeX-default-extension)
+
+(defvar TeX-doc-extensions
+ '("dvi" "pdf" "ps" "txt" "html" "dvi\\.gz" "pdf\\.gz" "ps\\.gz" "txt\\.gz"
+ "html\\.gz" "dvi\\.bz2" "pdf\\.bz2" "ps\\.bz2" "txt\\.bz2" "html\\.bz2")
+ "File extensions of documentation files.")
+
+(defcustom docTeX-default-extension "dtx"
+ "Default extension for docTeX files."
+ :group 'TeX-file-extension
+ :type 'string)
+
+(defvar TeX-output-extension nil
+ "Extension of TeX output file.
+This is either a string or a list with
+a string as element. Its value is obtained from `TeX-command-output-list'.
+Access to the value should be through the function `TeX-output-extension'.")
+
+ (make-variable-buffer-local 'TeX-output-extension)
+
+(defcustom TeX-Biber-file-extensions '("bib" "ris" "xml")
+ "Valid file extensions for Biber files."
+ :group 'TeX-file-extension
+ :type '(repeat (regexp :format "%v")))
+
+(defcustom BibTeX-file-extensions '("bib")
+ "Valid file extensions for BibTeX files."
+ :group 'TeX-file-extension
+ :type '(repeat (regexp :format "%v")))
+
+(defcustom BibLaTeX-style-extensions '("bbx")
+ "Valid file extensions for BibLaTeX styles."
+ :group 'TeX-file-extension
+ :type '(repeat (regexp :format "%v")))
+
+(defcustom BibTeX-style-extensions '("bst")
+ "Valid file extensions for BibTeX styles."
+ :group 'TeX-file-extension
+ :type '(repeat (regexp :format "%v")))
+
+(defun TeX-match-extension (file &optional extensions)
+ "Return non-nil if FILE has one of EXTENSIONS.
+
+If EXTENSIONS is not specified or nil, the value of
+`TeX-file-extensions' is used instead."
+
+ (if (null extensions)
+ (setq extensions TeX-file-extensions))
+
+ (let ((regexp (concat "\\.\\("
+ (mapconcat #'identity extensions "\\|")
+ "\\)$"))
+ (case-fold-search t))
+ (string-match regexp file)))
+
+(defun TeX-strip-extension (&optional string extensions nodir nostrip)
+ "Return STRING without any trailing extension in EXTENSIONS.
+If NODIR is t, also remove directory part of STRING.
+If NODIR is `path', remove directory part of STRING if it is
+equal to the current directory or is a member of
+`TeX-macro-private' or `TeX-macro-global'.
+If NOSTRIP is set, do not remove extension after all.
+STRING defaults to the name of the current buffer.
+EXTENSIONS defaults to `TeX-file-extensions'."
+
+ (if (null string)
+ (setq string (or (buffer-file-name) "<none>")))
+
+ (if (null extensions)
+ (setq extensions TeX-file-extensions))
+
+ (let* ((strip (if (and (not nostrip)
+ (TeX-match-extension string extensions))
+ (substring string 0 (match-beginning 0))
+ string))
+ (dir (expand-file-name (or (file-name-directory strip) "./"))))
+ (if (or (eq nodir t)
+ (string-equal dir (expand-file-name "./"))
+ (member dir (mapcar #'file-name-as-directory TeX-macro-global))
+ (member dir (mapcar #'file-name-as-directory TeX-macro-private)))
+ (file-name-nondirectory strip)
+ strip)))
+
+
+;;; File Searching
+
+(defun TeX-tree-roots ()
+ "Return a list of available TeX tree roots."
+ (let (list)
+ (dolist (dir (TeX-tree-expand '("$TEXMFHOME" "$TEXMFMAIN" "$TEXMFLOCAL"
+ "$TEXMFDIST")
+ "latex"))
+ (when (file-readable-p dir)
+ (cl-pushnew dir list :test #'equal)))
+ (nreverse list)))
+
+(defcustom TeX-tree-roots (TeX-tree-roots)
+ "List of all available TeX tree root directories."
+ :group 'TeX-file
+ :type '(repeat directory))
+
+;; We keep this function in addition to `TeX-search-files' because it
+;; is faster. Since it does not look further into subdirectories,
+;; this comes at the price of finding a smaller number of files.
+(defun TeX-search-files-kpathsea (var extensions scope nodir strip)
+ "Return a list of files in directories determined by expanding VAR.
+Only files which match EXTENSIONS are returned. SCOPE defines
+the scope for the search and can be `local' or `global' besides
+nil. If NODIR is non-nil, remove directory part. If STRIP is
+non-nil, remove file extension."
+ (when TeX-kpathsea-path-delimiter
+ (let ((dirs (if (eq scope 'local)
+ '("./")
+ (TeX-tree-expand (list var) nil)))
+ result)
+ (if (eq scope 'global)
+ (setq dirs (delete "./" dirs)))
+ (setq extensions (concat "\\.\\(?:"
+ (mapconcat #'identity extensions "\\|")
+ "\\)\\'")
+ result (apply #'append (mapcar (lambda (x)
+ (when (file-readable-p x)
+ (directory-files
+ x (not nodir) extensions t)))
+ dirs)))
+ (if strip
+ (mapcar (lambda (x)
+ (if (string-match extensions x)
+ (substring x 0 (match-beginning 0))
+ x))
+ result)
+ result))))
+
+(defun TeX-search-files (&optional directories extensions nodir strip)
+ "Return a list of all reachable files in DIRECTORIES ending with EXTENSIONS.
+If optional argument NODIR is set, remove directory part.
+If optional argument STRIP is set, remove file extension.
+If optional argument DIRECTORIES is set, search in those directories.
+Otherwise, search in all TeX macro directories.
+If optional argument EXTENSIONS is not set, use `TeX-file-extensions'"
+ (when (null extensions)
+ (setq extensions TeX-file-extensions))
+ (when (null directories)
+ (setq directories (cons "./" (append TeX-macro-private TeX-macro-global))))
+ (let (match
+ (TeX-file-recurse (cond ((symbolp TeX-file-recurse)
+ TeX-file-recurse)
+ ((zerop TeX-file-recurse)
+ nil)
+ ((1- TeX-file-recurse)))))
+ (while directories
+ (let* ((directory (car directories))
+ (content (and directory
+ (file-readable-p directory)
+ (file-directory-p directory)
+ (directory-files directory))))
+ (setq directories (cdr directories))
+ (while content
+ (let ((file (concat directory (car content))))
+ (setq content (cdr content))
+ (cond ((string-match TeX-ignore-file file))
+ ((not (file-readable-p file)))
+ ((file-directory-p file)
+ (if TeX-file-recurse
+ (setq match
+ (append match
+ (TeX-search-files
+ (list (file-name-as-directory file))
+ extensions nodir strip)))))
+ ((TeX-match-extension file extensions)
+ (setq match (cons (TeX-strip-extension
+ file extensions nodir (not strip))
+ match))))))))
+ match))
+
+;; The variables `TeX-macro-private' and `TeX-macro-global' are not
+;; used for specifying the directories because the number of
+;; directories to be searched should be limited as much as possible
+;; and the TeX-macro-* variables are just too broad for this.
+(defvar TeX-search-files-type-alist
+ '((texinputs "${TEXINPUTS}" ("tex/") TeX-file-extensions)
+ (docs "${TEXDOCS}" ("doc/") TeX-doc-extensions)
+ (bibinputs "${BIBINPUTS}" ("bibtex/bib/") BibTeX-file-extensions)
+ (bstinputs "${BSTINPUTS}" ("bibtex/bst/") BibTeX-style-extensions))
+ "Alist of filetypes with locations and file extensions.
+Each element of the alist consists of a symbol expressing the
+filetype, a variable which can be expanded on kpathsea-based
+systems into the directories where files of the given type
+reside, a list of absolute directories, relative directories
+below the root of a TDS-compliant TeX tree or a list of variables
+with either type of directories as an alternative for
+non-kpathsea-based systems and a list of extensions to be matched
+upon a file search. Note that the directories have to end with a
+directory separator.
+
+Each AUCTeX mode should set the variable buffer-locally with a
+more specific value. See `LaTeX-search-files-type-alist' for an
+example.")
+
+(defun TeX-search-files-by-type (filetype &optional scope nodir strip)
+ "Return a list of files in TeX's search path with type FILETYPE.
+FILETYPE is a symbol used to choose the search paths and
+extensions. See `TeX-search-files-type-alist' for supported
+symbols.
+
+The optional argument SCOPE sets the scope for the search.
+Besides nil the symbols `local' and `global' are accepted.
+`local' means to search in the current directory only, `global'
+in the global directories only and nil in both.
+
+If optional argument NODIR is non-nil, remove directory part.
+
+If optional argument STRIP is non-nil, remove file extension."
+ (let* ((gc-cons-threshold 10000000)
+ (spec (assq filetype TeX-search-files-type-alist))
+ (kpse-var (nth 1 spec))
+ (rawdirs (nth 2 spec))
+ (exts (nth 3 spec))
+ expdirs dirs local-files)
+ (setq exts (if (symbolp exts) (eval exts t) exts))
+ (or (TeX-search-files-kpathsea kpse-var exts scope nodir strip)
+ (progn
+ (unless (eq scope 'global)
+ (setq local-files
+ (let ((TeX-file-recurse nil))
+ (TeX-search-files '("./") exts nodir strip))))
+ (if (eq scope 'local)
+ local-files
+ (if (null TeX-tree-roots)
+ (error "No TeX trees available; configure `TeX-tree-roots'")
+ ;; Expand variables.
+ (setq expdirs
+ ;; Don't use `delete-dups' instead of
+ ;; `TeX-delete-duplicate-strings' here.
+ ;; Otherwise, when the last element of `rawdirs'
+ ;; is a variable, its value might be truncated as
+ ;; side effect.
+ (TeX-delete-duplicate-strings
+ (apply #'append
+ (mapcar (lambda (rawdir)
+ (if (symbolp rawdir)
+ (symbol-value rawdir)
+ (list rawdir)))
+ rawdirs))))
+ ;; Assumption: Either all paths are absolute or all are relative.
+ (if (file-name-absolute-p (car expdirs))
+ (setq dirs expdirs)
+ ;; Append relative TDS subdirs to all TeX tree roots.
+ (dolist (root TeX-tree-roots)
+ (dolist (dir expdirs)
+ (let ((dir (expand-file-name dir root)))
+ (unless (member dir dirs)
+ (setq dirs (append dirs (list dir)))))))))
+ (append local-files (TeX-search-files dirs exts nodir strip)))))))
+
+;;; Narrowing
+
+(defun TeX-narrow-to-group ()
+ "Make text outside current group invisible."
+ (interactive)
+ (save-excursion
+ (widen)
+ (let ((opoint (point))
+ beg end)
+ (if (null (search-backward "{" nil t))
+ (message "Nothing to be narrowed here.")
+ (setq beg (point))
+ (forward-sexp)
+ (setq end (point))
+ (if (< end opoint)
+ (message "Nothing to be narrowed here.")
+ (narrow-to-region beg end))))))
+(put 'TeX-narrow-to-group 'disabled t)
+
+;;; Utilities
+;;
+;; Some of these functions has little to do with TeX, but nonetheless we
+;; should use the "TeX-" prefix to avoid name clashes.
+
+(defun TeX-listify (elt)
+ "Return a newly created list with element ELT.
+If ELT already is a list, return ELT."
+ (if (listp elt) elt (list elt)))
+
+(defun TeX-member (elt list how)
+ "Return the member ELT in LIST. Comparison done with HOW.
+Return nil if ELT is not a member of LIST."
+ (while (and list (not (funcall how elt (car list))))
+ (setq list (cdr list)))
+ (car-safe list))
+
+(defun TeX-elt-of-list-member (elts list)
+ "Return non-nil if an element of ELTS is a member of LIST."
+ (catch 'found
+ (dolist (elt elts)
+ (when (member elt list)
+ (throw 'found t)))))
+
+;; Compatibility alias
+(defun TeX-assoc (key list)
+ (assoc-string key list t))
+(make-obsolete 'TeX-assoc
+ "use (assoc-string KEY LIST t) instead." "AUCTeX 13.0")
+
+(defun TeX-match-buffer (n)
+ "Return the substring corresponding to the N'th match.
+See `match-data' for details."
+ (if (match-beginning n)
+ (buffer-substring-no-properties (match-beginning n) (match-end n))
+ ""))
+
+(defun TeX-looking-at-backward (regexp &optional limit)
+ "Return non-nil if the text before point matches REGEXP.
+Optional second argument LIMIT gives a max number of characters
+to look backward for."
+ (let ((pos (point)))
+ (save-excursion
+ (and (re-search-backward regexp
+ (if limit (max (point-min) (- (point) limit)))
+ t)
+ (eq (match-end 0) pos)))))
+
+(defun TeX-current-line ()
+ "The current line number."
+ (format "%d" (1+ (TeX-current-offset))))
+
+(defun TeX-current-file-name-master-relative ()
+ "Return current filename, relative to master directory."
+ (file-relative-name
+ (buffer-file-name)
+ (TeX-master-directory)))
+
+(defun TeX-near-bobp ()
+ "Return t if there's nothing but whitespace between (bob) and (point)."
+ (save-excursion
+ (skip-chars-backward " \t\n")
+ (bobp)))
+
+(defun TeX-add-to-alist (alist-var new-alist)
+ "Add NEW-ALIST to the ALIST-VAR.
+If an element with the same key as the key of an element of
+NEW-ALIST is already present in ALIST-VAR, add the new values to
+it; if a matching element is not already present, append the new
+element to ALIST-VAR."
+ ;; Loop over all elements of NEW-ALIST.
+ (while new-alist
+ (let* ((new-element (car new-alist))
+ ;; Get the element of ALIST-VAR with the same key of the current
+ ;; element of NEW-ALIST, if any.
+ (old-element (assoc (car new-element) (symbol-value alist-var))))
+ (if old-element
+ (progn
+ (set alist-var (delete old-element (symbol-value alist-var)))
+ ;; Append to `old-element' the values of the current element of
+ ;; NEW-ALIST.
+ (mapc (lambda (elt)
+ (unless (member elt (cdr old-element))
+ (setq old-element (append old-element (list elt)))))
+ (cdr new-element))
+ (add-to-list alist-var old-element t))
+ (add-to-list alist-var new-element t)))
+ ;; Next element of NEW-ALIST.
+ (setq new-alist (cdr new-alist))))
+
+;;; Syntax Table
+
+(defvar TeX-mode-syntax-table (make-syntax-table)
+ "Syntax table used while in TeX mode.")
+
+ (make-variable-buffer-local 'TeX-mode-syntax-table)
+
+(progn ; Define TeX-mode-syntax-table.
+ (modify-syntax-entry (string-to-char TeX-esc)
+ "\\" TeX-mode-syntax-table)
+ (modify-syntax-entry ?\f ">" TeX-mode-syntax-table)
+ (modify-syntax-entry ?\n ">" TeX-mode-syntax-table)
+ (modify-syntax-entry (string-to-char TeX-grop)
+ (concat "(" TeX-grcl)
+ TeX-mode-syntax-table)
+ (modify-syntax-entry (string-to-char TeX-grcl)
+ (concat ")" TeX-grop)
+ TeX-mode-syntax-table)
+ (modify-syntax-entry ?% "<" TeX-mode-syntax-table)
+ (modify-syntax-entry ?\" "." TeX-mode-syntax-table)
+ (modify-syntax-entry ?& "." TeX-mode-syntax-table)
+ (modify-syntax-entry ?_ "." TeX-mode-syntax-table)
+ (modify-syntax-entry ?@ "_" TeX-mode-syntax-table)
+ (modify-syntax-entry ?~ "." TeX-mode-syntax-table)
+ (modify-syntax-entry ?$ "$" TeX-mode-syntax-table)
+ (modify-syntax-entry ?' "w" TeX-mode-syntax-table)
+ (modify-syntax-entry ?« "." TeX-mode-syntax-table)
+ (modify-syntax-entry ?» "." TeX-mode-syntax-table)
+ (modify-syntax-entry ?| "." TeX-mode-syntax-table))
+
+;;; Menu Support
+
+(defvar TeX-command-current #'TeX-command-master
+ "Specify whether to run command on master, buffer or region.")
+;; Function used to run external command.
+
+(defun TeX-command-select-master ()
+ "Determine that the next command will be on the master file."
+ (interactive)
+ (message "Next command will be on the master file.")
+ (setq TeX-command-current #'TeX-command-master))
+
+(defun TeX-command-select-buffer ()
+ "Determine that the next command will be on the buffer."
+ (interactive)
+ (message "Next command will be on the buffer")
+ (setq TeX-command-current #'TeX-command-buffer))
+
+(defun TeX-command-select-region ()
+ "Determine that the next command will be on the region."
+ (interactive)
+ (message "Next command will be on the region")
+ (setq TeX-command-current #'TeX-command-region))
+
+(defvar TeX-command-force nil)
+;; If non-nil, TeX-command-query will return the value of this
+;; variable instead of quering the user.
+
+(defun TeX-command-menu (name)
+ "Execute `TeX-command-list' NAME from a menu."
+ (let ((TeX-command-force name))
+ (funcall TeX-command-current)))
+
+(defun TeX-command-menu-print (printer command name)
+ "Print on PRINTER using method COMMAND to run NAME."
+ (let ((TeX-printer-default (unless (string= printer "Other") printer))
+ (TeX-printer-list (and (string= printer "Other") TeX-printer-list))
+ (TeX-print-command command)
+ (TeX-queue-command command))
+ (TeX-command-menu name)))
+
+(defun TeX-command-menu-printer-entry (entry lookup command name)
+ "Return `TeX-printer-list' ENTRY as a menu item."
+ (vector (nth 0 entry)
+ (list 'TeX-command-menu-print
+ (nth 0 entry)
+ (or (nth lookup entry) command)
+ name)))
+
+(defun TeX-command-menu-entry (entry)
+ "Return `TeX-command-list' ENTRY as a menu item."
+ (let ((name (car entry)))
+ (cond ((and (string-equal name TeX-command-Print)
+ TeX-printer-list)
+ (cons TeX-command-Print
+ (mapcar (lambda (entry)
+ (TeX-command-menu-printer-entry
+ entry 1 TeX-print-command name))
+ (append TeX-printer-list '(("Other"))))))
+ ((and (string-equal name TeX-command-Queue)
+ TeX-printer-list)
+ (cons TeX-command-Queue
+ (mapcar (lambda (entry)
+ (TeX-command-menu-printer-entry
+ entry 2 TeX-queue-command name))
+ (append TeX-printer-list '(("Other"))))))
+ (t
+ (vconcat `(,name (TeX-command-menu ,name))
+ (nthcdr 5 entry))))))
+
+(defconst TeX-command-menu-name "Command"
+ "Name to be displayed for the command menu in all modes defined by AUCTeX.")
+
+;;; Keymap
+
+(defcustom TeX-electric-escape nil
+ "If non-nil, ``\\'' will offer on-the-fly completion.
+In Texinfo-mode, ``@'' will do that job instead and ``\\'' is not
+affected. See `TeX-electric-macro' for detail."
+ :group 'TeX-macro
+ :type 'boolean)
+
+(defcustom TeX-electric-sub-and-superscript nil
+ "If non-nil, insert braces after typing `^' and `_' in math mode."
+ :group 'TeX-macro
+ :type 'boolean)
+
+(defcustom TeX-newline-function #'newline
+ "Function to be called upon pressing `RET'."
+ :group 'TeX-indentation
+ :type '(choice (const newline)
+ (const newline-and-indent)
+ (const reindent-then-newline-and-indent)
+ (sexp :tag "Other")))
+
+(defun TeX-insert-backslash (arg)
+ "Either insert typed key ARG times or call `TeX-electric-macro'.
+`TeX-electric-macro' will be called if `TeX-electric-escape' is non-nil."
+ (interactive "*p")
+ (if TeX-electric-escape
+ (TeX-electric-macro)
+ (self-insert-command arg)))
+
+(defun TeX-insert-sub-or-superscript (arg)
+ "Insert typed key ARG times and possibly a pair of braces.
+Brace insertion is only done if point is in a math construct and
+`TeX-electric-sub-and-superscript' has a non-nil value."
+ (interactive "*p")
+ (self-insert-command arg)
+ (when (and TeX-electric-sub-and-superscript (texmathp))
+ (insert (concat TeX-grop TeX-grcl))
+ (backward-char)))
+
+(defun TeX-newline ()
+ "Call the function specified by the variable `TeX-newline-function'."
+ (interactive) (call-interactively TeX-newline-function))
+
+(defvar TeX-mode-map
+ (let ((map (make-sparse-keymap)))
+ ;; Standard
+ ;; (define-key map "\177" #'backward-delete-char-untabify)
+ (define-key map "\C-c}" #'up-list)
+ (define-key map "\C-c#" #'TeX-normal-mode)
+ (define-key map "\C-c\C-n" #'TeX-normal-mode)
+ (define-key map "\C-c?" #'TeX-documentation-texdoc)
+ (define-key map "\C-c\C-i" #'TeX-goto-info-page)
+ (define-key map "\r" #'TeX-newline)
+
+ ;; From tex.el
+ (define-key map "\"" #'TeX-insert-quote)
+ (define-key map "$" #'TeX-insert-dollar)
+ ;; Removed because LaTeX 2e have a better solution to italic correction.
+ ;; (define-key map "." #'TeX-insert-punctuation)
+ ;; (define-key map "," #'TeX-insert-punctuation)
+ (define-key map "\C-c{" #'TeX-insert-braces)
+ (define-key map "\C-c\C-f" #'TeX-font)
+ (define-key map "\C-c\C-m" #'TeX-insert-macro)
+ (define-key map "\\" #'TeX-insert-backslash)
+ (define-key map "^" #'TeX-insert-sub-or-superscript)
+ (define-key map "_" #'TeX-insert-sub-or-superscript)
+ (define-key map "\e\t" #'TeX-complete-symbol) ;*** Emacs 19 way
+
+ (define-key map "\C-c'" #'TeX-comment-or-uncomment-paragraph) ;*** Old way
+ (define-key map "\C-c:" #'comment-or-uncomment-region) ;*** Old way
+ (define-key map "\C-c\"" #'TeX-uncomment) ;*** Old way
+
+ (define-key map "\C-c;" #'comment-or-uncomment-region)
+ (define-key map "\C-c%" #'TeX-comment-or-uncomment-paragraph)
+
+ (define-key map "\C-c\C-t\C-p" #'TeX-PDF-mode)
+ (define-key map "\C-c\C-t\C-i" #'TeX-interactive-mode)
+ (define-key map "\C-c\C-t\C-s" #'TeX-source-correlate-mode)
+ (define-key map "\C-c\C-t\C-r" #'TeX-pin-region)
+ (define-key map "\C-c\C-w" #'TeX-toggle-debug-bad-boxes); to be removed
+ (define-key map "\C-c\C-t\C-b" #'TeX-toggle-debug-bad-boxes)
+ (define-key map "\C-c\C-t\C-w" #'TeX-toggle-debug-warnings)
+ (define-key map "\C-c\C-t\C-x" #'TeX-toggle-suppress-ignored-warnings)
+ (define-key map "\C-c\C-v" #'TeX-view)
+ (define-key map "\C-c\C-d" #'TeX-save-document)
+ (define-key map "\C-c\C-r" #'TeX-command-region)
+ (define-key map "\C-c\C-b" #'TeX-command-buffer)
+ (define-key map "\C-c\C-c" #'TeX-command-master)
+ (define-key map "\C-c\C-a" #'TeX-command-run-all)
+ (define-key map "\C-c\C-k" #'TeX-kill-job)
+ (define-key map "\C-c\C-l" #'TeX-recenter-output-buffer)
+ (define-key map "\C-c^" #'TeX-home-buffer)
+ (define-key map "\C-c`" #'TeX-next-error)
+ ;; Remap bindings of `next-error'
+ (define-key map [remap next-error] #'TeX-next-error)
+ ;; Remap bindings of `previous-error'
+ (define-key map [remap previous-error] #'TeX-previous-error)
+ ;; From tex-fold.el
+ (define-key map "\C-c\C-o\C-f" #'TeX-fold-mode)
+
+ ;; Multifile
+ (define-key map "\C-c_" #'TeX-master-file-ask) ;*** temporary
+
+ (define-key map "\C-xng" #'TeX-narrow-to-group)
+ map)
+ "Keymap for common TeX and LaTeX commands.")
+
+(defun TeX-mode-specific-command-menu (mode)
+ "Return a Command menu specific to the major MODE."
+ (list TeX-command-menu-name
+ :filter (lambda (&rest _ignored)
+ (TeX-mode-specific-command-menu-entries mode))
+ "Bug."))
+
+(defun TeX-mode-specific-command-menu-entries (mode)
+ "Return the entries for a Command menu specific to the major MODE."
+ (append
+ `("Command on"
+ [ "Master File" TeX-command-select-master
+ :keys "C-c C-c" :style radio
+ :selected (eq TeX-command-current #'TeX-command-master)
+ :help "Commands in this menu work on the Master File"]
+ [ "Buffer" TeX-command-select-buffer
+ :keys "C-c C-b" :style radio
+ :selected (eq TeX-command-current #'TeX-command-buffer)
+ :help "Commands in this menu work on the current buffer"]
+ [ "Region" TeX-command-select-region
+ :keys "C-c C-r" :style radio
+ :selected (eq TeX-command-current #'TeX-command-region)
+ :help "Commands in this menu work on the region"]
+ [ "Fix the Region" TeX-pin-region
+ :active (or (if prefix-arg
+ (<= (prefix-numeric-value prefix-arg) 0)
+ (and (boundp 'TeX-command-region-begin)
+ (markerp TeX-command-region-begin)))
+ mark-active)
+ ;;:visible (eq TeX-command-current 'TeX-command-region)
+ :style toggle
+ :selected (and (boundp 'TeX-command-region-begin)
+ (markerp TeX-command-region-begin))
+ :help "Fix the region for \"Command on Region\""]
+ "-"
+ ["Recenter Output Buffer" TeX-recenter-output-buffer
+ :help "Show the output of current TeX process"]
+ ["Kill Job" TeX-kill-job
+ :help "Kill the current TeX process"]
+ ["Next Error" TeX-next-error
+ :help "Jump to the next error of the last TeX run"]
+ ["Previous Error" TeX-previous-error
+ :help "Jump to the previous error of the last TeX run"
+ :visible TeX-parse-all-errors]
+ ["Error Overview" TeX-error-overview
+ :help "Open an overview of errors occured in the last TeX run"
+ :visible TeX-parse-all-errors]
+ ["Quick View" TeX-view
+ :help "Start a viewer without prompting"]
+ "-"
+ ("TeXing Options"
+ ,@(mapcar (lambda (x)
+ (let ((symbol (car x)) (name (nth 1 x)))
+ `[ ,(format "Use %s engine" name) (TeX-engine-set ',symbol)
+ :style radio :selected (eq TeX-engine ',symbol)
+ :help ,(format "Use %s engine for compiling" name) ]))
+ (TeX-engine-alist))
+ "-"
+ [ "Generate PDF" TeX-PDF-mode
+ :style toggle :selected TeX-PDF-mode
+ :active (not (eq TeX-engine 'omega))
+ :help "Use PDFTeX to generate PDF instead of DVI"]
+ ( "PDF from DVI"
+ :visible TeX-PDF-mode
+ :help "Compile to DVI with (La)TeX and convert to PDF"
+ [ "Compile directly to PDF"
+ (lambda () (interactive) (setq TeX-PDF-from-DVI nil))
+ :style radio :selected (null (TeX-PDF-from-DVI))
+ :help "Compile directly to PDF without intermediate conversions"]
+ [ "dvips + ps2pdf"
+ (lambda () (interactive) (setq TeX-PDF-from-DVI "Dvips"))
+ :style radio :selected (equal (TeX-PDF-from-DVI) "Dvips")
+ :help "Convert DVI to PDF with dvips + ps2pdf sequence"]
+ [ "dvipdfmx"
+ (lambda () (interactive) (setq TeX-PDF-from-DVI "Dvipdfmx"))
+ :style radio :selected (equal (TeX-PDF-from-DVI) "Dvipdfmx")
+ :help "Convert DVI to PDF with dvipdfmx"])
+ [ "Run Interactively" TeX-interactive-mode
+ :style toggle :selected TeX-interactive-mode :keys "C-c C-t C-i"
+ :help "Stop on errors in a TeX run"]
+ [ "Correlate I/O" TeX-source-correlate-mode
+ :style toggle :selected TeX-source-correlate-mode
+ :help "Enable forward and inverse search in the previewer"]
+ ["Debug Bad Boxes" TeX-toggle-debug-bad-boxes
+ :style toggle :selected TeX-debug-bad-boxes :keys "C-c C-t C-b"
+ :help "Make \"Next Error\" show overfull and underfull boxes"]
+ ["Debug Warnings" TeX-toggle-debug-warnings
+ :style toggle :selected TeX-debug-warnings
+ :help "Make \"Next Error\" show warnings"])
+ ["Compile and view" TeX-command-run-all
+ :help "Compile the document until it is ready and open the viewer"])
+ (delq nil
+ (mapcar #'TeX-command-menu-entry
+ (TeX-mode-specific-command-list mode)))))
+
+(defun TeX-mode-specific-command-list (mode)
+ "Return the list of commands available in the given MODE."
+ (let ((full-list TeX-command-list)
+ out-list
+ entry)
+ (while (setq entry (pop full-list))
+ ;; `(nth 4 entry)' may be either an atom in case of which the
+ ;; entry should be present in any mode or a list of major modes.
+ (if (or (atom (nth 4 entry))
+ (memq mode (nth 4 entry)))
+ (push entry out-list)))
+ (nreverse out-list)))
+
+(defvar TeX-fold-menu
+ '("Show/Hide"
+ ["Fold Mode" TeX-fold-mode
+ :style toggle
+ :selected (and (boundp 'TeX-fold-mode) TeX-fold-mode)
+ :help "Toggle folding mode"]
+ "-"
+ ["Hide All in Current Buffer" TeX-fold-buffer
+ :active (and (boundp 'TeX-fold-mode) TeX-fold-mode)
+ :help "Hide all configured TeX constructs in the current buffer"]
+ ["Hide All in Current Region" TeX-fold-region
+ :active (and (boundp 'TeX-fold-mode) TeX-fold-mode)
+ :help "Hide all configured TeX constructs in the marked region"]
+ ["Hide All in Current Paragraph" TeX-fold-paragraph
+ :active (and (boundp 'TeX-fold-mode) TeX-fold-mode)
+ :help "Hide all configured TeX constructs in the paragraph containing point"]
+ ["Hide Current Macro" TeX-fold-macro
+ :active (and (boundp 'TeX-fold-mode) TeX-fold-mode)
+ :help "Hide the macro containing point"]
+ ["Hide Current Environment" TeX-fold-env
+ :visible (not (eq major-mode 'plain-tex-mode))
+ :active (and (boundp 'TeX-fold-mode) TeX-fold-mode)
+ :help "Hide the environment containing point"]
+ ["Hide Current Comment" TeX-fold-comment
+ :active (and (boundp 'TeX-fold-mode) TeX-fold-mode)
+ :help "Hide the comment containing point"]
+ "-"
+ ["Show All in Current Buffer" TeX-fold-clearout-buffer
+ :active (and (boundp 'TeX-fold-mode) TeX-fold-mode)
+ :help "Permanently show all folded content again"]
+ ["Show All in Current Region" TeX-fold-clearout-region
+ :active (and (boundp 'TeX-fold-mode) TeX-fold-mode)
+ :help "Permanently show all folded content in marked region"]
+ ["Show All in Current Paragraph" TeX-fold-clearout-paragraph
+ :active (and (boundp 'TeX-fold-mode) TeX-fold-mode)
+ :help "Permanently show all folded content in paragraph containing point"]
+ ["Show Current Item" TeX-fold-clearout-item
+ :active (and (boundp 'TeX-fold-mode) TeX-fold-mode)
+ :help "Permanently show the item containing point"]
+ "-"
+ ["Hide or Show Current Item" TeX-fold-dwim
+ :active (and (boundp 'TeX-fold-mode) TeX-fold-mode)
+ :help "Hide or show the item containing point"])
+ "Menu definition for commands from tex-fold.el.")
+
+(defvar TeX-customization-menu nil)
+
+(defvar TeX-common-menu-entries
+ `(("Multifile/Parsing"
+ ["Switch to Master File" TeX-home-buffer
+ :help "Switch to buffer of Master File, or buffer of last TeX command"]
+ ["Save Document" TeX-save-document
+ :help "Save all buffers associated with the current Master File"]
+ ["Set Master File" TeX-master-file-ask
+ :active (not (TeX-local-master-p))
+ :help "Set the main file to run TeX commands on"]
+ ["Reset Buffer" TeX-normal-mode
+ :help "Save and reparse the current buffer for style information"]
+ ["Reset AUCTeX" (TeX-normal-mode t) :keys "C-u C-c C-n"
+ :help "Reset buffer and reload AUCTeX style files"])
+ ["Find Documentation..." TeX-documentation-texdoc
+ :help "Get help on commands, packages, or TeX-related topics in general"]
+ ["Read the AUCTeX Manual" TeX-goto-info-page
+ :help "Everything worth reading"]
+ ("Customize AUCTeX"
+ ["Browse Options"
+ (customize-group 'AUCTeX)
+ :help "Open the customization buffer for AUCTeX"]
+ ["Extend this Menu"
+ (progn
+ (easy-menu-add-item
+ nil
+ ;; Ugly hack because docTeX mode uses the LaTeX menu.
+ (list (if (eq major-mode 'doctex-mode) "LaTeX" TeX-base-mode-name))
+ (or TeX-customization-menu
+ (setq TeX-customization-menu
+ (customize-menu-create 'AUCTeX "Customize AUCTeX")))))
+ :help "Make this menu a full-blown customization menu"])
+ ["Report AUCTeX Bug" TeX-submit-bug-report
+ :help ,(format "Problems with AUCTeX %s? Mail us!"
+ AUCTeX-version)]))
+
+
+;;; Verbatim constructs
+
+(defvar TeX-verbatim-p-function nil
+ "Mode-specific function to be called by `TeX-verbatim-p'.
+It must accept optional argument POS for position.")
+(make-variable-buffer-local 'TeX-verbatim-p-function)
+
+;; XXX: We only have an implementation for LaTeX mode at the moment (Oct 2009).
+(defun TeX-verbatim-p (&optional pos)
+ "Return non-nil if position POS is in a verbatim-like construct.
+A mode-specific implementation is required. If it is not
+available, the function always returns nil."
+ (when TeX-verbatim-p-function
+ (funcall TeX-verbatim-p-function pos)))
+
+
+;;; Comments
+
+(defvar TeX-comment-start-regexp "%"
+ "Regular expression matching a comment starter.
+Unlike the variable `comment-start-skip' it should not match any
+whitespace after the comment starter or any character before it.")
+(make-variable-buffer-local 'TeX-comment-start-regexp)
+
+(defun TeX-uncomment ()
+ "Delete comment characters from the beginning of each line in a comment."
+ (interactive)
+ (save-excursion
+ ;; Find first comment line
+ (beginning-of-line)
+ (while (and (looking-at (concat "^[ \t]*" TeX-comment-start-regexp))
+ (not (bobp)))
+ (forward-line -1))
+ (let ((beg (point)))
+ (forward-line 1)
+ ;; Find last comment line
+ (while (and (looking-at (concat "^[ \t]*" TeX-comment-start-regexp))
+ (not (eobp)))
+ (forward-line 1))
+ ;; Uncomment region
+ (uncomment-region beg (point)))))
+
+(defun TeX-comment-or-uncomment-paragraph ()
+ "Comment or uncomment current paragraph."
+ (interactive)
+ (if (TeX-in-commented-line)
+ (TeX-uncomment)
+ (save-excursion
+ (beginning-of-line)
+ ;; Don't do anything if we are in an empty line. If this line
+ ;; is followed by a lot of commented lines, this shall prevent
+ ;; that mark-paragraph skips over these lines and marks a
+ ;; paragraph outside the visible window which might get
+ ;; commented without the user noticing.
+ (unless (looking-at "^[ \t]*$")
+ (mark-paragraph)
+ (comment-region (point) (mark))))))
+
+(defun TeX-in-comment ()
+ "Return non-nil if point is in a comment."
+ (if (or (bolp)
+ (null comment-start-skip)
+ (eq (preceding-char) ?\r))
+ nil
+ (save-excursion
+ (save-match-data
+ (let ((pos (point)))
+ (beginning-of-line)
+ (and (or (looking-at comment-start-skip)
+ (re-search-forward comment-start-skip pos t))
+ (not (TeX-verbatim-p))))))))
+
+(defun TeX-in-commented-line ()
+ "Return non-nil if point is in a line consisting only of a comment.
+The comment can be preceded by whitespace. This means that
+`TeX-in-commented-line' is more general than `TeX-in-line-comment'
+which will not match commented lines with leading whitespace. But
+`TeX-in-commented-line' will match commented lines without leading
+whitespace as well."
+ (save-excursion
+ (forward-line 0)
+ (skip-chars-forward " \t")
+ (string= (buffer-substring-no-properties
+ (point) (min (point-max) (+ (point) (length comment-start))))
+ comment-start)))
+
+(defun TeX-in-line-comment ()
+ "Return non-nil if point is in a line comment.
+A line comment is a comment starting in column one, that is, there is
+no whitespace before the comment sign."
+ (save-excursion
+ (forward-line 0)
+ (string= (buffer-substring-no-properties
+ (point) (min (point-max) (+ (point) (length comment-start))))
+ comment-start)))
+
+(defun TeX-comment-prefix ()
+ "Return the comment prefix of the current line.
+If there are no comment starters after potential whitespace at
+the beginning of the line, return nil."
+ (save-excursion
+ (beginning-of-line)
+ (save-match-data
+ (when (looking-at (concat "\\([ \t]*" TeX-comment-start-regexp "+\\)+"))
+ (match-string 0)))))
+
+(defun TeX-forward-comment-skip (&optional count limit)
+ "Move forward to the next comment skip.
+This may be a switch between commented and not commented adjacent
+lines or between lines with different comment prefixes. With
+argument COUNT do it COUNT times. If argument LIMIT is given, do
+not move point further than this value."
+ (unless count (setq count 1))
+ ;; A value of 0 is nonsense.
+ (when (= count 0) (setq count 1))
+ (unless limit (setq limit (point-max)))
+ (dotimes (_ (abs count))
+ (if (< count 0)
+ (forward-line -1)
+ (beginning-of-line))
+ (let ((prefix (when (looking-at (concat "\\([ \t]*"
+ TeX-comment-start-regexp "+\\)+"))
+ (buffer-substring (+ (line-beginning-position)
+ (current-indentation))
+ (match-end 0)))))
+ (while (save-excursion
+ (and (if (> count 0)
+ (<= (point) limit)
+ (>= (point) limit))
+ (zerop (if (> count 0)
+ (forward-line 1)
+ (forward-line -1)))
+ (if prefix
+ (if (looking-at (concat "\\([ \t]*"
+ TeX-comment-start-regexp
+ "+\\)+"))
+ ;; If the preceding line is a commented line
+ ;; as well, check if the prefixes are
+ ;; identical.
+ (string= prefix
+ (buffer-substring
+ (+ (line-beginning-position)
+ (current-indentation))
+ (match-end 0)))
+ nil)
+ (not (looking-at (concat "[ \t]*"
+ TeX-comment-start-regexp))))))
+ (if (> count 0)
+ (forward-line 1)
+ (forward-line -1)))
+ (if (> count 0)
+ (forward-line 1)))))
+
+(defun TeX-backward-comment-skip (&optional count limit)
+ "Move backward to the next comment skip.
+This may be a switch between commented and not commented adjacent
+lines or between lines with different comment prefixes. With
+argument COUNT do it COUNT times. If argument LIMIT is given, do
+not move point to a position less than this value."
+ (unless count (setq count 1))
+ (when (= count 0) (setq count 1))
+ (unless limit (setq limit (point-min)))
+ (TeX-forward-comment-skip (- count) limit))
+
+(defun TeX-comment-forward (&optional n)
+ "Skip forward over N comments.
+Just like `forward-comment' but only for positive N
+and can use regexps instead of syntax."
+ (comment-normalize-vars)
+ (comment-forward n))
+
+(defun TeX-comment-padding-string ()
+ "Return comment padding as a string.
+The variable `comment-padding' can hold an integer or a string.
+This function will return the appropriate string representation
+regardless of its data type."
+ (if (integerp comment-padding)
+ (make-string comment-padding ? )
+ comment-padding))
+
+
+;;; Indentation
+
+(defgroup TeX-indentation nil
+ "Indentation of TeX buffers in AUCTeX."
+ :group 'AUCTeX)
+
+(defcustom TeX-brace-indent-level 2
+ "The level of indentation produced by an open brace."
+ :group 'TeX-indentation
+ :type 'integer)
+
+(defcustom TeX-indent-open-delimiters ""
+ "Additional open delimiters to increase indentation.
+Include \"[\" to indent inside square brackets.
+See `TeX-brace-count-line' and `TeX-indent-close-delimiters'."
+ :group 'TeX-indentation
+ :type '(string :tag "Open delimiters"))
+
+(defcustom TeX-indent-close-delimiters ""
+ "Additional close delimiters to increase indentation.
+Include \"]\" to indent inside square brackets.
+See `TeX-brace-count-line' and `TeX-indent-open-delimiters'."
+ :group 'TeX-indentation
+ :type '(string :tag "Close delimiters"))
+
+(defun TeX-comment-indent ()
+ "Determine the indentation of a comment."
+ (if (looking-at "%%%")
+ (current-column)
+ (skip-chars-backward " \t")
+ (max (if (bolp) 0 (1+ (current-column)))
+ comment-column)))
+
+(defun TeX-brace-count-line ()
+ "Count indent caused by open/closed braces.
+In addition to \"{\" and \"}\", characters in
+`TeX-indent-open-delimiters' and `TeX-indent-close-delimiters'
+are also taken into account. Ignore them when they are escaped
+by \"\\\". In comments, ignore \"{\" and \"}\" but don't ignore
+additional characters."
+ (save-excursion
+ (let ((count 0) (limit (line-end-position)) char)
+ (while (progn
+ (skip-chars-forward
+ (concat "^{}\\\\"
+ TeX-indent-open-delimiters
+ TeX-indent-close-delimiters)
+ limit)
+ (when (and (< (point) limit)
+ (not (and (memq (setq char (char-after))
+ '(?\{ ?\} ?\\))
+ (TeX-in-comment))))
+ (forward-char)
+ (cond ((memq char (append
+ TeX-indent-open-delimiters
+ '(?\{)))
+ (setq count (+ count TeX-brace-indent-level)))
+ ((memq char (append
+ TeX-indent-close-delimiters
+ '(?\})))
+ (setq count (- count TeX-brace-indent-level)))
+ ((eq char ?\\)
+ (when (< (point) limit)
+ (forward-char)
+ t))))))
+ count)))
+
+;;; Navigation
+
+(defvar TeX-search-syntax-table
+ (let ((table (make-syntax-table (make-char-table 'syntax-table))))
+ ;; Preset mode-independent syntax entries. (Mode-dependent
+ ;; entries are set in the function `TeX-search-syntax-table'.)
+ ;; ?\", ?\( and ?\) explicitly get whitespace syntax because
+ ;; Emacs 21.3 and XEmacs don't generate a completely empty syntax
+ ;; table.
+ (dolist (elt '((?\f . ">") (?\n . ">") (?\" . " ") (?\( . " ") (?\) . " ")))
+ (modify-syntax-entry (car elt) (cdr elt) table))
+ table)
+ "Syntax table used for searching purposes.
+It should be accessed through the function `TeX-search-syntax-table'.")
+
+(defun TeX-search-syntax-table (&rest args)
+ "Return a syntax table for searching purposes.
+ARGS may be a list of characters. For each of them the
+respective predefined syntax is set. Currently the parenthetical
+characters ?{, ?}, ?[, ?], ?\(, ?\), ?<, and ?> are supported.
+The syntax of each of these characters not specified will be
+reset to \" \"."
+ (let ((char-syntax-alist '((?\{ . "(}") (?\} . "){")
+ (?\[ . "(]") (?\] . ")[")
+ (?\( . "()") (?\) . ")(")
+ (?\< . "(>") (?\> . ")<"))))
+ ;; Clean entries possibly set before.
+ (modify-syntax-entry ?\\ " " TeX-search-syntax-table)
+ (modify-syntax-entry ?@ " " TeX-search-syntax-table)
+ (modify-syntax-entry ?\% " " TeX-search-syntax-table)
+ ;; Preset mode-dependent syntax entries. (Mode-independent entries
+ ;; are set when the variable `TeX-search-syntax-table' is created.)
+ (modify-syntax-entry (string-to-char TeX-esc) "\\" TeX-search-syntax-table)
+ (unless (eq major-mode 'texinfo-mode)
+ (modify-syntax-entry ?\% "<" TeX-search-syntax-table))
+ ;; Clean up the entries which can be specified as arguments.
+ (dolist (elt char-syntax-alist)
+ (modify-syntax-entry (car elt) " " TeX-search-syntax-table))
+ ;; Now set what we got.
+ (dolist (elt args)
+ (unless (assoc elt char-syntax-alist) (error "Char not supported"))
+ (modify-syntax-entry elt (cdr (assoc elt char-syntax-alist))
+ TeX-search-syntax-table))
+ ;; Return the syntax table.
+ TeX-search-syntax-table))
+
+(defun TeX-find-balanced-brace (&optional count depth limit)
+ "Return the position of a balanced brace in a TeX group.
+The function scans forward COUNT parenthetical groupings.
+Default is 1. If COUNT is negative, it searches backwards. With
+optional DEPTH>=1, find that outer level. If LIMIT is non-nil,
+do not search further than this position in the buffer."
+ (let ((count (if count
+ (if (= count 0) (error "COUNT has to be <> 0") count)
+ 1))
+ (depth (if depth
+ (if (< depth 1) (error "DEPTH has to be > 0") depth)
+ 1)))
+ (save-restriction
+ (when limit
+ (if (> count 0)
+ (narrow-to-region (point-min) limit)
+ (narrow-to-region limit (point-max))))
+ (with-syntax-table (TeX-search-syntax-table ?\{ ?\})
+ (condition-case nil
+ (scan-lists (point) count depth)
+ (error nil))))))
+
+(defun TeX-find-closing-brace (&optional depth limit)
+ "Return the position of the closing brace in a TeX group.
+The function assumes that point is inside the group, that is, after
+an opening brace. With optional DEPTH>=1, find that outer level.
+If LIMIT is non-nil, do not search further down than this
+position in the buffer."
+ (TeX-find-balanced-brace 1 depth limit))
+
+(defun TeX-find-opening-brace (&optional depth limit)
+ "Return the position of the opening brace in a TeX group.
+The function assumes that point is inside the group, that is, before
+a closing brace. With optional DEPTH>=1, find that outer level.
+If LIMIT is non-nil, do not search further up than this position
+in the buffer."
+ (TeX-find-balanced-brace -1 depth limit))
+
+(defun TeX-find-macro-boundaries (&optional lower-bound)
+ "Return a list containing the start and end of a macro.
+If LOWER-BOUND is given, do not search backward further than this
+point in buffer. Arguments enclosed in brackets or braces are
+considered part of the macro."
+ (save-restriction
+ (when lower-bound
+ (narrow-to-region lower-bound (point-max)))
+ (let ((orig-point (point))
+ start-point)
+ ;; Point is located directly at the start of a macro. (-!-\foo{bar})
+ (when (and (eq (char-after) (aref TeX-esc 0))
+ (not (TeX-escaped-p)))
+ (setq start-point (point)))
+ ;; Point is located on a macro. (\fo-!-o{bar})
+ (unless start-point
+ (save-excursion
+ (skip-chars-backward "A-Za-z@*")
+ (when (and (eq (char-before) (aref TeX-esc 0))
+ (not (TeX-escaped-p (1- (point)))))
+ (setq start-point (1- (point))))))
+ ;; Point is located in the argument of a macro. (\foo{ba-!-r})
+ (unless start-point
+ (save-excursion
+ (catch 'abort
+ (let ((parse-sexp-ignore-comments t))
+ (when (condition-case nil (progn (up-list) t) (error nil))
+ (while (progn
+ (condition-case nil (backward-sexp)
+ (error (throw 'abort nil)))
+ (forward-comment -1)
+ (and (memq (char-before) '(?\] ?\}))
+ (not (TeX-escaped-p (1- (point)))))))
+ (skip-chars-backward "A-Za-z@*")
+ (when (and (eq (char-before) (aref TeX-esc 0))
+ (not (TeX-escaped-p (1- (point)))))
+ (setq start-point (1- (point)))))))))
+ ;; Search forward for the end of the macro.
+ (when start-point
+ (save-excursion
+ (goto-char (TeX-find-macro-end-helper start-point))
+ (if (< orig-point (point))
+ (cons start-point (point))
+ nil))))))
+
+(defun TeX-find-macro-end-helper (start)
+ "Find the end of a macro given its START.
+START is the position just before the starting token of the macro.
+If the macro is followed by square brackets or curly braces,
+those will be considered part of it."
+ (save-excursion
+ (save-match-data
+ (catch 'found
+ (goto-char (1+ start))
+ (if (zerop (skip-chars-forward "A-Za-z@"))
+ (forward-char)
+ (skip-chars-forward "*"))
+ (while (not (eobp))
+ (cond
+ ;; Skip over pairs of square brackets
+ ((or (looking-at "[ \t]*\n?\\(\\[\\)") ; Be conservative: Consider
+ ; only consecutive lines.
+ (and (looking-at (concat "[ \t]*" TeX-comment-start-regexp))
+ (save-excursion
+ (forward-line 1)
+ (looking-at "[ \t]*\\(\\[\\)"))))
+ (goto-char (match-beginning 1))
+ (condition-case nil
+ (forward-sexp)
+ (scan-error (throw 'found (point)))))
+ ;; Skip over pairs of curly braces
+ ((or (looking-at "[ \t]*\n?{") ; Be conservative: Consider
+ ; only consecutive lines.
+ (and (looking-at (concat "[ \t]*" TeX-comment-start-regexp))
+ (save-excursion
+ (forward-line 1)
+ (looking-at "[ \t]*{"))))
+ (goto-char (match-end 0))
+ (goto-char (or (TeX-find-closing-brace)
+ ;; If we cannot find a regular end, use the
+ ;; next whitespace.
+ (save-excursion (skip-chars-forward "^ \t\n")
+ (point)))))
+ (t
+ (throw 'found (point)))))
+ ;; Make sure that this function does not return nil, even
+ ;; when the above `while' loop is totally skipped. (bug#35638)
+ (throw 'found (point))))))
+
+(defun TeX-find-macro-start (&optional limit)
+ "Return the start of a macro.
+If LIMIT is given, do not search backward further than this point
+in buffer. Arguments enclosed in brackets or braces are
+considered part of the macro."
+ (car (TeX-find-macro-boundaries limit)))
+
+(defun TeX-find-macro-end ()
+ "Return the end of a macro.
+Arguments enclosed in brackets or braces are considered part of
+the macro."
+ (cdr (TeX-find-macro-boundaries)))
+
+(defun TeX-search-forward-unescaped (string &optional bound noerror)
+ "Search forward from point for unescaped STRING.
+The optional argument BOUND limits the search to the respective
+buffer position.
+If NOERROR is non-nil, return nil if the search failed instead of
+throwing an error.
+A pattern is escaped, if it is preceded by an odd number of escape
+characters."
+ (TeX-search-unescaped string 'forward nil bound noerror))
+
+(defun TeX-search-backward-unescaped (string &optional bound noerror)
+ "Search backward from point for unescaped STRING.
+The optional argument BOUND limits the search to the respective
+buffer position.
+If NOERROR is non-nil, return nil if the search failed instead of
+throwing an error.
+A pattern is escaped, if it is preceded by an odd number of escape
+characters."
+ (TeX-search-unescaped string 'backward nil bound noerror))
+
+(defun TeX-re-search-forward-unescaped (regexp &optional bound noerror)
+ "Search forward from point for unescaped regular expression REGEXP.
+The optional argument BOUND limits the search to the respective
+buffer position.
+If NOERROR is non-nil, return nil if the search failed instead of
+throwing an error.
+A pattern is escaped, if it is preceded by an odd number of escape
+characters."
+ (TeX-search-unescaped regexp 'forward t bound noerror))
+
+(defun TeX-search-unescaped (pattern
+ &optional direction regexp-flag bound noerror)
+ "Search for unescaped PATTERN in a certain DIRECTION.
+DIRECTION can be indicated by the symbols 'forward and 'backward.
+If DIRECTION is omitted, a forward search is carried out.
+If REGEXP-FLAG is non-nil, PATTERN may be a regular expression,
+otherwise a string.
+The optional argument BOUND limits the search to the respective
+buffer position.
+If NOERROR is non-nil, return nil if the search failed instead of
+throwing an error.
+A pattern is escaped, if it is preceded by an odd number of escape
+characters."
+ (let ((search-fun (if (eq direction 'backward)
+ (if regexp-flag 're-search-backward 'search-backward)
+ (if regexp-flag 're-search-forward 'search-forward))))
+ (catch 'found
+ (while (funcall search-fun pattern bound noerror)
+ (when (not (TeX-escaped-p (match-beginning 0)))
+ (throw 'found (point)))))))
+
+(defun TeX-escaped-p (&optional pos)
+ "Return t if the character at position POS is escaped.
+If POS is omitted, examine the character at point.
+A character is escaped if it is preceded by an odd number of
+escape characters, such as \"\\\" in LaTeX."
+ (save-excursion
+ (when pos (goto-char pos))
+ (not (zerop (mod (skip-chars-backward (regexp-quote TeX-esc)) 2)))))
+
+(defun TeX-current-macro ()
+ "Return the name of the macro containing point, nil if there is none."
+ (let ((macro-start (TeX-find-macro-start)))
+ (when macro-start
+ (save-excursion
+ (goto-char macro-start)
+ (forward-char (length TeX-esc))
+ (buffer-substring-no-properties
+ (point) (progn (skip-chars-forward "@A-Za-z*") (point)))))))
+
+(defvar TeX-search-forward-comment-start-function nil
+ "Function to find the start of a comment.
+The function should accept an optional argument for specifying
+the limit of the search. It should return the position just
+before the comment if one is found and nil otherwise. Point
+should not be moved.")
+(make-variable-buffer-local 'TeX-search-forward-comment-start-function)
+
+(defun TeX-search-forward-comment-start (&optional limit)
+ "Search forward for a comment start from current position till LIMIT.
+If LIMIT is omitted, search till the end of the buffer.
+
+The search relies on `TeX-comment-start-regexp' being set
+correctly for the current mode.
+
+Set `TeX-search-forward-comment-start-function' in order to
+override the default implementation."
+ (if TeX-search-forward-comment-start-function
+ (funcall TeX-search-forward-comment-start-function limit)
+ (setq limit (or limit (point-max)))
+ (when (TeX-re-search-forward-unescaped TeX-comment-start-regexp limit t)
+ (match-beginning 0))))
+
+;;; Fonts
+
+(defcustom TeX-font-list '((?\C-b "{\\bf " "}")
+ (?\C-c "{\\sc " "}")
+ (?\C-e "{\\em " "\\/}")
+ (?\C-i "{\\it " "\\/}")
+ (?\C-r "{\\rm " "}")
+ (?\C-s "{\\sl " "\\/}")
+ (?\C-t "{\\tt " "}")
+ (?\C-d "" "" t))
+ "List of fonts used by `TeX-font'.
+
+Each entry is a list.
+The first element is the key to activate the font.
+The second element is the string to insert before point, and the third
+element is the string to insert after point.
+If the fourth and fifth element are strings, they specify the prefix and
+suffix to be used in math mode.
+An optional fourth (or sixth) element means always replace if t."
+ :group 'TeX-macro
+ :type '(repeat
+ (group
+ :value (?\C-a "" "")
+ (character :tag "Key")
+ (string :tag "Prefix")
+ (string :tag "Suffix")
+ (option (group
+ :inline t
+ (string :tag "Math Prefix")
+ (string :tag "Math Suffix")))
+ (option (sexp :format "Replace\n" :value t)))))
+
+(defvar TeX-font-replace-function #'TeX-font-replace
+ "Determines the function which is called when a font should be replaced.")
+
+(defun TeX-describe-font-entry (entry)
+ "A textual description of an ENTRY in `TeX-font-list'."
+ (concat (format "%16s " (key-description (char-to-string (nth 0 entry))))
+ (if (or (eq t (nth 3 entry)) (eq t (nth 5 entry)))
+ "-- delete font"
+ (format "%14s %-3s %14s %-3s"
+ (nth 1 entry) (nth 2 entry)
+ (if (stringp (nth 3 entry)) (nth 3 entry) "")
+ (if (stringp (nth 4 entry)) (nth 4 entry) "")))))
+
+(defun TeX-font (replace what)
+ "Insert template for font change command.
+If REPLACE is not nil, replace current font. WHAT determines the font
+to use, as specified by `TeX-font-list'."
+ (interactive "*P\nc")
+ (TeX-update-style)
+ (let* ((entry (assoc what TeX-font-list))
+ (in-math (texmathp))
+ (before (nth 1 entry))
+ (after (nth 2 entry)))
+ (setq replace (or replace (eq t (nth 3 entry)) (eq t (nth 5 entry))))
+ (if (and in-math (stringp (nth 3 entry)))
+ (setq before (nth 3 entry)
+ after (nth 4 entry)))
+ (cond ((null entry)
+ (let ((help (concat
+ "Font list: "
+ "KEY TEXTFONT MATHFONT\n\n"
+ (mapconcat #'TeX-describe-font-entry
+ TeX-font-list "\n"))))
+ (with-output-to-temp-buffer "*Help*"
+ (set-buffer "*Help*")
+ (insert help))))
+ (replace
+ (funcall TeX-font-replace-function before after))
+ ((TeX-active-mark)
+ (save-excursion
+ (cond ((> (mark) (point))
+ (insert before)
+ (goto-char (mark))
+ (insert after))
+ (t
+ (insert after)
+ (goto-char (mark))
+ (insert before)))))
+ (t
+ (insert before)
+ (save-excursion
+ (insert after))))))
+
+(defun TeX-font-replace (start end)
+ "Replace font specification around point with START and END.
+For modes with font specifications like `{\\font text}'.
+See also `TeX-font-replace-macro' and `TeX-font-replace-function'."
+ (save-excursion
+ (while (not (looking-at "{\\\\[a-zA-Z]+ "))
+ (up-list -1))
+ (forward-sexp)
+ (save-excursion
+ (replace-match start t t))
+ (if (save-excursion
+ (backward-char 3)
+ (if (looking-at (regexp-quote "\\/}"))
+ (progn
+ (delete-char 3)
+ nil)
+ t))
+ (delete-char -1))
+ (insert end)))
+
+(defun TeX-font-replace-macro (start end)
+ "Replace font specification around point with START and END.
+For modes with font specifications like `\\font{text}'.
+See also `TeX-font-replace' and `TeX-font-replace-function'."
+ (let ((font-list TeX-font-list)
+ cmds strings regexp)
+ (while font-list
+ (setq strings (cdr (car font-list))
+ font-list (cdr font-list))
+ (and (stringp (car strings)) (null (string= (car strings) ""))
+ (setq cmds (cons (car strings) cmds)))
+ (setq strings (cdr (cdr strings)))
+ (and (stringp (car strings)) (null (string= (car strings) ""))
+ (setq cmds (cons (car strings) cmds))))
+ (setq regexp (mapconcat #'regexp-quote cmds "\\|"))
+ (save-excursion
+ (catch 'done
+ (while t
+ (if (/= ?\\ (following-char))
+ (skip-chars-backward "a-zA-Z "))
+ (skip-chars-backward (regexp-quote TeX-esc))
+ (if (looking-at regexp)
+ (throw 'done t)
+ (up-list -1))))
+ ;; Use stripped syntax table in order to get stuff like "\emph{(}" right.
+ (with-syntax-table (TeX-search-syntax-table ?\{ ?\})
+ (forward-sexp 2))
+ (save-excursion
+ (replace-match start t t))
+ (delete-char -1)
+ (insert end))))
+
+;;; Dollars
+;;
+;; Rewritten from scratch with use of `texmathp' by
+;; Carsten Dominik <dominik@strw.leidenuniv.nl>
+
+(defvar TeX-symbol-marker nil)
+
+(defvar TeX-symbol-marker-pos 0)
+
+;; The following constants are no longer used, but kept in case some
+;; foreign code uses any of them.
+(defvar TeX-dollar-sign ?$
+ "Character used to enter and leave math mode in TeX.")
+(defconst TeX-dollar-string (char-to-string TeX-dollar-sign))
+(defconst TeX-dollar-regexp
+ (concat "^" (regexp-quote TeX-dollar-string) "\\|[^" TeX-esc "]"
+ (regexp-quote TeX-dollar-string)))
+
+(defcustom TeX-math-toggle-off-input-method t
+ "If non-nil, auto turn off some input methods when entering math mode.
+See `TeX-math-input-method-off-regexp'."
+ :group 'TeX-macro
+ :type 'boolean)
+
+(defcustom TeX-electric-math nil
+ "If non-nil, when outside math mode `TeX-insert-dollar' will
+insert symbols for opening and closing inline equation and put
+the point between them. If there is an active region,
+`TeX-insert-dollar' will put around it symbols for opening and
+closing inline equation and keep the region active, with point
+after closing symbol. If you press `$' again, you can toggle
+between inline equation, display equation, and no equation.
+
+If non-nil and point is inside math mode right between a couple
+of single dollars, pressing `$' will insert another pair of
+dollar signs and leave the point between them.
+
+If nil, `TeX-insert-dollar' will simply insert \"$\" at point,
+this is the default.
+
+If non-nil, this variable is a cons cell whose CAR is the string
+to insert before point, the CDR is the string to insert after
+point. You can choose between \"$...$\" and \"\\(...\\)\"."
+ :group 'TeX-macro
+ :type '(choice (const :tag "No electricity" nil)
+ (const :tag "$...$" ("$" . "$"))
+ (const :tag "\\(...\\)" ("\\(" . "\\)"))
+ (cons :tag "Other"
+ (string :tag "Insert before point")
+ (string :tag "Insert after point"))))
+
+(defun TeX-insert-dollar (&optional arg)
+ "Insert dollar sign.
+
+If current math mode was not entered with a dollar, refuse to
+insert one. Show matching dollar sign if this dollar sign ends
+the TeX math mode and `blink-matching-paren' is non-nil.
+
+When outside math mode, the behavior is controlled by the variable
+`TeX-electric-math'.
+
+With raw \\[universal-argument] prefix, insert exactly one dollar
+sign. With optional ARG, insert that many dollar signs."
+ (interactive "P")
+ (cond
+ ((and arg (listp arg))
+ ;; C-u always inserts one
+ (insert "$"))
+ (arg
+ ;; Numerical arg inserts that many
+ (insert (make-string (prefix-numeric-value arg) ?\$)))
+ ((or (TeX-escaped-p) (TeX-verbatim-p))
+ ;; Point is escaped with `\' or is in a verbatim-like construct, so just
+ ;; insert one $.
+ (insert "$"))
+ ((texmathp)
+ ;; We are inside math mode
+ (cond
+ ((and TeX-electric-math
+ (eq (preceding-char) ?\$)
+ (eq (following-char) ?\$))
+ ;; Point is between "$$" and `TeX-electric-math' is non-nil - insert
+ ;; another pair of dollar signs and leave point between them.
+ (insert "$$")
+ (backward-char))
+ ((and (stringp (car texmathp-why))
+ (string-equal (substring (car texmathp-why) 0 1) "\$"))
+ ;; Math mode was turned on with $ or $$ - insert a single $.
+ (insert "$")
+ ;; Compatibility, `TeX-math-close-double-dollar' has been removed
+ ;; after AUCTeX 11.87.
+ (if (boundp 'TeX-math-close-double-dollar)
+ (message
+ (concat "`TeX-math-close-double-dollar' has been removed,"
+ "\nplease use `TeX-electric-math' instead.")))
+ (when (and blink-matching-paren
+ (or (string= (car texmathp-why) "$")
+ (zerop (mod (save-excursion
+ (skip-chars-backward "$")) 2))))
+ (save-excursion
+ (goto-char (cdr texmathp-why))
+ (if (pos-visible-in-window-p)
+ (sit-for blink-matching-delay)
+ (message "Matches %s"
+ (buffer-substring
+ (point) (progn (end-of-line) (point))))))))
+ (t
+ ;; Math mode was not entered with dollar - we cannot finish it with one.
+ (message "Math mode started with `%s' cannot be closed with dollar"
+ (car texmathp-why)))))
+ (t
+ ;; Just somewhere in the text.
+ (cond
+ ((and TeX-electric-math (TeX-active-mark))
+ (if (> (point) (mark))
+ (exchange-point-and-mark))
+ (cond
+ ;; $...$ to $$...$$
+ ((and (eq last-command #'TeX-insert-dollar)
+ (re-search-forward "\\=\\$\\([^$][^z-a]*[^$]\\)\\$" (mark) t))
+ (replace-match "$$\\1$$")
+ (set-mark (match-beginning 0)))
+ ;; \(...\) to \[...\]
+ ((and (eq last-command #'TeX-insert-dollar)
+ (re-search-forward "\\=\\\\(\\([^z-a]*\\)\\\\)" (mark) t))
+ (replace-match "\\\\[\\1\\\\]")
+ (set-mark (match-beginning 0)))
+ ;; Strip \[...\] or $$...$$
+ ((and (eq last-command #'TeX-insert-dollar)
+ (or (re-search-forward "\\=\\\\\\[\\([^z-a]*\\)\\\\\\]" (mark) t)
+ (re-search-forward "\\=\\$\\$\\([^z-a]*\\)\\$\\$" (mark) t)))
+ (replace-match "\\1")
+ (set-mark (match-beginning 0)))
+ (t
+ ;; We use `save-excursion' because point must be situated before opening
+ ;; symbol.
+ (save-excursion (insert (car TeX-electric-math)))
+ (exchange-point-and-mark)
+ (insert (cdr TeX-electric-math))))
+ ;; Keep the region active.
+ (TeX-activate-region))
+ (TeX-electric-math
+ (insert (car TeX-electric-math))
+ (save-excursion (insert (cdr TeX-electric-math)))
+ (if blink-matching-paren
+ (progn
+ (backward-char)
+ (sit-for blink-matching-delay)
+ (forward-char))))
+ ;; In any other case just insert a single $.
+ ((insert "$")))))
+ (TeX-math-input-method-off))
+
+(defcustom TeX-math-input-method-off-regexp
+ (concat "^" (regexp-opt '("chinese" "japanese" "korean" "bulgarian" "russian") t))
+ "Regexp matching input methods to be deactivated when entering math mode."
+ :group 'TeX-misc
+ :type 'regexp)
+
+(defun TeX-math-input-method-off ()
+ "Toggle off input method when entering math mode."
+ (and TeX-math-toggle-off-input-method
+ (texmathp)
+ current-input-method
+ (string-match TeX-math-input-method-off-regexp current-input-method)
+ (deactivate-input-method)))
+
+;;; Simple Commands
+
+(defvar TeX-normal-mode-reset-list '(TeX-style-hook-list)
+ "List of variables to reset with `\\[universal-argument] \\[TeX-normal-mode]'.
+AUCTeX libraries and styles should add variables for reset to
+this list.")
+
+(defun TeX-normal-mode (&optional arg)
+ "Remove all information about this buffer, and apply the style hooks again.
+Save buffer first including style information.
+With optional argument ARG, also reload the style hooks."
+ (interactive "*P")
+ (if arg
+ (dolist (var TeX-normal-mode-reset-list)
+ (set var nil)))
+ (let ((TeX-auto-save t))
+ (if (buffer-modified-p)
+ (save-buffer)
+ (TeX-auto-write)))
+ (normal-mode)
+ ;; See also addition to `find-file-hook' in `VirTeX-common-initialization'.
+ (when (eq TeX-master 'shared) (TeX-master-file nil nil t))
+ (TeX-update-style t))
+
+(defgroup TeX-quote nil
+ "Quoting in AUCTeX."
+ :group 'AUCTeX)
+
+(defcustom TeX-open-quote "``"
+ "String inserted by typing \\[TeX-insert-quote] to open a quotation."
+ :group 'TeX-quote
+ :type 'string)
+
+(defcustom TeX-close-quote "''"
+ "String inserted by typing \\[TeX-insert-quote] to close a quotation."
+ :group 'TeX-quote
+ :type 'string)
+
+(defcustom TeX-quote-after-quote nil
+ "Behaviour of \\[TeX-insert-quote].
+Nil means standard behaviour; when non-nil, opening and closing
+quotes are inserted only after \"."
+ :group 'TeX-quote
+ :type 'boolean)
+
+(defcustom TeX-quote-language-alist nil
+ "Alist for overriding the default language-specific quote insertion.
+First element in each item is the name of the language as set by
+the language style file as a string. Second element is the
+opening quotation mark. Third element is the closing quotation
+mark. Opening and closing quotation marks can be specified
+directly as strings or as functions returning a string. Fourth
+element is a boolean specifying insertion behavior, overriding
+`TeX-quote-after-quote'. See Info node `(auctex)European' for
+valid languages."
+ :group 'TeX-quote
+ :link '(custom-manual "(auctex)European")
+ :type '(repeat (group (choice
+ (const "czech")
+ (const "danish")
+ (const "dutch")
+ (const "german")
+ (const "ngerman")
+ (const "french") ;; not frenchb or francais
+ (const "italian")
+ (const "polish")
+ (const "portuguese")
+ (const "slovak")
+ (const "swedish")
+ (string :tag "Other Language"))
+ (choice :tag "Opening quotation mark" string function)
+ (choice :tag "Closing quotation mark" string function)
+ (boolean :tag "Insert plain quote first" :value t))))
+
+(defvar TeX-quote-language nil
+ "If non-nil determines behavior of quote insertion.
+It is usually set by language-related style files. Its value has
+the same structure as the elements of `TeX-quote-language-alist'.
+The symbol `override' can be used as its car in order to override
+the settings of style files. Style files should therefore check
+if this symbol is present and not alter `TeX-quote-language' if
+it is.")
+(make-variable-buffer-local 'TeX-quote-language)
+
+(defun TeX-insert-quote (force)
+ "Insert the appropriate quotation marks for TeX.
+Inserts the value of `TeX-open-quote' (normally \\=`\\=`) or `TeX-close-quote'
+\(normally \\='\\=') depending on the context. If `TeX-quote-after-quote'
+is non-nil, this insertion works only after \".
+With prefix argument FORCE, always inserts \" characters."
+ (interactive "*P")
+ (if (or force
+ ;; Do not insert TeX quotes in verbatim, math or comment constructs.
+ (and (fboundp 'font-latex-faces-present-p)
+ (font-latex-faces-present-p '(font-latex-verbatim-face
+ font-latex-math-face
+ font-lock-comment-face))
+ (font-latex-faces-present-p '(font-latex-verbatim-face
+ font-latex-math-face
+ font-lock-comment-face)
+ (1- (point))))
+ (texmathp)
+ (and (TeX-in-comment) (not (eq major-mode 'doctex-mode))))
+ (self-insert-command (prefix-numeric-value force))
+ (TeX-update-style)
+ (let* ((lang-override (if (eq (car TeX-quote-language) 'override)
+ TeX-quote-language
+ (assoc (car TeX-quote-language)
+ TeX-quote-language-alist)))
+ (lang (or lang-override TeX-quote-language))
+ (open-quote (if lang (nth 1 lang) TeX-open-quote))
+ (close-quote (if lang (nth 2 lang) TeX-close-quote))
+ (q-after-q (if lang (nth 3 lang) TeX-quote-after-quote)))
+ (when (functionp open-quote)
+ (setq open-quote (funcall open-quote)))
+ (when (functionp close-quote)
+ (setq close-quote (funcall close-quote)))
+ (if q-after-q
+ (insert (cond ((bobp)
+ ?\")
+ ((save-excursion
+ (TeX-looking-at-backward
+ (concat (regexp-quote open-quote) "\\|"
+ (regexp-quote close-quote))
+ (max (length open-quote) (length close-quote))))
+ (delete-char (- (length (match-string 0))))
+ "\"\"")
+ ((< (save-excursion (skip-chars-backward "\"")) -1)
+ ?\")
+ ((not (= (preceding-char) ?\"))
+ ?\")
+ ((save-excursion
+ (forward-char -1)
+ (bobp))
+ (delete-char -1)
+ open-quote)
+ ((save-excursion
+ (forward-char -2) ;;; at -1 there is double quote
+ (looking-at "[ \t\n]\\|\\s("))
+ (delete-char -1)
+ open-quote)
+ (t
+ (delete-char -1)
+ close-quote)))
+ (insert (cond ((bobp)
+ open-quote)
+ ((= (preceding-char) (string-to-char TeX-esc))
+ ?\")
+ ((= (preceding-char) ?\")
+ ?\")
+ ((and (<= (length open-quote) (- (point) (point-min)))
+ (save-excursion
+ (forward-char (- (length open-quote)))
+ (looking-at (regexp-quote open-quote))))
+ (delete-char (- (length open-quote)))
+ ?\")
+ ((and (<= (length open-quote) (- (point) (point-min)))
+ (save-excursion
+ (forward-char (- (length close-quote)))
+ (looking-at (regexp-quote close-quote))))
+ (delete-char (- (length close-quote)))
+ ?\")
+ ((save-excursion
+ (forward-char -1)
+ (looking-at "[ \t\n]\\|\\s("))
+ open-quote)
+ (t
+ close-quote)))))))
+
+(defun TeX-insert-punctuation ()
+ "Insert point or comma, cleaning up preceding space."
+ (interactive)
+ (expand-abbrev)
+ (if (TeX-looking-at-backward "\\\\/\\(}+\\)" 50)
+ (replace-match "\\1" t))
+ (call-interactively #'self-insert-command))
+
+(defun TeX-insert-braces (arg)
+ "Make a pair of braces around next ARG sexps and leave point inside.
+No argument is equivalent to zero: just insert braces and leave point
+between.
+
+If there is an active region, ARG will be ignored, braces will be
+inserted around the region, and point will be left after the
+closing brace."
+ (interactive "P")
+ (if (TeX-active-mark)
+ (progn
+ (if (< (point) (mark))
+ (exchange-point-and-mark))
+ (insert TeX-grcl)
+ (save-excursion
+ (goto-char (mark))
+ (insert TeX-grop)))
+ (insert TeX-grop)
+ (save-excursion
+ (if arg (forward-sexp (prefix-numeric-value arg)))
+ (insert TeX-grcl))))
+
+;;;###autoload
+(defun TeX-submit-bug-report ()
+ "Submit a bug report on AUCTeX via mail.
+
+Don't hesitate to report any problems or inaccurate documentation.
+
+If you don't have setup sending mail from Emacs, please copy the
+output buffer into your mail program, as it gives us important
+information about your AUCTeX version and AUCTeX configuration."
+ (interactive)
+ (require 'reporter)
+ (defvar reporter-prompt-for-summary-p)
+ (let ((reporter-prompt-for-summary-p "Bug report subject: "))
+ (reporter-submit-bug-report
+ "bug-auctex@gnu.org"
+ AUCTeX-version
+ (list 'AUCTeX-date
+ 'window-system
+ 'LaTeX-version
+ 'TeX-style-path
+ 'TeX-auto-save
+ 'TeX-parse-self
+ 'TeX-master
+ 'TeX-command-list)
+ nil
+ ;; reporter adds too many new lines around salutation text, that we don't
+ ;; want, since it's itself a new line.
+ (lambda ()
+ (save-excursion
+ (goto-char (point-min))
+ (re-search-forward mail-header-separator)
+ (forward-char)
+ (delete-char 1)
+ (forward-char)
+ (delete-char 2)))
+ (propertize
+ "\n" 'display
+ (with-temp-buffer
+ (insert
+ "Remember to cover the basics, that is, what you expected to happen and
+what in fact did happen.
+
+Be sure to consult the FAQ section in the manual before submitting
+a bug report. In addition check if the bug is reproducable with an
+up-to-date version of AUCTeX. So please upgrade to the version
+available from ")
+ (insert-text-button
+ "https://www.gnu.org/software/auctex/"
+ 'face 'link
+ 'help-echo (concat "mouse-2, RET: Follow this link")
+ 'action (lambda (_button)
+ (browse-url "https://www.gnu.org/software/auctex/"))
+ 'follow-link t)
+ (insert " if your
+installation is older than the one available from the web site.
+
+If the bug is triggered by a specific \(La\)TeX file, you should try
+to produce a minimal sample file showing the problem and include it
+in your report.
+
+Your report will be posted for the auctex package at the GNU bug
+tracker. Visit ")
+ (insert-text-button
+ "https://debbugs.gnu.org/cgi/pkgreport.cgi?pkg=auctex"
+ 'face 'link
+ 'help-echo (concat "mouse-2, RET: Follow this link")
+ 'action (lambda (_button)
+ (browse-url "https://debbugs.gnu.org/cgi/pkgreport.cgi?pkg=auctex"))
+ 'follow-link t)
+ (insert "\nto browse existing AUCTeX bugs.
+------------------------------------------------------------------------\n\n")
+ (buffer-string))))))
+
+
+;;; Documentation
+
+(defun TeX-documentation-texdoc (&optional arg)
+ "Run texdoc to read documentation.
+
+Prompt for selection of the package of which to show the documentation.
+
+If called with a prefix argument ARG, after selecting the
+package, prompt for selection of the manual of that package to
+show."
+ (interactive "P")
+ (let ((pkg (thing-at-point 'symbol))
+ buffer list doc)
+ ;; Strip off properties. XXX: XEmacs doesn't have
+ ;; `substring-no-properties'.
+ (set-text-properties 0 (length pkg) nil pkg)
+ (setq pkg (TeX-read-string "View documentation for: " pkg))
+ (unless (zerop (length pkg))
+ (if arg
+ ;; Called with prefix argument: run "texdoc --list --nointeract <pkg>"
+ (progn
+ ;; Create the buffer, insert the result of the command, and
+ ;; accumulate the list of manuals.
+ (with-current-buffer (get-buffer-create
+ (setq buffer (format "*texdoc: %s*" pkg)))
+ (erase-buffer)
+ (insert (shell-command-to-string
+ (concat "texdoc --list --nointeract " pkg)))
+ (goto-char 1) ; No need to use `point-min' here.
+ (save-excursion
+ (while (re-search-forward
+ ;; XXX: XEmacs doesn't support character classes in
+ ;; regexps, like "[:alnum:]".
+ "^ *\\([0-9]+\\) +\\([-~/a-zA-Z0-9_.${}#%,:\\ ()]+\\)" nil t)
+ (push (cons (match-string 1) (match-string 2)) list))))
+ (unwind-protect
+ (cond
+ ((null (executable-find "texdoc"))
+ ;; Note: `shell-command-to-string' uses shell, only
+ ;; `call-process' looks at `exec-path', thus only here makes
+ ;; sense to use `executable-find' to test whether texdoc is
+ ;; available.
+ (message "texdoc not found"))
+ (list
+ ;; Go on if there are manuals listed: show the buffer, prompt
+ ;; for the number of the manual, then run
+ ;; texdoc --just-view <doc>
+ (TeX-pop-to-buffer (get-buffer buffer))
+ (condition-case nil
+ (when (setq doc
+ (cdr (assoc (TeX-read-string "Please enter \
+the number of the file to view, anything else to skip: ") list)))
+ (call-process "texdoc" nil 0 nil "--just-view" doc))
+ ;; Exit gently if a `quit' signal is thrown.
+ (quit nil)))
+ (t (message "No documentation found for %s" pkg)))
+ ;; In any case quit-and-kill the window.
+ (when (get-buffer-window buffer)
+ (quit-window t (get-buffer-window buffer)))))
+ ;; Called without prefix argument: just run "texdoc --view <pkg>" and
+ ;; show the output, so that the user is warned in case it doesn't find
+ ;; the documentation or "texdoc" is not available.
+ (message "%s"
+ ;; The folowing code to the end of `defun' used to be
+ ;; just
+ ;; (shell-command-to-string (concat "texdoc --view " pkg))
+ ;; , but in some cases it blocks emacs until the user
+ ;; quits the viewer (bug#28905).
+ (with-output-to-string
+ (let* (;; Use pipe rather than pty because the
+ ;; latter causes atril (evince variant
+ ;; viewer) to exit before showing anything.
+ (process-connection-type nil)
+ (process (start-process-shell-command
+ "Doc view" standard-output
+ (concat "texdoc --view " pkg))))
+ ;; Suppress the message "Process Doc view
+ ;; finished".
+ (set-process-sentinel process #'ignore)
+ ;; Kill temp buffer without query. This is
+ ;; necessary, at least for some environment, if
+ ;; the underlying shell can't find the texdoc
+ ;; executable.
+ (set-process-query-on-exit-flag process nil)
+ ;; Don't discard shell output.
+ (accept-process-output process))))))))
+
+(defun TeX-goto-info-page ()
+ "Read documentation for AUCTeX in the info system."
+ (interactive)
+ (info "auctex"))
+
+(autoload 'info-lookup->completions "info-look")
+
+(defvar TeX-doc-backend-alist
+ '((texdoc (plain-tex-mode latex-mode doctex-mode ams-tex-mode context-mode)
+ (lambda ()
+ (when (executable-find "texdoc")
+ (TeX-search-files-by-type 'docs 'global t t)))
+ (lambda (doc)
+ ;; texdoc in MiKTeX requires --view in order to start
+ ;; the viewer instead of an intermediate web page.
+ (call-process "texdoc" nil 0 nil "--view" doc)))
+ (latex-info (latex-mode)
+ (lambda ()
+ (mapcar (lambda (x)
+ (let ((x (car x)))
+ (if (string-match "\\`\\\\" x)
+ (substring x 1) x)))
+ (info-lookup->completions 'symbol 'latex-mode)))
+ (lambda (doc)
+ (info-lookup-symbol (concat "\\" doc) 'latex-mode)))
+ (texinfo-info (texinfo-mode)
+ (lambda ()
+ (mapcar (lambda (x)
+ (let ((x (car x)))
+ (if (string-match "\\`@" x)
+ (substring x 1) x)))
+ (info-lookup->completions 'symbol
+ 'texinfo-mode)))
+ (lambda (doc)
+ (info-lookup-symbol (concat "@" doc) 'texinfo-mode))))
+ "Alist of backends used for looking up documentation.
+Each item consists of four elements.
+
+The first is a symbol describing the backend's name.
+
+The second is a list of modes the backend should be activated in.
+
+The third is a function returning a list of documents available
+to the backend. It should return nil if the backend is not
+available, for example if a required executable is not present on the
+system in question.
+
+The fourth is a function for displaying the documentation. The
+function should accept a single argument, the chosen package,
+command, or document name.")
+
+(defun TeX-doc (&optional name)
+ "Display documentation for string NAME.
+NAME may be a package, a command, or a document."
+ (interactive)
+ (let (docs)
+ ;; Build the lists of available documentation used for completion.
+ (dolist (elt TeX-doc-backend-alist)
+ (when (memq major-mode (nth 1 elt))
+ (let ((completions (funcall (nth 2 elt))))
+ (unless (null completions)
+ (cl-pushnew (cons completions (nth 0 elt)) docs :test #'equal)))))
+ (if (null docs)
+ (progn
+ (if (executable-find "texdoc")
+ ;; Fallback if we did not find anything via the backend list.
+ (let ((doc (read-from-minibuffer "Input for `texdoc': ")))
+ (when doc (call-process "texdoc" nil 0 nil "--view" doc)))
+ ;; Give up.
+ (message "No documentation found")))
+ ;; Ask the user about the package, command, or document.
+ (when (and (called-interactively-p 'any)
+ (or (not name) (string= name "")))
+ (let ((symbol (thing-at-point 'symbol))
+ contained completions)
+ ;; Is the symbol at point contained in the lists of available
+ ;; documentation?
+ (setq contained (catch 'found
+ (dolist (elt docs)
+ (when (member symbol (car elt))
+ (throw 'found t)))))
+ ;; Setup completion list in a format suitable for `completing-read'.
+ (dolist (elt docs)
+ ;; FIXME: Probably not needed!
+ (setq completions (nconc (mapcar #'list (car elt)) completions)))
+ ;; Query user.
+ (setq name (completing-read
+ (if contained
+ (format "Package, command, or document (default %s): "
+ symbol)
+ "Package, command, or document: ")
+ completions nil nil nil nil symbol))))
+ (if (not name)
+ (message "No documentation specified")
+ ;; XXX: Provide way to choose in case a symbol can be found in
+ ;; more than one backend.
+ (let* ((backend (catch 'found
+ (dolist (elt docs)
+ (when (member name (car elt))
+ (throw 'found (cdr elt)))))))
+ (if backend
+ (funcall (nth 3 (assoc backend TeX-doc-backend-alist)) name)
+ (message "Documentation not found")))))))
+
+
+;;; Ispell Support
+
+(defun TeX-run-ispell (_command _string file)
+ "Run ispell on current TeX buffer."
+ (cond ((string-equal file (TeX-region-file))
+ (call-interactively #'ispell-region))
+ (t
+ (ispell-buffer))))
+
+(defun TeX-ispell-document (name)
+ "Run ispell on all open files belonging to the current document."
+ (interactive (list (TeX-master-file)))
+ (if (string-equal name "")
+ (setq name (TeX-master-file)))
+
+ (let ((regexp (concat "\\`\\("
+ (mapconcat (lambda (dir)
+ (regexp-quote
+ (expand-file-name
+ (file-name-as-directory dir))))
+ (append (when (file-name-directory name)
+ (list (file-name-directory name)))
+ TeX-check-path)
+ "\\|")
+ "\\).*\\("
+ (mapconcat #'regexp-quote
+ (cons (file-name-nondirectory name)
+ (TeX-style-list))
+ "\\|")
+ "\\)\\.\\("
+ (mapconcat #'identity TeX-file-extensions "\\|")
+ "\\)\\'"))
+ (buffers (buffer-list)))
+ (while buffers
+ (let* ((buffer (car buffers))
+ (name (buffer-file-name buffer)))
+ (setq buffers (cdr buffers))
+ (when (and name (string-match regexp name))
+ (save-excursion (switch-to-buffer buffer) (ispell-buffer))
+ t)))))
+
+(defcustom TeX-ispell-extend-skip-list t
+ "Whether to extend regions selected for skipping during spell checking."
+ :group 'TeX-misc
+ :type 'boolean)
+
+;; These functions are used to add new items to
+;; `ispell-tex-skip-alists' -- see tex-ispell.el:
+(defun TeX-ispell-skip-setcar (skip)
+ "Add SKIP to car of `ispell-tex-skip-alists'.
+SKIP is an alist with the format described in
+`ispell-tex-skip-alists'. Each element in SKIP is added on top
+of the car of `ispell-tex-skip-alists'. This only happens if
+`TeX-ispell-extend-skip-list' is non-nil."
+ (when TeX-ispell-extend-skip-list
+ (let ((raws (car ispell-tex-skip-alists))
+ (envs (cadr ispell-tex-skip-alists)))
+ (dolist (x skip)
+ (cl-pushnew x raws :test #'equal))
+ (setq ispell-tex-skip-alists (list raws envs)))))
+
+(defun TeX-ispell-skip-setcdr (skip)
+ "Add SKIP to cdr of `ispell-tex-skip-alists'.
+SKIP is an alist with the format described in
+`ispell-tex-skip-alists'. Each element in SKIP is added on top
+of the cdr of `ispell-tex-skip-alists'. This only happens if
+`TeX-ispell-extend-skip-list' is non-nil."
+ (when TeX-ispell-extend-skip-list
+ (let ((raws (car ispell-tex-skip-alists))
+ (envs (cadr ispell-tex-skip-alists)))
+ (dolist (x skip)
+ (cl-pushnew x envs :test #'equal))
+ (setq ispell-tex-skip-alists (list raws envs)))))
+
+(defun TeX-ispell-tex-arg-end (&optional arg1 arg2 arg3)
+ "Skip across ARG1, ARG2 and ARG3 number of braces and brackets.
+This function is a variation of `ispell-tex-arg-end'. It should
+be used when adding skip regions to `ispell-tex-skip-alists' for
+constructs like:
+
+ \\begin{tabularx}{300pt}[t]{lrc} ...
+ or
+ \\fontspec{font name}[font features]
+
+where optional and/or mandatory argument(s) follow(s) a mandatory
+one. ARG1 is the number of mandatory arguments before the
+optional one, ARG2 the max. number of following optional
+arguments, ARG3 is the max. number of mandatory arguments
+following. Omitting argument means 1.
+
+Here some examples for additions to `ispell-tex-skip-alists':
+
+ \\begin{tabularx}{300pt}[t]{lrc} ...
+ ARG 1 2 3
+ (\"tabularx\" TeX-ispell-tex-arg-end) or equivalent
+ (\"tabularx\" TeX-ispell-tex-arg-end 1 1 1)
+
+ \\fontspec{font name}[font features]
+ ARG1 ARG2 ARG3=0
+ (\"\\\\\\\\fontspec\" TeX-ispell-tex-arg-end 1 1 0)
+
+ \\raisebox{lift}[height][depth]{contents}
+ ARG1 ARG2 ARG3=0 (checked by Ispell)
+ (\"\\\\\\\\raisebox\" TeX-ispell-tex-arg-end 1 2 0)
+
+Optional arguments before the first mandatory one are all
+skipped."
+ (condition-case nil
+ (progn
+ (while (looking-at "[ \t\n]*\\[") (forward-sexp))
+ (forward-sexp (or arg1 1))
+ (let ((num 0))
+ (while (and (looking-at "[ \t\n]*\\[")
+ (< num (or arg2 1)))
+ (setq num (1+ num))
+ (forward-sexp)))
+ (forward-sexp (or arg3 1)))
+ (error
+ (message "Error skipping s-expressions at point %d" (point))
+ (sit-for 2))))
+
+(defun TeX-ispell-tex-arg-verb-end (&optional arg)
+ "Skip an optional argument, ARG number of mandatory ones and verbatim content.
+This function always checks if one optional argument in brackets
+is given and skips over it. If ARG is a number, it skips over
+that many mandatory arguments in braces. Then it checks for
+verbatim content to skip which is enclosed by a character given
+in `TeX-ispell-verb-delimiters' or in braces, otherwise raises an
+error."
+ (condition-case nil
+ (progn
+ (when (looking-at "[ \t\n]*\\[") (forward-sexp))
+ (when (and arg (looking-at "{"))
+ (forward-sexp arg))
+ (cond ((looking-at (concat "[" TeX-ispell-verb-delimiters "]"))
+ (forward-char)
+ (skip-chars-forward (concat "^" (string (char-before))))
+ (forward-char))
+ ((looking-at "{")
+ (forward-sexp))
+ (t (error nil))))
+ (error
+ (message "Verbatim delimiter is not one of %s"
+ (split-string TeX-ispell-verb-delimiters "" t))
+ (sit-for 2))))
+
+;;; Abbrev mode
+
+(defmacro TeX-abbrev-mode-setup (mode)
+ "Set up the abbrev table and variable for MODE."
+ (let ((symbol (intern (concat (symbol-name mode) "-abbrev-table")))
+ (name (TeX-mode-prefix mode)))
+ `(progn
+ (defvar ,symbol nil
+ ,(format "Abbrev table for %s mode." name))
+ (define-abbrev-table ',symbol nil)
+ (abbrev-table-put ,symbol :parents (list text-mode-abbrev-table)))))
+
+
+;;; Special provisions for other modes and libraries
+
+;; desktop-locals-to-save is broken by design. Don't have
+;; buffer-local values of it.
+(eval-after-load "desktop"
+ '(progn
+ (dolist (elt '(TeX-master))
+ (unless (member elt (default-value 'desktop-locals-to-save))
+ (setq-default desktop-locals-to-save
+ (cons elt (default-value 'desktop-locals-to-save)))))
+ (add-hook 'desktop-after-read-hook (lambda ()
+ (TeX-set-mode-name t)))))
+
+;; delsel.el, `delete-selection-mode'
+(put 'TeX-newline 'delete-selection t)
+(put 'TeX-insert-quote 'delete-selection t)
+(put 'TeX-insert-backslash 'delete-selection t)
+;; When `TeX-electric-math' is non-nil, `TeX-insert-dollar' interferes with
+;; `delete-selection-mode', but when it's nil users may want to be able to
+;; delete active region if `delete-selection-mode' is active, see bug#23177. We
+;; can dynamically determine the behavior of `delete-selection' with
+;; `TeX-insert-dollar' based on the value of `TeX-electric-math'.
+(put 'TeX-insert-dollar 'delete-selection
+ (lambda () (null TeX-electric-math)))
+
+(defun TeX--list-of-string-p (lst)
+ "Return non-nil if LST is a list of strings.
+Used as function for validating a variable's `safe-local-variable' property."
+ (and (listp lst)
+ (let ((all-strings t))
+ (while (and all-strings lst)
+ (setq all-strings (stringp (car lst)))
+ (setq lst (cdr lst)))
+ all-strings)))
+
+;; add-log.el: This function is a variation of
+;; `tex-current-defun-name' defined in `tex-mode.el'. In `latex.el',
+;; the variable `add-log-current-defun-function' is set to this
+;; function.
+(defun TeX-current-defun-name ()
+ "Return the name of the TeX section/paragraph/chapter at point, or nil."
+ (save-excursion
+ (let (s1 e1 s2 e2)
+ ;; If we are now precisely at the beginning of a sectioning
+ ;; command, move forward and make sure `re-search-backward'
+ ;; finds this one rather than the previous one:
+ (or (eobp) (progn
+ (when (looking-at-p "\\\\")
+ (forward-char))
+ (unless (eolp)
+ (forward-sexp))))
+ ;; Search backward for sectioning command. If
+ ;; `LaTeX-section-label' is buffer-local, assume that a style
+ ;; has changed the value and recalculate the string. Otherwise
+ ;; take the standard one:
+ (when (re-search-backward
+ (if (local-variable-p 'LaTeX-section-label)
+ (concat "\\\\"
+ (regexp-opt
+ (remove "part" (mapcar #'car LaTeX-section-label)))
+ "\\*?")
+ "\\\\\\(sub\\)*\\(section\\|paragraph\\|chapter\\)\\*?")
+ nil t)
+ ;; Skip over the backslash:
+ (setq s1 (1+ (point)))
+ ;; Skip over the sectioning command, incl. the *:
+ (setq e1 (goto-char (match-end 0)))
+ ;; Skip over the optional argument, if any:
+ (when (looking-at-p "[ \t]*\\[")
+ (forward-sexp))
+ ;; Skip over any chars until the mandatory argument:
+ (skip-chars-forward "^{")
+ ;; Remember the points for the mandatory argument:
+ (setq s2 (point))
+ (setq e2 (progn (forward-sexp)
+ (point)))
+ ;; Now pick the content: For one-line title, return it
+ ;; incl. the closing brace. For multi-line, return the first
+ ;; line of the mandatory argument incl. ellipsis and a brace;
+ (concat
+ (buffer-substring-no-properties s1 e1)
+ (buffer-substring-no-properties
+ (goto-char s2)
+ (min (line-end-position) e2))
+ (when (> e2 (line-end-position))
+ (concat "..." TeX-grcl)))))))
+
+;;; Customization:
+
+(defcustom TeX-process-asynchronous (not (eq system-type 'ms-dos))
+ "Use asynchronous processes."
+ :group 'TeX-command
+ :type 'boolean)
+
+(defcustom TeX-shell
+ (if (memq system-type '(ms-dos emx windows-nt))
+ shell-file-name
+ "/bin/sh")
+ "Name of shell used to parse TeX commands."
+ :group 'TeX-command
+ :type 'file)
+
+(defcustom TeX-shell-command-option
+ (cond ((memq system-type '(ms-dos emx windows-nt))
+ shell-command-switch)
+ (t ;Unix & EMX (Emacs 19 port to OS/2)
+ "-c"))
+ "Shell argument indicating that next argument is the command."
+ :group 'TeX-command
+ :type 'string)
+
+;;; Interactive Commands
+;;
+;; The general idea is, that there is one process and process buffer
+;; associated with each master file, and one process and process
+;; buffer for running TeX on a region.
+;;
+;; Some user commands operates on ``the'' process, which is the last
+;; process still running or already finished. Note that you cannot
+;; run more than one process simultaneously, including preview by
+;; preview-latex, because process filters and sentinels refer to
+;; certain set of global variables which each invokation of the
+;; process overwrites. If you dare to do, the result is thus
+;; unpredictable.
+
+(defun TeX-save-document (name-or-file-fn)
+ "Save all files belonging to the current document.
+Return non-nil if document needs to be re-TeX'ed.
+In Lisp program, NAME-OR-FILE-FN specifies the current document.
+It is either the master name without extension or the function
+`TeX-master-file'."
+ (interactive (list #'TeX-master-file))
+ (TeX-check-files (TeX--concat-ext name-or-file-fn (TeX-output-extension))
+ (cons (TeX--concat-ext name-or-file-fn) (TeX-style-list))
+ TeX-file-extensions))
+
+(defun TeX--concat-ext (name-or-file-fn &optional extension)
+ "Append EXTENSION to a filename specified by NAME-OR-FILE-FN.
+
+If NAME-OR-FILE-FN is a string, interpret it as the filename.
+Otherwise, assume it is a callable function and call it with
+EXTENSION as an argument and return the result without
+modification. EXTENSION is a string which should not start with
+'.'."
+ (if (stringp name-or-file-fn)
+ (if extension
+ (concat name-or-file-fn "." extension)
+ name-or-file-fn)
+ (funcall name-or-file-fn extension)))
+
+(defun TeX-command-master (&optional override-confirm)
+ "Run command on the current document.
+
+If a prefix argument OVERRIDE-CONFIRM is given, confirmation will
+depend on it being positive instead of the entry in `TeX-command-list'."
+ (interactive "P")
+ (TeX-master-file nil nil t) ;; call to ask if necessary
+ (TeX-command (TeX-command-query #'TeX-master-file)
+ #'TeX-master-file override-confirm))
+
+(defcustom TeX-region-extra ""
+ "String to insert in the region file between the header and the text."
+ :group 'TeX-command
+ :type 'string)
+
+;; This was "{\\makeatletter\\gdef\\AucTeX@cite#1[#2]#3{[#3#1#2]}\
+;; \\gdef\\cite{\\@ifnextchar[{\\AucTeX@cite{, }}\
+;; {\\AucTeX@cite{}[]}}}\n"
+;; However, that string is inappropriate for plain TeX and ConTeXt.
+;; This needs reconsideration.
+
+(defvar TeX-command-region-begin nil)
+(defvar TeX-command-region-end nil)
+;; Used for marking the last region.
+
+(make-variable-buffer-local 'TeX-command-region-begin)
+(make-variable-buffer-local 'TeX-command-region-end)
+
+(defun TeX-current-offset (&optional pos)
+ "Calculate line offset of POS, or of point if POS is nil."
+ (save-restriction
+ (widen)
+ (save-excursion
+ (let ((inhibit-point-motion-hooks t)
+ (inhibit-field-text-motion t))
+ (if pos (goto-char pos))
+ (+ (count-lines (point-min) (point))
+ (if (bolp) 0 -1))))))
+
+(defun TeX-pin-region (begin end)
+ "Pin the TeX region specified by BEGIN and END.
+If BEGIN is nil, the region is unpinned.
+
+In interactive use, a positive prefix arg will pin the region,
+a non-positive one will unpin it. Without a prefix arg, if
+a region is actively marked, it will get pinned. If not, a
+pinned region will get unpinned and vice versa."
+ (interactive
+ (if
+ (if current-prefix-arg
+ (> (prefix-numeric-value current-prefix-arg) 0)
+ (or (TeX-active-mark)
+ (null TeX-command-region-begin)))
+ (list (region-beginning) (region-end))
+ '(nil nil)))
+ (if begin
+ (progn
+ (unless (markerp TeX-command-region-begin)
+ (setq TeX-command-region-begin (make-marker))
+ (setq TeX-command-region-end (make-marker)))
+ (set-marker TeX-command-region-begin begin)
+ (set-marker TeX-command-region-end end)
+ (message "TeX region pinned."))
+ (when (markerp TeX-command-region-begin)
+ (set-marker TeX-command-region-begin nil)
+ (set-marker TeX-command-region-end nil))
+ (setq TeX-command-region-begin nil)
+ (setq TeX-command-region-end nil)
+ (message "TeX region unpinned.")))
+
+(defun TeX-region-update ()
+ "Update the TeX-region file."
+ ;; Note that TeX-command-region-begin is not a marker when called
+ ;; from TeX-command-buffer.
+ (and (or (null TeX-command-region-begin)
+ (markerp TeX-command-region-begin))
+ (TeX-active-mark)
+ (TeX-pin-region (region-beginning) (region-end)))
+ (let* ((begin (or TeX-command-region-begin (region-beginning)))
+ (end (or TeX-command-region-end (region-end)))
+ (TeX-region-extra
+ ;; Write out counter information to region.
+ (concat (and (fboundp 'preview--counter-information)
+ (preview--counter-information begin))
+ TeX-region-extra)))
+ (TeX-region-create (TeX-region-file TeX-default-extension)
+ (buffer-substring-no-properties begin end)
+ (file-name-nondirectory (buffer-file-name))
+ (TeX-current-offset begin))))
+
+(defun TeX-command-region (&optional override-confirm)
+ "Run TeX on the current region.
+
+Query the user for a command to run on the temporary file specified by
+the variable `TeX-region'. If there is an explicitly active region,
+it is stored for later commands. If not, a previously stored region
+\(can be also be set with `TeX-pin-region') overrides the current region,
+if present.
+
+If a prefix argument OVERRIDE-CONFIRM is given, prompting will
+ignore the prompting flag from `TeX-command-list' and instead
+will prompt only if the prefix is positive.
+
+If the master file for the document has a header, it is written to the
+temporary file before the region itself. The document's header is all
+text before `TeX-header-end'.
+
+If the master file for the document has a trailer, it is written to
+the temporary file after the region itself. The document's trailer is
+all text after `TeX-trailer-start'."
+ (interactive "P")
+ (TeX-region-update)
+ ;; In the next line, `TeX-region-file' should be called with nil
+ ;; `nondirectory' argument, otherwise `TeX-command-default' called
+ ;; within `TeX-command-query' won't work in included files not
+ ;; placed in `TeX-master-directory'.
+ (TeX-command (TeX-command-query #'TeX-region-file) #'TeX-region-file
+ override-confirm))
+
+(defun TeX-command-buffer (&optional override-confirm)
+ "Run TeX on the current buffer.
+
+Query the user for a command to run on the temporary file specified by
+the variable `TeX-region'. The region file will be recreated from the
+visible part of the buffer.
+
+If a prefix argument OVERRIDE-CONFIRM is given, confirmation will
+depend on it being positive instead of the entry in `TeX-command-list'."
+ (interactive "P")
+ (let ((TeX-command-region-begin (point-min))
+ (TeX-command-region-end (point-max)))
+ (TeX-command-region override-confirm)))
+
+(defcustom TeX-record-buffer nil
+ "Whether to record buffer names of generated TeX buffers.
+When non-nil, these buffers are put at the front of the list of
+recently selected ones."
+ :group 'TeX-command
+ :type 'boolean)
+
+(defun TeX-pop-to-buffer (buffer &optional other-window norecord)
+ "Compatibility wrapper for `pop-to-buffer'.
+
+Select buffer BUFFER in some window, preferably a different one.
+BUFFER may be a buffer, a string (a buffer name), or nil.
+If BUFFER is a string which is not the name of an existing buffer,
+then this function creates a buffer with that name.
+If BUFFER is nil, then it chooses some other buffer.
+If `pop-up-windows' is non-nil, windows can be split to do this.
+If optional second arg OTHER-WINDOW is non-nil, insist on finding another
+window even if BUFFER is already visible in the selected window,
+and ignore `same-window-regexps' and `same-window-buffer-names'.
+This function returns the buffer it switched to.
+This uses the function `display-buffer' as a subroutine; see the documentation
+of `display-buffer' for additional customization information.
+
+Optional third arg NORECORD non-nil means do not put this buffer
+at the front of the list of recently selected ones."
+ (pop-to-buffer buffer other-window (and norecord (not TeX-record-buffer))))
+
+(defun TeX-recenter-output-buffer (line)
+ "Redisplay buffer of TeX job output so that most recent output can be seen.
+The last line of the buffer is displayed on line LINE of the window, or
+at bottom if LINE is nil."
+ (interactive "P")
+ (let ((buffer (TeX-active-buffer)))
+ (if buffer
+ (let ((old-buffer (current-buffer)))
+ (TeX-pop-to-buffer buffer t t)
+ (bury-buffer buffer)
+ (goto-char (point-max))
+ (recenter (if line
+ (prefix-numeric-value line)
+ (/ (window-height) 2)))
+ (TeX-pop-to-buffer old-buffer nil t))
+ (message "No process for this document."))))
+
+(defun TeX-kill-job ()
+ "Kill the currently running TeX job."
+ (interactive)
+ (let ((process (TeX-active-process)))
+ (if process
+ (kill-process process)
+ ;; Should test for TeX background process here.
+ (error "No TeX process to kill"))))
+
+;; FIXME: The vars below are defined in this file, but they're defined too
+;; far down (i.e. further down than their first use), so we have to pre-declare
+;; them here to explain it to the compiler.
+;; We should move those vars's definitions earlier instead!
+(defvar TeX-current-process-region-p)
+(defvar TeX-save-query)
+(defvar TeX-parse-function)
+(defvar TeX-sentinel-function)
+(defvar TeX-sentinel-default-function)
+(defvar compilation-in-progress)
+(defvar TeX-current-page)
+(defvar TeX-error-overview-open-after-TeX-run)
+(defvar TeX-error-list)
+(defvar TeX-command-buffer)
+(defvar TeX-region)
+
+(defun TeX-home-buffer ()
+ "Go to the buffer where you last issued a TeX command.
+If there is no such buffer, or you already are in that buffer, find
+the master file."
+ (interactive)
+ (if (or (null TeX-command-buffer)
+ (null (buffer-name TeX-command-buffer))
+ (eq TeX-command-buffer (current-buffer)))
+ (find-file (TeX-master-file TeX-default-extension))
+ (switch-to-buffer TeX-command-buffer)))
+
+(defvar TeX-error-last-visited -1
+ "Index of the last visited error listed in `TeX-error-list'.
+
+This variable is intended to be set only in output buffer so it
+will be shared among all files of the same document.")
+(make-variable-buffer-local 'TeX-error-last-visited)
+
+(defun TeX-get-parse-function ()
+ "Get the parse function for the current buffer."
+ (with-current-buffer TeX-command-buffer
+ (TeX-process-get-variable (TeX-active-master) 'TeX-parse-function)))
+
+(defun TeX-next-error (&optional arg reparse)
+ "Find the next error in the TeX output buffer.
+
+A prefix ARG specifies how many error messages to move;
+negative means move back to previous error messages, if possible.
+
+If REPARSE is non-nil, reparse the error message buffer.
+
+\\[universal-argument] as a prefix means reparse the error
+message buffer and start at the first error."
+ (interactive "P")
+ (if (or (null (TeX-active-buffer))
+ (eq 'compilation-mode (with-current-buffer TeX-command-buffer
+ major-mode)))
+ (next-error arg reparse)
+
+ ;; Force reparsing when the function is called with a universal-argument.
+ (if (consp arg) (setq reparse t arg nil))
+
+ (funcall (TeX-get-parse-function) arg reparse)))
+
+(defun TeX-previous-error (arg)
+ "Find the previous error in the TeX output buffer.
+
+Prefix ARG says how many error messages to move backward (or
+forward, if negative).
+
+This works only with TeX commands and if the
+`TeX-parse-all-errors' variable is non-nil."
+ (interactive "p")
+ (if (or (null (TeX-active-buffer))
+ (eq 'compilation-mode (with-current-buffer TeX-command-buffer
+ major-mode)))
+ (previous-error arg)
+
+ (let ((parse-function (TeX-get-parse-function)))
+ (if (and TeX-parse-all-errors (equal parse-function #'TeX-parse-TeX))
+ ;; When `TeX-parse-all-errors' is non-nil and the parsing function is
+ ;; `TeX-parse-TeX' we can move backward in the errors.
+ (TeX-parse-TeX (- arg) nil)
+ ;; XXX: moving backward in the errors hasn't yet been implemented for
+ ;; other parsing functions.
+ (error "Jumping to previous error not supported")))))
+
+;;; Command Query
+
+(defvar TeX-error-overview-frame nil
+ "The frame of the error overview.")
+
+(defconst TeX-error-overview-buffer-name "*TeX errors*"
+ "Name of the buffer in which to show error list.")
+
+(defvar LaTeX-idx-md5-alist nil
+ "Alist of MD5 hashes of idx file.
+
+Car is the idx file, cdr is its md5 hash.")
+
+(defvar LaTeX-idx-changed-alist nil
+ "Whether the idx files changed.
+
+Car is the idx file, cdr is whether idx changed after LaTeX
+run.")
+
+(defcustom TeX-check-engine t
+ "Check the correct engine has been set before running TeX commands."
+ :group 'TeX-command
+ :type 'boolean)
+
+(defvar TeX-check-engine-list '(default luatex omega xetex)
+ "List of engines required by the loaded TeX packages.
+
+Do not set this variable directly, use
+`TeX-check-engine-add-engines' to specify required engines.")
+(make-variable-buffer-local 'TeX-check-engine-list)
+
+(defun TeX-check-engine-add-engines (&rest engines)
+ "Add ENGINES to list of required engines.
+
+Set `TeX-check-engine-list' to the intersection between the list
+itself and the list of provided engines.
+
+See for example style/fontspec.el"
+ (let ((list TeX-check-engine-list)
+ (res nil))
+ (setq TeX-check-engine-list
+ ;; The following is based on the definition of `cl-intersection' of
+ ;; GNU Emacs.
+ (and list engines
+ (if (equal list engines) list
+ (or (>= (length list) (length engines))
+ (setq list (prog1 engines (setq engines list))))
+ (while engines
+ (if (memq (car engines) list)
+ (push (car engines) res))
+ (pop engines))
+ res)))))
+
+(defun TeX-check-engine (name)
+ "Check the correct engine has been set.
+
+Look into `TeX-check-engine-list' for the required engines.
+
+NAME is the command to be run. Actually do the check only if the
+variable `TeX-check-engine' is non-nil and LaTeX is the command
+to be run."
+ (and
+ (string= name "LaTeX")
+ TeX-check-engine
+ TeX-check-engine-list
+ (null (memq TeX-engine TeX-check-engine-list))
+ (memq TeX-engine '(default luatex omega xetex))
+ ;; The set engine is not listed in `TeX-check-engine-list'. We check only
+ ;; builtin engines because we can't take care of custom ones. Do nothing if
+ ;; there is no allowed engine, we don't know what to do in that case.
+ (let ((length (length TeX-check-engine-list))
+ (name-alist '((default . "TeX")
+ (luatex . "LuaTeX")
+ (omega . "Omega")
+ (xetex . "XeTeX")))
+ (completion-ignore-case t)
+ (engine nil))
+ (when
+ (cond
+ ;; There is exactly one allowed engine.
+ ((= length 1)
+ (setq engine (car TeX-check-engine-list))
+ (y-or-n-p (format "%s is required to build this document.
+Do you want to use this engine? " (cdr (assoc engine name-alist)))))
+ ;; More than one engine is allowed.
+ ((> length 1)
+ (if (y-or-n-p (format "It appears %s are required to build this document.
+Do you want to select one of these engines? "
+ (mapconcat
+ (lambda (elt) (cdr (assoc elt name-alist)))
+ TeX-check-engine-list ", ")))
+ (setq engine
+ (car (rassoc
+ (completing-read
+ (format
+ "Choose between %s: "
+ (mapconcat
+ (lambda (elt) (cdr (assoc elt name-alist)))
+ TeX-check-engine-list ", "))
+ (mapcar
+ (lambda (elt) (cdr (assoc elt name-alist)))
+ TeX-check-engine-list))
+ name-alist)))
+ ;; Don't keep asking. If user doesn't want to change engine,
+ ;; probably has a good reason. In order to do so, without adding
+ ;; yet another variable we just hack `TeX-check-engine-list' and
+ ;; make it nil.
+ (setq TeX-check-engine-list nil))))
+ (TeX-engine-set engine)
+ (when (y-or-n-p "Do you want to remember the choice? ")
+ (add-file-local-variable 'TeX-engine engine)
+ (save-buffer))))))
+
+(defcustom TeX-check-TeX t
+ "Whether AUCTeX should check if a working TeX distribution is present."
+ :group 'TeX-command
+ :type 'boolean)
+
+(defcustom TeX-check-TeX-command-not-found 127
+ "Numerical code returned by shell for a command not found error."
+ :group 'TeX-command
+ :type 'integer)
+
+(defun TeX-command (name file-fn &optional override-confirm)
+ "Run command NAME on the file returned by calling FILE-FN.
+
+FILE-FN is the symbol of a function returning a file name. The
+function has one optional argument, the extension to use on the
+file. Valid choices are `TeX-master-file' and `TeX-region-file'.
+
+Use the information in `TeX-command-list' to determine how to run
+the command.
+
+If OVERRIDE-CONFIRM is a prefix argument, confirmation will be
+asked if it is positive, and suppressed if it is not.
+
+Run function `TeX-check-engine' to check the correct engine has
+been set."
+ (TeX-check-engine name)
+
+ ;; Make sure that `TeX-command-buffer' is set always.
+ ;; It isn't safe to remove similar lines in `TeX-run-command' etc.
+ ;; because preview-latex calls `TeX-run-command' directly.
+ (setq-default TeX-command-buffer (current-buffer))
+
+ (cond ((eq file-fn #'TeX-region-file)
+ (setq TeX-current-process-region-p t))
+ ((eq file-fn #'TeX-master-file)
+ (setq TeX-current-process-region-p nil)))
+
+ ;; When we're operating on a region, we need to update the position
+ ;; of point in the region file so that forward search works.
+ (if (string= name "View") (TeX-region-update-point))
+
+ (let ((command (TeX-command-expand (nth 1 (assoc name TeX-command-list))))
+ (hook (nth 2 (assoc name TeX-command-list)))
+ (confirm (if override-confirm
+ (> (prefix-numeric-value override-confirm) 0)
+ (nth 3 (assoc name TeX-command-list)))))
+
+ ;; Verify the expanded command
+ (if confirm
+ (setq command
+ (read-from-minibuffer (concat name " command: ") command
+ nil nil)))
+
+ ;; Kill the frame and buffer associated to the error overview before running
+ ;; the command, but keep them if the command to be run is View.
+ (unless (string= name "View")
+ (if (frame-live-p TeX-error-overview-frame)
+ (delete-frame TeX-error-overview-frame))
+ (if (get-buffer TeX-error-overview-buffer-name)
+ (kill-buffer TeX-error-overview-buffer-name)))
+
+ ;; Before running some commands, check that AUCTeX is able to find "tex"
+ ;; program.
+ (and TeX-check-TeX
+ (member name '("TeX" "LaTeX" "AmSTeX" "ConTeXt" "ConTeXt Full"))
+ (= TeX-check-TeX-command-not-found
+ (call-process TeX-shell nil nil nil
+ TeX-shell-command-option TeX-command))
+ (error (format "ERROR: AUCTeX cannot find a working TeX distribution.
+Make sure you have one and that TeX binaries are in PATH environment variable%s"
+ (if (eq system-type 'darwin)
+ ".
+If you are using OS X El Capitan or later
+remember to add /Library/TeX/texbin/ to your PATH"
+ ""))))
+
+ ;; Now start the process
+ (let ((file (funcall file-fn)))
+ (TeX-process-set-variable file 'TeX-command-next TeX-command-Show)
+ (funcall hook name command file))))
+
+(defun TeX-command-expand (command &optional list)
+ "Expand COMMAND for `TeX-active-master' as described in LIST.
+LIST default to `TeX-expand-list'. As a special exception,
+`%%' can be used to produce a single `%' sign in the output
+without further expansion."
+ (let ((TeX-expand-command command)
+ TeX-expand-pos
+ TeX-command-text
+ TeX-command-pos
+ pat entry case-fold-search string expansion arguments)
+ (setq list (cons
+ (list "%%" (lambda nil
+ (setq TeX-expand-pos (1+ TeX-expand-pos))
+ "%"))
+ (or list (TeX-expand-list)))
+ pat (regexp-opt (mapcar #'car list)))
+ (while (setq TeX-expand-pos (string-match pat TeX-expand-command TeX-expand-pos))
+ (setq string (match-string 0 TeX-expand-command)
+ entry (assoc string list)
+ expansion (car (cdr entry)) ;Second element
+ arguments (cdr (cdr entry)) ;Remaining elements
+ string (save-match-data
+ (cond
+ ((functionp expansion)
+ (apply expansion arguments))
+ ((boundp expansion)
+ (apply (symbol-value expansion) arguments))
+ (t
+ (error "Nonexpansion %s" expansion)))))
+ (if (stringp string)
+ (setq TeX-expand-command
+ (replace-match string t t TeX-expand-command))))
+ TeX-expand-command))
+
+(defun TeX-active-master-with-quotes
+ (&optional extension nondirectory ask extra preprocess-fn)
+ "Return the current master or region file name with quote for shell.
+Pass arguments EXTENSION NONDIRECTORY ASK to `TeX-active-master'.
+If the returned file name contains space, enclose it within
+quotes `\"' when \" \\input\" is supplemented (indicated by
+dynamically bound variable `TeX-command-text' having string
+value.) Also enclose the file name within \\detokenize{} when
+the following three conditions are met:
+ 1. compiling with standard (pdf)LaTeX or upLaTeX
+ 2. \" \\input\" is supplemented
+ 3. EXTRA is non-nil (default when expanding \"%T\")
+Adjust dynamically bound variable `TeX-expand-pos' to avoid possible
+infinite loop in `TeX-command-expand'.
+If PREPROCESS-FN is non-nil then it is called with the filename
+as an argument and the result is enclosed instead of the
+filename.
+
+Helper function of `TeX-command-expand'. Use only within entries in
+`TeX-expand-list-builtin' and `TeX-expand-list'."
+ (let* ((raw (TeX-active-master extension nondirectory ask))
+ ;; String `TeX-command-text' means that the file name is
+ ;; given through \input command.
+ (quote-for-space (if (and (stringp TeX-command-text)
+ (string-match " " raw))
+ "\"" ""))
+ (res
+ (shell-quote-argument
+ (format
+ (if (and extra
+ (stringp TeX-command-text)
+ (memq major-mode '(latex-mode doctex-mode))
+ (memq TeX-engine '(default uptex)))
+ ;; Since TeXLive 2018, the default encoding for LaTeX
+ ;; files has been changed to UTF-8 if used with
+ ;; classic TeX or pdfTeX. I.e.,
+ ;; \usepackage[utf8]{inputenc} is enabled by default
+ ;; in (pdf)latex.
+ ;; c.f. LaTeX News issue 28
+ ;; Due to this change, \detokenize is required to
+ ;; recognize non-ascii characters in the file name
+ ;; when \input precedes.
+ "\\detokenize{ %s }" "%s")
+ (concat quote-for-space
+ (if preprocess-fn
+ (funcall preprocess-fn raw)
+ raw)
+ quote-for-space)))))
+ ;; Advance past the file name in order to
+ ;; prevent expanding any substring of it.
+ (setq TeX-expand-pos
+ (+ TeX-expand-pos (length res)))
+ res))
+
+(defun TeX-check-files (derived originals extensions)
+ "Check if DERIVED is newer than any of the ORIGINALS.
+Try each original with each member of EXTENSIONS, in all directories
+in `TeX-check-path'. Returns true if any of the ORIGINALS with any of the
+EXTENSIONS are newer than DERIVED. Will prompt to save the buffer of any
+ORIGINALS which are modified but not saved yet."
+ (let (existingoriginals
+ found
+ (extensions (TeX-delete-duplicate-strings extensions))
+ (buffers (buffer-list)))
+ (dolist (path (TeX-delete-duplicate-strings
+ (mapcar (lambda (dir)
+ (expand-file-name (file-name-as-directory dir)))
+ (append
+ TeX-check-path
+ ;; In `TeX-command-default', this function is used to
+ ;; check whether bibliography databases are newer
+ ;; than generated *.bbl files, but bibliography
+ ;; database are relative to `TeX-master-directory'
+ ;; and the test can be run also from included files
+ ;; that are in directories different from
+ ;; `TeX-master-directory'.
+ (list (TeX-master-directory))))))
+ (dolist (orig originals)
+ (dolist (ext extensions)
+ (let ((filepath (concat path orig "." ext)))
+ (if (or (file-exists-p filepath)
+ (get-file-buffer filepath))
+ (setq existingoriginals (cons filepath existingoriginals)))))))
+ (while buffers
+ (let* ((buffer (car buffers))
+ (name (buffer-file-name buffer)))
+ (setq buffers (cdr buffers))
+ (if (and name (member name existingoriginals))
+ (progn
+ (and (buffer-modified-p buffer)
+ (or (not TeX-save-query)
+ (y-or-n-p (concat "Save file "
+ (buffer-file-name buffer)
+ "? ")))
+ (with-current-buffer buffer (save-buffer)))))))
+ (dolist (eo existingoriginals)
+ (if (file-newer-than-file-p eo derived)
+ (setq found t)))
+ found))
+
+(defcustom TeX-command-sequence-max-runs-same-command 4
+ "Maximum number of runs of the same command."
+ :type 'integer
+ :group 'TeX-command)
+
+(defcustom TeX-command-sequence-max-runs 12
+ "Maximum number of total runs."
+ :type 'integer
+ :group 'TeX-command)
+
+(defvar TeX-command-sequence-count-same-command 1
+ "Counter for the runs of the same command in `TeX-command-sequence'.")
+
+(defvar TeX-command-sequence-count 1
+ "Counter for the total runs of `TeX-command-sequence'.")
+
+(defvar TeX-command-sequence-last-command nil
+ "Last command run in `TeX-command-sequence'.")
+
+(defvar TeX-command-sequence-sentinel nil
+ "Sentinel for `TeX-command-sequence'.")
+
+(defvar TeX-command-sequence-file-function nil
+ "File function for `TeX-command-sequence'.")
+
+(defvar TeX-command-sequence-command nil
+ "Command argument for `TeX-command-sequence'.
+
+It is set in `TeX-command-sequence' and used in
+`TeX-command-sequence-sentinel' to call again
+`TeX-command-sequence' with the appropriate command argument.")
+
+(defun TeX-command-sequence (command &optional reset file-fn)
+ "Run a sequence of TeX commands defined by COMMAND.
+
+The COMMAND argument may be
+
+ * nil: no command will be run in this case
+
+ * a string with a command from `TeX-command-list'
+
+ * a non-nil list of strings, which are commands from
+ `TeX-command-list'; the car of the list is used as command to
+ be executed in the first run of `TeX-command-sequence', the
+ cdr of the list will be passed to the function in the next
+ run, etc.
+
+ * a function name, returning a string which is command from
+ `TeX-command-list'; it will be funcall'd (without arguments!)
+ and used again in the next run of `TeX-command-sequence'.
+
+ * with any other value the function `TeX-command-default' is
+ used to determine the command to run, until a stopping
+ condition is met.
+
+This function runs at most
+`TeX-command-sequence-max-runs-same-command' times the same
+command in a row, and `TeX-command-sequence-max-runs' times in
+total in any case. It ends when `TeX-command-Show' is the
+command to be run.
+
+A non-nil value for the optional argument RESET means this is the
+first run of the function and some variables need to be reset.
+
+FILE-FN is a function of zero arguments returning the current
+filename. Valid choices are `TeX-master-file' (default if
+omitted) and `TeX-region-file'."
+ (setq TeX-command-sequence-file-function (or file-fn #'TeX-master-file))
+ (if (null command)
+ (message "No command to run.")
+ (let (cmd process)
+ (cond
+ ((stringp command)
+ (setq cmd command
+ TeX-command-sequence-command nil))
+ ((listp command)
+ (setq cmd (pop command)
+ TeX-command-sequence-command command))
+ ((functionp command)
+ (setq cmd (funcall command)
+ TeX-command-sequence-command command))
+ (t
+ ;; We first call `TeX-master-file' with the third argument
+ ;; (`ask') set to t, so that the master file is properly set.
+ ;; This is also what `TeX-command-master' does.
+ (funcall TeX-command-sequence-file-function nil nil t)
+ (setq cmd (TeX-command-default TeX-command-sequence-file-function)
+ TeX-command-sequence-command t)))
+ (TeX-command cmd TeX-command-sequence-file-function 0)
+ (when reset
+ (setq TeX-command-sequence-count-same-command 1
+ TeX-command-sequence-count 1
+ TeX-command-sequence-last-command nil))
+ (cond
+ ;; Stop when the same command has been run
+ ;; `TeX-command-sequence-max-runs-same-command' times in a row.
+ ((>= TeX-command-sequence-count-same-command
+ TeX-command-sequence-max-runs-same-command)
+ (message "Stopping after running %S %d times in a row."
+ TeX-command-sequence-last-command
+ TeX-command-sequence-count-same-command))
+ ;; Stop when there have been `TeX-command-sequence-max-runs' total
+ ;; compilations.
+ ((>= TeX-command-sequence-count TeX-command-sequence-max-runs)
+ (message "Stopping after %d compilations." TeX-command-sequence-count))
+ ;; The command just run is `TeX-command-Show'.
+ ((equal command TeX-command-Show))
+ ;; In any other case continue: increase counters (when needed), update
+ ;; `TeX-command-sequence-last-command' and run the sentinel.
+ (t
+ (if (equal cmd TeX-command-sequence-last-command)
+ (setq TeX-command-sequence-count-same-command
+ (1+ TeX-command-sequence-count-same-command))
+ (setq TeX-command-sequence-count-same-command 1))
+ (setq TeX-command-sequence-count (1+ TeX-command-sequence-count)
+ TeX-command-sequence-last-command cmd)
+ (and (setq process (get-buffer-process (current-buffer)))
+ (setq TeX-command-sequence-sentinel (process-sentinel process))
+ (set-process-sentinel process
+ #'TeX-command-sequence-sentinel)))))))
+
+(defcustom TeX-save-query t
+ "If non-nil, ask user for permission to save files before starting TeX."
+ :group 'TeX-command
+ :type 'boolean)
+
+(defvar TeX-command-history nil)
+
+(defun TeX-command-default (name-or-file-fn)
+ "Guess the next command to be run on NAME-OR-FILE-FN."
+ (let ((command-next nil)
+ (name (TeX--concat-ext name-or-file-fn)))
+ (cond ((if (eq name-or-file-fn #'TeX-region-file)
+ (TeX-check-files (TeX-region-file (TeX-output-extension))
+ ;; Each original will be checked for all dirs
+ ;; in `TeX-check-path' so this needs to be just
+ ;; a filename without directory.
+ (list (file-relative-name name))
+ TeX-file-extensions)
+ (TeX-save-document name-or-file-fn))
+ TeX-command-default)
+ ((and (memq major-mode '(doctex-mode latex-mode))
+ ;; Want to know if bib file is newer than .bbl
+ ;; We don't care whether the bib files are open in emacs
+ (TeX-check-files (TeX--concat-ext name-or-file-fn "bbl")
+ (mapcar #'car
+ (LaTeX-bibliography-list))
+ (append BibTeX-file-extensions
+ TeX-Biber-file-extensions)))
+ ;; We should check for bst files here as well.
+ (if (bound-and-true-p LaTeX-using-Biber)
+ TeX-command-Biber TeX-command-BibTeX))
+ ((and
+ ;; Rationale: makeindex should be run when final document is almost
+ ;; complete (see
+ ;; https://tex-talk.net/2012/09/dont-forget-to-run-makeindex/),
+ ;; otherwise, after following latex runs, index pages may change due
+ ;; to changes in final document, resulting in extra makeindex and
+ ;; latex runs.
+ (member
+ (setq command-next
+ (TeX-process-get-variable
+ name
+ 'TeX-command-next
+ (or (and TeX-PDF-mode (TeX-PDF-from-DVI))
+ TeX-command-Show)))
+ (list "Dvips" "Dvipdfmx" TeX-command-Show))
+ (cdr (assoc (expand-file-name (TeX--concat-ext name-or-file-fn "idx"))
+ LaTeX-idx-changed-alist)))
+ "Index")
+ (command-next)
+ (TeX-command-Show))))
+
+(defun TeX-command-query (name-or-file-fn)
+ "Query the user for what TeX command to use."
+ (let* ((default (TeX-command-default name-or-file-fn))
+ (completion-ignore-case t)
+ (answer (or TeX-command-force
+ (completing-read
+ (concat "Command (default " default "): ")
+ (TeX-mode-specific-command-list major-mode) nil t
+ nil 'TeX-command-history default))))
+ ;; If the answer is "latex" it will not be expanded to "LaTeX"
+ (setq answer (car-safe (assoc-string answer TeX-command-list t)))
+ (if (and answer
+ (not (string-equal answer "")))
+ answer
+ default)))
+
+(defvar TeX-command-next nil
+ "The default command next time `TeX-command' is invoked.")
+
+ (make-variable-buffer-local 'TeX-command-next)
+
+(defun TeX-printer-query (&optional queue)
+ "Query the user for a printer name.
+QUEUE is non-nil when we are checking for the printer queue."
+ (let (command element printer)
+ (if queue
+ (unless (setq element 2 command TeX-queue-command)
+ (error "Need to customize `TeX-queue-command'"))
+ (unless (setq element 1 command TeX-print-command)
+ (error "Need to customize `TeX-print-command'")))
+ (while (progn
+ (setq printer (if TeX-printer-list
+ (let ((completion-ignore-case t))
+ (completing-read
+ (format "Printer%s: "
+ (if TeX-printer-default
+ (format " (default %s)" TeX-printer-default) ""))
+ TeX-printer-list))
+ ""))
+ (setq printer (or (car-safe (assoc-string printer TeX-printer-list t))
+ printer))
+ (not (if (or (null printer) (string-equal "" printer))
+ (setq printer TeX-printer-default)
+ (setq TeX-printer-default printer)))))
+
+ (let ((expansion (let ((entry (assoc printer TeX-printer-list)))
+ (or (nth element entry)
+ command))))
+ (if (string-match "%p" printer)
+ (error "Don't use %s in printer names" "%p"))
+ (while (string-match "%p" expansion)
+ (setq expansion (replace-match printer t t expansion 0)))
+ expansion)))
+
+(defun TeX-style-check (styles)
+ "Check STYLES compared to the current style options."
+ (let ((files (TeX-style-list)))
+ (while (and styles
+ (not (TeX-member (car (car styles)) files #'string-match)))
+ (setq styles (cdr styles))))
+ (if styles
+ (nth 1 (car styles))
+ ""))
+
+(defun TeX-output-extension ()
+ "Get the extension of the current TeX output file."
+ (if (listp TeX-output-extension)
+ (car TeX-output-extension)
+ (or (TeX-process-get-variable (TeX-active-master)
+ 'TeX-output-extension
+ TeX-output-extension)
+ TeX-output-extension)))
+
+(defun TeX-view-mouse (event)
+ "Start `TeX-view' at mouse position."
+ (interactive "e")
+ (with-current-buffer (window-buffer (posn-window (event-start event)))
+ (goto-char (posn-point (event-start event)))
+ (TeX-view)))
+
+(defun TeX-region-update-point ()
+ "Syncs the location of point in the region file with the current file.
+
+Thereafter, point in the region file is on the same text as in
+the current buffer.
+
+Do nothing in case the last command hasn't operated on the region
+or `TeX-source-correlate-mode' is disabled."
+ (when (and TeX-current-process-region-p TeX-source-correlate-mode)
+ (let ((region-buf (get-file-buffer (TeX-region-file t)))
+ (orig-line (TeX-current-offset))
+ (pos-in-line (- (point) (max (line-beginning-position)
+ (or TeX-command-region-begin
+ (region-beginning))))))
+ (when region-buf
+ (with-current-buffer region-buf
+ (goto-char (point-min))
+ (when (re-search-forward "!offset(\\(-?[0-9]+\\)" nil t)
+ (let ((offset (string-to-number (match-string 1))))
+ (goto-char (point-min))
+ (forward-line (- orig-line offset))
+ (forward-char pos-in-line))))))))
+
+(defun TeX-view ()
+ "Start a viewer without confirmation.
+The viewer is started either on region or master file,
+depending on the last command issued."
+ (interactive)
+ (let ((output-file (TeX-active-master (TeX-output-extension))))
+ (if (file-exists-p output-file)
+ (TeX-command "View" #'TeX-active-master 0)
+ (message "Output file %S does not exist." output-file))))
+
+;;; Command Hooks
+
+(defvar TeX-after-compilation-finished-functions nil
+ "Hook being run after TeX/LaTeX/ConTeXt finished successfully.
+The functions in this hook are run with the DVI/PDF output file
+given as argument. Using this hook can be useful for updating
+the viewer automatically after re-compilation of the document.
+
+If you use an emacs-internal viewer such as `doc-view-mode' or
+`pdf-view-mode', add `TeX-revert-document-buffer' to this hook.")
+
+(make-obsolete-variable 'TeX-after-TeX-LaTeX-command-finished-hook
+ 'TeX-after-compilation-finished-functions
+ "11.89")
+
+(defun TeX-revert-document-buffer (file)
+ "Revert the buffer visiting FILE.
+This function is intended to be used in
+`TeX-after-compilation-finished-functions' for users that view
+their compiled document with an emacs viewer such as
+`doc-view-mode' or `pdf-view-mode'. (Note that this function
+just calls `revert-buffer' in the respective buffer and thus
+requires that the corresponding mode defines a sensible
+`revert-buffer-function'.)"
+ (let ((buf (find-buffer-visiting file)))
+ (when buf
+ (with-current-buffer buf
+ (revert-buffer nil t t)))))
+
+(defvar TeX-after-start-process-function
+ #'TeX-adjust-process-coding-system
+ "Function to adjust coding system of an asynchronous process.
+Called with one argument PROCESS.")
+
+(defun TeX-adjust-process-coding-system (process)
+ "Adjust coding system of PROCESS to suitable value.
+Usually coding system is the same as the TeX file with eol format
+adjusted to OS default value. Take care of Japanese TeX, which
+requires special treatment."
+ (if (and (boundp 'japanese-TeX-mode)
+ (fboundp 'japanese-TeX-set-process-coding-system)
+ (with-current-buffer TeX-command-buffer
+ japanese-TeX-mode))
+ (japanese-TeX-set-process-coding-system process)
+ (let ((cs (coding-system-base (with-current-buffer TeX-command-buffer
+ buffer-file-coding-system))))
+ ;; The value of `buffer-file-coding-system' is sometimes
+ ;; undecided-{unix,dos,mac}. That happens when the file
+ ;; contains no multibyte chars and only end of line format is
+ ;; determined. Emacs lisp reference recommends not to use
+ ;; undecided-* for process coding system, so it might seem
+ ;; reasonable to change `undecided' into some fixed coding
+ ;; system like this:
+ ;; (if (eq 'undecided cs)
+ ;; (setq cs 'utf-8))
+ ;; However, that can lose when the following conditions are met:
+ ;; (1) The document is divided into multiple files.
+ ;; (2) The command buffer contains no multibyte chars.
+ ;; (3) The other files contain mutlibyte chars and saved in a
+ ;; coding system other than the one chosen above.
+ ;; So we leave `undecided' unchanged here. Although `undecided'
+ ;; is not quite safe for the coding system for encoding, i.e.,
+ ;; keyboard input to the TeX process, we expect that this does
+ ;; not raise serious problems because it is pretty rare that TeX
+ ;; process needs keyboard input of multibyte chars.
+
+ ;; `utf-8-with-signature' (UTF-8 with BOM) doesn't suit at all
+ ;; for the coding system for encoding because it always injects
+ ;; 3-byte BOM in front of its return value (even when the string
+ ;; to be sent has only ascii characters!) Thus we change it
+ ;; into `utf-8'. On decoding, `utf-8' can decode UTF-8 with
+ ;; BOM. So it is safe for both decoding and encoding.
+ (if (eq cs 'utf-8-with-signature)
+ (setq cs 'utf-8))
+
+ ;; Eol format of TeX files can differ from OS default. TeX
+ ;; binaries accept all type of eol format in the given files
+ ;; and output messages according to OS default. So we set eol
+ ;; format to OS default value.
+ (setq cs (coding-system-change-eol-conversion
+ cs
+ ;; The eol of macosX is LF, not CR. So we choose
+ ;; other than `unix' only for w32 system.
+ ;; FIXME: what should we do for cygwin?
+ (if (eq system-type 'windows-nt) 'dos 'unix)))
+ (set-process-coding-system process cs cs))))
+
+(defcustom TeX-show-compilation nil
+ "If non-nil, show output of TeX compilation in other window."
+ :group 'TeX-command
+ :type 'boolean)
+
+(defun TeX-run-command (name command file)
+ "Create a process for NAME using COMMAND to process FILE.
+Return the new process."
+ (let ((default TeX-command-default)
+ (buffer (TeX-process-buffer-name file))
+ (dir (TeX-master-directory))
+ (command-buff (current-buffer)))
+ (TeX-process-check file) ; Check that no process is running
+ (setq-default TeX-command-buffer command-buff)
+ (get-buffer-create buffer)
+ (set-buffer buffer)
+ (buffer-disable-undo)
+ (erase-buffer)
+ (set (make-local-variable 'line-number-display-limit) 0)
+ (setq TeX-output-extension nil)
+ (set (make-local-variable 'TeX-command-buffer) command-buff)
+ (if dir (cd dir))
+ (insert "Running `" name "' on `" file "' with ``" command "''\n")
+ (TeX-output-mode)
+ (if TeX-show-compilation
+ (display-buffer buffer)
+ (message "Type `%s' to display results of compilation."
+ (substitute-command-keys
+ "\\<TeX-mode-map>\\[TeX-recenter-output-buffer]")))
+ (setq TeX-parse-function #'TeX-parse-command)
+ (setq TeX-command-default default)
+ (setq TeX-sentinel-function
+ (lambda (_process name)
+ (message (concat name ": done."))))
+ (if TeX-process-asynchronous
+ (let ((process (start-process name buffer TeX-shell
+ TeX-shell-command-option command)))
+ (if TeX-after-start-process-function
+ (funcall TeX-after-start-process-function process))
+ (TeX-command-mode-line process)
+ (set-process-filter process #'TeX-command-filter)
+ (set-process-sentinel process #'TeX-command-sentinel)
+ (set-marker (process-mark process) (point-max))
+ (setq compilation-in-progress (cons process compilation-in-progress))
+ process)
+ (setq mode-line-process ": run")
+ (force-mode-line-update)
+ (call-process TeX-shell nil buffer nil
+ TeX-shell-command-option command))))
+
+(defun TeX-run-set-command (name command)
+ "Remember TeX command to use to NAME and set corresponding output extension."
+ (setq TeX-command-default name
+ TeX-output-extension
+ (if (and (null (TeX-PDF-from-DVI)) TeX-PDF-mode) "pdf" "dvi"))
+ (let ((case-fold-search t)
+ (lst TeX-command-output-list))
+ (while lst
+ (if (string-match (car (car lst)) command)
+ (setq TeX-output-extension (car (cdr (car lst)))
+ lst nil)
+ (setq lst (cdr lst))))))
+
+(defvar TeX-error-report-switches nil
+ "Reports presence of errors after `TeX-run-TeX'.
+Actually, `TeX-run-format' sets it.
+To test whether the current buffer has a compile error from last
+run of `TeX-run-format', use
+ (TeX-error-report-has-errors-p)")
+
+(defun TeX-error-report-has-errors-p ()
+ "Return non-nil if current buffer has compile errors from last TeX run."
+ (plist-get TeX-error-report-switches (intern (TeX-master-file))))
+
+(defun TeX-run-format (name command file)
+ "Create a process for NAME using COMMAND to format FILE with TeX."
+ (TeX-run-set-command name command)
+ (let ((current-master (TeX-master-file))
+ (buffer (TeX-process-buffer-name file))
+ (process (TeX-run-command name command file)))
+
+ ;; Save information in TeX-error-report-switches
+ ;; Initialize error to nil (no error) for current master.
+ ;; Presence of error is reported inside `TeX-TeX-sentinel-check'
+
+ ;; the current master file is saved because error routines are
+ ;; parsed in other buffers;
+ (setq TeX-error-report-switches
+ (plist-put TeX-error-report-switches
+ 'TeX-current-master current-master))
+ ;; reset error to nil (no error)
+ (setq TeX-error-report-switches
+ (plist-put TeX-error-report-switches
+ (intern current-master) nil))
+
+ ;; Hook to TeX debugger.
+ (with-current-buffer buffer
+ (TeX-parse-reset)
+ (setq TeX-parse-function #'TeX-parse-TeX)
+ (setq TeX-sentinel-function #'TeX-TeX-sentinel)
+ (if TeX-process-asynchronous
+ (progn
+ ;; Updating the mode line.
+ (setq TeX-current-page "[0]")
+ (TeX-format-mode-line process)
+ (set-process-filter process #'TeX-format-filter)))
+ process)))
+
+(defun TeX-run-TeX (name command file)
+ "Create a process for NAME using COMMAND to format FILE with TeX."
+
+ (let ((idx-file nil) (element nil))
+ ;; Store md5 hash of the index file before running LaTeX.
+ (and (memq major-mode '(doctex-mode latex-mode))
+ (prog1 (file-exists-p
+ (setq idx-file (expand-file-name (TeX-active-master "idx"))))
+ ;; In order to avoid confusion and pollution of
+ ;; `LaTeX-idx-md5-alist', remove from this alist all md5 hashes of
+ ;; the current index file. Note `assq-delete-all' doesn't work with
+ ;; string keys and has problems with non-list elements in Emacs 21
+ ;; (see file tex-site.el).
+ (while (setq element (assoc idx-file LaTeX-idx-md5-alist))
+ (setq LaTeX-idx-md5-alist (delq element LaTeX-idx-md5-alist))))
+ (with-temp-buffer
+ (insert-file-contents-literally idx-file)
+ (push (cons idx-file (md5 (current-buffer))) LaTeX-idx-md5-alist))))
+
+ ;; can we assume that TeX-sentinel-function will not be changed
+ ;; during (TeX-run-format ..)? --pg
+ ;; rather use let* ? --pg
+
+ (if TeX-interactive-mode
+ (TeX-run-interactive name command file)
+ (let* ((sentinel-function TeX-sentinel-default-function)
+ (process (TeX-run-format name command file)))
+ (setq TeX-sentinel-function sentinel-function)
+ (if TeX-process-asynchronous
+ process
+ (TeX-synchronous-sentinel name file process)))))
+
+;; backward compatibilty
+
+(defalias 'TeX-run-LaTeX #'TeX-run-TeX)
+
+
+(defun TeX-run-BibTeX (name command file)
+ "Create a process for NAME using COMMAND to format FILE with BibTeX."
+ (let ((process (TeX-run-command name command file)))
+ (setq TeX-sentinel-function #'TeX-BibTeX-sentinel)
+ (if TeX-process-asynchronous
+ process
+ (TeX-synchronous-sentinel name file process))))
+
+(defun TeX-run-Biber (name command file)
+ "Create a process for NAME using COMMAND to format FILE with Biber."
+ (let ((process (TeX-run-command name command file)))
+ (setq TeX-sentinel-function #'TeX-Biber-sentinel)
+ (if TeX-process-asynchronous
+ process
+ (TeX-synchronous-sentinel name file process))))
+
+(defun TeX-run-dvips (name command file)
+ "Create a process for NAME using COMMAND to convert FILE with dvips."
+ (let ((process (TeX-run-command name command file)))
+ (setq TeX-sentinel-function #'TeX-dvips-sentinel)
+ (if TeX-process-asynchronous
+ process
+ (TeX-synchronous-sentinel name file process))))
+
+(defun TeX-run-dvipdfmx (name command file)
+ "Create a process for NAME using COMMAND to convert FILE with dvipdfmx."
+ (let ((process (TeX-run-command name command file)))
+ (setq TeX-sentinel-function #'TeX-dvipdfmx-sentinel)
+ (if TeX-process-asynchronous
+ process
+ (TeX-synchronous-sentinel name file process))))
+
+(defun TeX-run-ps2pdf (name command file)
+ "Create a process for NAME using COMMAND to convert FILE with ps2pdf."
+ (let ((process (TeX-run-command name command file)))
+ (setq TeX-sentinel-function #'TeX-ps2pdf-sentinel)
+ (if TeX-process-asynchronous
+ process
+ (TeX-synchronous-sentinel name file process))))
+
+(defun TeX-run-index (name command file)
+ "Create a process for NAME using COMMAND to compile the index file."
+ (let ((process (TeX-run-command name command file))
+ (element nil))
+ (setq TeX-sentinel-function #'TeX-index-sentinel)
+ ;; Same cleaning as that for `LaTeX-idx-md5-alist' in `TeX-run-TeX'.
+ (while (setq element
+ ;; `file' has been determined in `TeX-command-buffer', while
+ ;; this function has `TeX-master-directory' as
+ ;; `default-directory', then we have to expand `file' file-name
+ ;; in the same directory of `TeX-command-buffer'.
+ (assoc (with-current-buffer TeX-command-buffer
+ (expand-file-name (TeX-active-master "idx")))
+ LaTeX-idx-changed-alist))
+ (setq LaTeX-idx-changed-alist (delq element LaTeX-idx-changed-alist)))
+ (if TeX-process-asynchronous
+ process
+ (TeX-synchronous-sentinel name file process))))
+
+(defun TeX-run-compile (_name command _file)
+ "Ignore first and third argument, start compile with second argument."
+ (let ((default-directory (TeX-master-directory)))
+ (setq TeX-command-buffer (compile command)))
+ ;; Make `compilation-mode' recognize file names with spaces.
+ ;; (bug#36483)
+ ;; FIXME: This is just an ad-hoc workaround and it's better to fix
+ ;; the regular expression in compile.el properly, if possible. But
+ ;; there was no response to such request in emacs-devel@gnu.org.
+ (with-current-buffer TeX-command-buffer
+ (make-local-variable 'compilation-error-regexp-alist)
+ ;; Add slightly modified entry of the one associated with `comma'
+ ;; in `compilation-error-regexp-alist-alist' to pick up file names
+ ;; with spaces.
+ (add-to-list 'compilation-error-regexp-alist
+ '("^\"\\([^,\"\n\t]+\\)\", line \\([0-9]+\\)\
+\\(?:[(. pos]+\\([0-9]+\\))?\\)?[:.,; (-]\\( warning:\\|[-0-9 ]*(W)\\)?" 1 2 3 (4))
+ t)))
+
+(defun TeX-run-shell (_name command _file)
+ "Ignore first and third argument, start shell-command with second argument."
+ (let ((default-directory (TeX-master-directory)))
+ (shell-command command)
+ (if (eq system-type 'ms-dos)
+ (redraw-display))))
+
+(defun TeX-run-discard (_name command _file)
+ "Start COMMAND as process, discarding its output.
+NAME and FILE are ignored."
+ (let ((default-directory (TeX-master-directory)))
+ (call-process TeX-shell
+ nil 0 nil
+ TeX-shell-command-option
+ command)))
+
+(defun TeX-run-discard-foreground (_name command _file)
+ "Call process with second argument in the foreground, discarding its output.
+With support for MS-DOS, especially when dviout is used with PC-9801 series."
+ (if (and (boundp 'dos-machine-type) (eq dos-machine-type 'pc98)) ;if PC-9801
+ (send-string-to-terminal "\e[2J")) ; clear screen
+ (call-process TeX-shell (if (eq system-type 'ms-dos) "con") nil nil
+ TeX-shell-command-option command)
+ (if (eq system-type 'ms-dos)
+ (redraw-display)))
+(defalias 'TeX-run-dviout #'TeX-run-discard-foreground)
+
+(defun TeX-run-background (name command _file)
+ "Start process with second argument, show output when and if it arrives."
+ (let ((dir (TeX-master-directory)))
+ (set-buffer (get-buffer-create "*TeX background*"))
+ (if dir (cd dir))
+ (erase-buffer)
+ (let ((process (start-process (concat name " background")
+ nil TeX-shell
+ TeX-shell-command-option command)))
+ (if TeX-after-start-process-function
+ (funcall TeX-after-start-process-function process))
+ (set-process-filter process #'TeX-background-filter)
+ (set-process-query-on-exit-flag process nil))))
+
+(defun TeX-run-silent (name command _file)
+ "Start process with second argument."
+ (let ((dir (TeX-master-directory)))
+ (set-buffer (get-buffer-create "*TeX silent*"))
+ (if dir (cd dir))
+ (erase-buffer)
+ (let ((process (start-process (concat name " silent")
+ (current-buffer) TeX-shell
+ TeX-shell-command-option command)))
+ (if TeX-after-start-process-function
+ (funcall TeX-after-start-process-function process))
+ (set-process-query-on-exit-flag process nil))))
+
+(defun TeX-run-interactive (name command file)
+ "Run TeX interactively.
+Run command in a buffer (in comint-shell-mode) so that it accepts user
+interaction. If you return to the file buffer after the TeX run,
+Error parsing on \\[next-error] should work with a bit of luck."
+ (TeX-run-set-command name command)
+ (require 'comint)
+ (let ((default TeX-command-default)
+ (buffer (TeX-process-buffer-name file))
+ (process nil)
+ (dir (TeX-master-directory))
+ (command-buff (current-buffer))
+ (sentinel-function TeX-sentinel-default-function)) ; inherit from major mode
+ (TeX-process-check file) ; Check that no process is running
+ (setq-default TeX-command-buffer command-buff)
+ (with-output-to-temp-buffer buffer)
+ (set-buffer buffer)
+ (set (make-local-variable 'TeX-command-buffer) command-buff)
+ (setq buffer-read-only nil)
+ (if dir (cd dir))
+ (insert "Running `" name "' on `" file "' with ``" command "''\n")
+ (comint-exec buffer name TeX-shell nil
+ (list TeX-shell-command-option command))
+ (comint-mode)
+ (add-hook 'comint-output-filter-functions #'TeX-interactive-goto-prompt)
+ (setq mode-name name)
+ (setq TeX-command-default default)
+ (setq process (get-buffer-process buffer))
+ (if TeX-after-start-process-function
+ (funcall TeX-after-start-process-function process))
+ (TeX-command-mode-line process)
+ (set-process-sentinel process #'TeX-command-sentinel)
+ (set-marker (process-mark process) (point-max))
+ (setq compilation-in-progress (cons process compilation-in-progress))
+ (TeX-parse-reset)
+ (setq TeX-parse-function #'TeX-parse-TeX)
+ ;; use the sentinel-function that the major mode sets, not the LaTeX one
+ (setq TeX-sentinel-function sentinel-function)))
+
+(defun TeX-run-function (_name command _file)
+ "Execute Lisp function or function call given as the string COMMAND.
+Parameters NAME and FILE are ignored."
+ (let ((fun (car (read-from-string command))))
+ (if (functionp fun) (funcall fun) (eval fun t))))
+
+(defun TeX-run-discard-or-function (name command file)
+ "Start COMMAND as process or execute it as a Lisp function.
+If run as a process, the output is discarded. COMMAND is
+expected to be a string. NAME and FILE are ignored."
+ (if (functionp (car (read-from-string command)))
+ (TeX-run-function name command file)
+ (TeX-run-discard name command file)))
+
+(defun TeX-run-ispell-on-document (_command _ignored _name)
+ "Run Ispell on all open files belonging to the current document.
+This function is *obsolete* and only here for compatibility
+reasons. Use `TeX-run-function' instead."
+ (interactive)
+ (TeX-ispell-document ""))
+
+
+;;; Command Sentinels
+
+(defun TeX-synchronous-sentinel (name file result)
+ "Process TeX command output buffer after the process dies."
+ (let ((buffer (TeX-process-buffer (file-name-nondirectory file))))
+ (with-current-buffer buffer
+
+ ;; Append post-mortem information to the buffer
+ (goto-char (point-max))
+ (insert "\n" mode-name (if (and result (zerop result))
+ " finished" " exited") " at "
+ (substring (current-time-string) 0 -5))
+ (setq mode-line-process ": exit")
+
+ ;; Do command specific actions.
+ (setq TeX-command-next TeX-command-Show)
+ (goto-char (point-min))
+ (apply TeX-sentinel-function nil name nil)
+
+ ;; Force mode line redisplay soon
+ (force-mode-line-update))))
+
+(defun TeX-command-sentinel (process msg)
+ "Process TeX command output buffer after the PROCESS dies.
+Insert MSG with some additional information."
+ ;; Set `TeX-transient-master' here because `preview-parse-messages'
+ ;; may open files and thereby trigger master file questions which we
+ ;; don't want and need because we already know the master. Use
+ ;; `TeX-master-file' instead of `TeX-active-master' to determine the
+ ;; master because the region file should never be the master.
+ (let* ((TeX-transient-master (TeX-master-file))
+ (buffer (process-buffer process))
+ (name (process-name process)))
+ (cond ((null (buffer-name buffer)) ; buffer killed
+ (set-process-buffer process nil)
+ (set-process-sentinel process nil))
+ ((memq (process-status process) '(signal exit))
+ (with-current-buffer buffer
+
+ ;; Append post-mortem information to the buffer
+ (goto-char (point-max))
+ (insert-before-markers "\n" mode-name " " msg)
+ (forward-char -1)
+ (insert " at "
+ (substring (current-time-string) 0 -5))
+ (forward-char 1)
+
+ ;; Do command specific actions.
+ (TeX-command-mode-line process)
+ (setq TeX-command-next TeX-command-Show)
+ (goto-char (point-min))
+ (apply TeX-sentinel-function process name nil)
+
+
+ ;; If buffer and mode line will show that the process
+ ;; is dead, we can delete it now. Otherwise it
+ ;; will stay around until M-x list-processes.
+ (delete-process process))
+
+ ;; Force mode line redisplay soon
+ ;; Do this in all buffers (bug#38058 and bug#40965)
+ (force-mode-line-update t))))
+
+ (setq compilation-in-progress (delq process compilation-in-progress)))
+
+
+(defvar TeX-sentinel-function (lambda (_process _name) nil)
+ "Hook to cleanup TeX command buffer after termination of PROCESS.
+NAME is the name of the process.")
+
+(make-variable-buffer-local 'TeX-sentinel-function)
+
+
+(defvar TeX-sentinel-default-function (lambda (_process _name) nil)
+ "Default for `TeX-sentinel-function'. To be set in major mode.
+Hook to cleanup TeX command buffer after termination of PROCESS.
+NAME is the name of the process.")
+
+(make-variable-buffer-local 'TeX-sentinel-default-function)
+
+(defun TeX-TeX-sentinel (process name)
+ "Cleanup TeX output buffer after running TeX.
+
+Parse the output buffer to collect errors and warnings if the
+variable `TeX-parse-all-errors' is non-nil.
+
+Open the error overview if
+`TeX-error-overview-open-after-TeX-run' is non-nil and there are
+errors or warnings to show."
+ (if (TeX-TeX-sentinel-check process name)
+ (progn
+ (if TeX-parse-all-errors
+ (TeX-parse-all-errors))
+ (if (and TeX-error-overview-open-after-TeX-run
+ (TeX-error-overview-make-entries
+ (TeX-master-directory) (TeX-active-buffer)))
+ (TeX-error-overview)))
+ (message (concat name ": formatted " (TeX-current-pages)))
+ (let (dvi2pdf)
+ (if (with-current-buffer TeX-command-buffer
+ (and TeX-PDF-mode (setq dvi2pdf (TeX-PDF-from-DVI))))
+ (setq TeX-command-next dvi2pdf)
+ (setq TeX-command-next TeX-command-Show)))))
+
+(defun TeX-current-pages ()
+ "Return string indicating the number of pages formatted."
+ (cond ((null TeX-current-page)
+ "some pages")
+ ((string-match "[^0-9]1[^0-9]" TeX-current-page)
+ (concat TeX-current-page " page"))
+ (t
+ (concat TeX-current-page " pages"))))
+
+(defun TeX-TeX-sentinel-check (process name)
+ "Cleanup TeX output buffer after running TeX.
+Return nil only if no errors were found."
+ (save-excursion
+ (goto-char (point-max))
+ (cond
+ ((and (string-match "ConTeXt" name) (boundp 'ConTeXt-Mark-version)
+ (with-current-buffer TeX-command-buffer
+ (string= ConTeXt-Mark-version "IV")))
+ (when (re-search-backward " > result saved in file: \\(.*?\\), " nil t)
+ (let ((output-file (TeX-match-buffer 1)))
+ ;; Shave off quotation marks if present.
+ (when (string-match "\\`\"\\(.*\\)\"\\'" output-file)
+ (setq output-file (match-string 1 output-file)))
+ (setq TeX-output-extension
+ (if (string-match "\\.\\([^.]*\\)$" output-file)
+ (match-string 1 output-file)
+ "dvi")))
+ (if (re-search-forward ", \\([0-9]+\\) shipped pages, " nil t)
+ (setq TeX-current-page (concat "{" (TeX-match-buffer 1) "}")))))
+ (t
+ (if (re-search-backward "^Output written on \\(.*?\\) (\\([0-9]+\\) page"
+ nil t)
+ (let ((output-file (TeX-match-buffer 1)))
+ (setq TeX-current-page (concat "{" (TeX-match-buffer 2) "}"))
+ ;; Shave off quotation marks if present.
+ (when (string-match "\\`\"\\(.*\\)\"\\'" output-file)
+ (setq output-file (match-string 1 output-file)))
+ (setq TeX-output-extension
+ (if (string-match "\\.\\([^.]*\\)$" output-file)
+ (match-string 1 output-file)
+ "dvi")))))))
+ (if process (TeX-format-mode-line process))
+ (if (re-search-forward "^\\(!\\|.*:[0-9]+:\\) " nil t)
+ (progn
+ (message "%s errors in `%s'. Use %s to display." name (buffer-name)
+ (substitute-command-keys
+ "\\<TeX-mode-map>\\[TeX-next-error]"))
+ (setq TeX-command-next TeX-command-default)
+ ;; error reported to TeX-error-report-switches
+ (setq TeX-error-report-switches
+ (plist-put TeX-error-report-switches
+ (intern (plist-get TeX-error-report-switches
+ 'TeX-current-master))
+ t))
+ t)
+ (let (dvi2pdf)
+ (if (with-current-buffer TeX-command-buffer
+ (and TeX-PDF-mode (setq dvi2pdf (TeX-PDF-from-DVI))))
+ (setq TeX-command-next dvi2pdf)
+ (setq TeX-command-next TeX-command-Show)))
+ nil))
+
+;; This regexp should catch warnings of the type
+;; LaTeX Warning: ...
+;; LaTeX Font Warning: ...
+;; Package xyz123 Warning: ...
+;; Class xyz123 Warning: ...
+(defvar LaTeX-warnings-regexp
+ "\\(?:LaTeX\\|Class\\|Package\\|\\*\\) [-A-Za-z0-9]* ?[Ww]arning:"
+ "Regexp matching LaTeX warnings.")
+
+(defun TeX-LaTeX-sentinel-has-warnings ()
+ "Return non-nil, if the output buffer contains warnings.
+Warnings can be indicated by LaTeX or packages."
+ (save-excursion
+ (goto-char (point-min))
+ (re-search-forward (concat "^" LaTeX-warnings-regexp) nil t)))
+
+(defun TeX-LaTeX-sentinel-has-bad-boxes ()
+ "Return non-nil, if LaTeX output indicates overfull or underfull boxes."
+ (save-excursion
+ (goto-char (point-min))
+ (re-search-forward "^\\(Ov\\|Und\\)erfull \\\\" nil t)))
+
+;; should go into latex.el? --pg
+(defun TeX-LaTeX-sentinel (process name)
+ "Cleanup TeX output buffer after running LaTeX.
+
+Parse the output buffer to collect errors and warnings if the
+variable `TeX-parse-all-errors' is non-nil.
+
+Open the error overview if
+`TeX-error-overview-open-after-TeX-run' is non-nil and there are
+errors or warnings to show."
+ (if TeX-parse-all-errors
+ (TeX-parse-all-errors))
+ (if (and TeX-error-overview-open-after-TeX-run
+ (TeX-error-overview-make-entries
+ (TeX-master-directory) (TeX-active-buffer)))
+ (TeX-error-overview))
+ (cond ((TeX-TeX-sentinel-check process name))
+ ((and (save-excursion
+ (re-search-forward
+ "^Package biblatex Warning: Please (re)run Biber on the file"
+ nil t))
+ (with-current-buffer TeX-command-buffer
+ (and (LaTeX-bibliography-list)
+ (TeX-check-files (TeX-master-file "bbl")
+ (TeX-style-list)
+ (append TeX-file-extensions
+ BibTeX-file-extensions
+ TeX-Biber-file-extensions)))))
+ (message "%s%s" "You should run Biber to get citations right, "
+ (TeX-current-pages))
+ (setq TeX-command-next (with-current-buffer TeX-command-buffer
+ TeX-command-Biber)))
+ ((and (save-excursion
+ (re-search-forward
+ "^\\(?:LaTeX\\|Package natbib\\) Warning: Citation" nil t))
+ (with-current-buffer TeX-command-buffer
+ (and (LaTeX-bibliography-list)
+ (TeX-check-files (TeX-master-file "bbl")
+ (TeX-style-list)
+ (append TeX-file-extensions
+ BibTeX-file-extensions
+ TeX-Biber-file-extensions)))))
+ (message "%s%s" "You should run BibTeX to get citations right, "
+ (TeX-current-pages))
+ (setq TeX-command-next (with-current-buffer TeX-command-buffer
+ TeX-command-BibTeX)))
+ ((re-search-forward "Package biblatex Warning: Please rerun LaTeX" nil t)
+ (message "%s%s" "You should run LaTeX again, " (TeX-current-pages))
+ (setq TeX-command-next TeX-command-default))
+ ((re-search-forward "^(biblatex)\\W+Page breaks have changed" nil t)
+ (message "%s%s" "You should run LaTeX again - page breaks have changed, "
+ (TeX-current-pages))
+ (setq TeX-command-next TeX-command-default))
+ ((re-search-forward "^\\(?:LaTeX Warning: Label(s)\\|\
+Package natbib Warning: Citation(s)\\)" nil t)
+ (message "%s%s" "You should run LaTeX again to get references right, "
+ (TeX-current-pages))
+ (setq TeX-command-next TeX-command-default))
+ ((re-search-forward
+ "^\\(?:(rerunfilecheck)\\|Package hyperref Warning:\\)\\W+\
+Rerun to get outlines right" nil t)
+ (message "%s%s" "You should run LaTeX again to get outlines right, "
+ (TeX-current-pages))
+ (setq TeX-command-next TeX-command-default))
+ ((re-search-forward "^LaTeX Warning: Reference" nil t)
+ (message "%s%s%s" name ": there were unresolved references, "
+ (TeX-current-pages))
+ (let (dvi2pdf)
+ (if (with-current-buffer TeX-command-buffer
+ (and TeX-PDF-mode (setq dvi2pdf (TeX-PDF-from-DVI))))
+ (setq TeX-command-next dvi2pdf)
+ (setq TeX-command-next TeX-command-Show))))
+ ((re-search-forward "^\\(?:LaTeX Warning: Citation\\|\
+Package natbib Warning:.*undefined citations\\)" nil t)
+ (message "%s%s%s" name ": there were unresolved citations, "
+ (TeX-current-pages))
+ (let (dvi2pdf)
+ (if (with-current-buffer TeX-command-buffer
+ (and TeX-PDF-mode (setq dvi2pdf (TeX-PDF-from-DVI))))
+ (setq TeX-command-next dvi2pdf)
+ (setq TeX-command-next TeX-command-Show))))
+ ((re-search-forward "^No file .*\\.\\(toc\\|lof\\|lot\\)\\.$" nil t)
+ (message "%s" (concat "You should run LaTeX again to get "
+ (upcase (match-string-no-properties 1))
+ " right"))
+ (setq TeX-command-next TeX-command-default))
+ ((re-search-forward "Package longtable Warning: Table widths have \
+changed\\. Rerun LaTeX\\." nil t)
+ (message
+ "%s" "You should run LaTeX again to get table formatting right")
+ (setq TeX-command-next TeX-command-default))
+ ((re-search-forward "^hf-TikZ Warning: Mark '.*' changed\\. \
+Rerun to get mark in right position\\." nil t)
+ (message
+ "%s" "You should run LaTeX again to get TikZ marks in right position")
+ (setq TeX-command-next TeX-command-default))
+ ((re-search-forward "^\\* xsim warning: \"rerun\"" nil t)
+ (message
+ "%s" "You should run LaTeX again to synchronize exercise properties")
+ (setq TeX-command-next TeX-command-default))
+ ((re-search-forward
+ "^\\(\\*\\* \\)?J?I?p?\\(La\\|Sli\\)TeX\\(2e\\)? \
+\\(Version\\|ver\\.\\|<[0-9/-]*\\(?:u[^>]*\\)?>\\)" nil t)
+ (let* ((warnings (and TeX-debug-warnings
+ (TeX-LaTeX-sentinel-has-warnings)))
+ (bad-boxes (and TeX-debug-bad-boxes
+ (TeX-LaTeX-sentinel-has-bad-boxes)))
+ (add-info (when (or warnings bad-boxes)
+ (concat " (with "
+ (when warnings "warnings")
+ (when (and warnings bad-boxes) " and ")
+ (when bad-boxes "bad boxes")
+ ")"))))
+ (message "%s" (concat name ": successfully formatted "
+ (TeX-current-pages) add-info)))
+ (let (dvi2pdf)
+ (if (with-current-buffer TeX-command-buffer
+ (and TeX-PDF-mode (setq dvi2pdf (TeX-PDF-from-DVI))))
+ (setq TeX-command-next dvi2pdf)
+ (setq TeX-command-next TeX-command-Show))))
+ (t
+ (message "%s%s%s" name ": problems after " (TeX-current-pages))
+ (setq TeX-command-next TeX-command-default)))
+
+ ;; Check whether the idx file changed.
+ (let (idx-file)
+ (and (file-exists-p
+ (setq idx-file
+ (with-current-buffer TeX-command-buffer
+ (expand-file-name (TeX-active-master "idx")))))
+ ;; imakeidx package automatically runs makeindex, thus, we need to be
+ ;; sure .ind file isn't newer than .idx.
+ (TeX-check-files (with-current-buffer TeX-command-buffer
+ (expand-file-name (TeX-active-master "ind")))
+ (with-current-buffer TeX-command-buffer
+ (list (file-name-nondirectory (TeX-active-master))))
+ '("idx"))
+ (with-temp-buffer
+ (insert-file-contents-literally idx-file)
+ (not (equal
+ ;; Compare old md5 hash of the idx file with the new one.
+ (cdr (assoc idx-file LaTeX-idx-md5-alist))
+ (md5 (current-buffer)))))
+ (push (cons idx-file t) LaTeX-idx-changed-alist)))
+
+ (unless (TeX-error-report-has-errors-p)
+ (run-hook-with-args 'TeX-after-compilation-finished-functions
+ (with-current-buffer TeX-command-buffer
+ (expand-file-name
+ (TeX-active-master (TeX-output-extension)))))))
+
+;; should go into latex.el? --pg
+(defun TeX-BibTeX-sentinel (_process _name)
+ "Cleanup TeX output buffer after running BibTeX."
+ (goto-char (point-max))
+ (cond
+ ;; Check whether BibTeX reports any warnings or errors.
+ ((re-search-backward (concat
+ "^(There \\(?:was\\|were\\) \\([0-9]+\\) "
+ "\\(warnings?\\|error messages?\\))")
+ nil t)
+ ;; Tell the user their number so that she sees whether the
+ ;; situation is getting better or worse.
+ (message (concat "BibTeX finished with %s %s. "
+ "Type `%s' to display output.")
+ (match-string 1) (match-string 2)
+ (substitute-command-keys
+ "\\<TeX-mode-map>\\[TeX-recenter-output-buffer]")))
+ (t
+ (message (concat "BibTeX finished successfully. "
+ "Run LaTeX again to get citations right."))))
+ ;; In any case, run the default next command.
+ (setq TeX-command-next TeX-command-default))
+
+(defun TeX-Biber-sentinel (_process _name)
+ "Cleanup TeX output buffer after running Biber."
+ (goto-char (point-max))
+ (cond
+ ((re-search-backward "^INFO - \\(WARNINGS\\|ERRORS\\): \\([0-9]+\\)" nil t)
+ (message (concat "Biber finished with %s %s. "
+ "Type `%s' to display output.")
+ (match-string 2) (downcase (match-string 1))
+ (substitute-command-keys
+ "\\<TeX-mode-map>\\[TeX-recenter-output-buffer]"))
+ (setq TeX-command-next TeX-command-default))
+ ((re-search-backward "^FATAL" nil t)
+ (message (concat "Biber had a fatal error and did not finish! "
+ "Type `%s' to display output.")
+ (substitute-command-keys
+ "\\<TeX-mode-map>\\[TeX-recenter-output-buffer]"))
+ (setq TeX-command-next TeX-command-Biber))
+ (t
+ (message (concat "Biber finished successfully. "
+ "Run LaTeX again to get citations right."))
+ (setq TeX-command-next TeX-command-default))))
+
+(defun TeX-dvips-sentinel (_process _name)
+ "Cleanup TeX output buffer after running dvips."
+ (goto-char (point-max))
+ (cond
+ ((search-backward "TeX Output exited abnormally" nil t)
+ (message "Dvips failed. Type `%s' to display output."
+ (substitute-command-keys
+ "\\<TeX-mode-map>\\[TeX-recenter-output-buffer]")))
+ (t
+ (if (with-current-buffer TeX-command-buffer
+ (and (equal (TeX-PDF-from-DVI) "Dvips") TeX-PDF-mode))
+ (setq TeX-output-extension "ps"
+ TeX-command-next "Ps2pdf"))
+ (message "Dvips finished successfully. "))))
+
+(defun TeX-dvipdfmx-sentinel (_process _name)
+ "Cleanup TeX output buffer after running dvipdfmx."
+ (goto-char (point-max))
+ (cond
+ ((search-backward "TeX Output exited abnormally" nil t)
+ (message "Dvipdfmx failed. Type `%s' to display output."
+ (substitute-command-keys
+ "\\<TeX-mode-map>\\[TeX-recenter-output-buffer]")))
+ (t
+ (if (with-current-buffer TeX-command-buffer
+ (and (equal (TeX-PDF-from-DVI) "Dvipdfmx") TeX-PDF-mode))
+ (setq TeX-output-extension "pdf"
+ TeX-command-next TeX-command-Show))
+ (message "Dvipdfmx finished successfully. "))))
+
+(defun TeX-ps2pdf-sentinel (_process _name)
+ "Cleanup TeX output buffer after running ps2pdf."
+ (goto-char (point-max))
+ (cond
+ ((search-backward "TeX Output exited abnormally" nil t)
+ (message "ps2pdf failed. Type `%s' to display output."
+ (substitute-command-keys
+ "\\<TeX-mode-map>\\[TeX-recenter-output-buffer]")))
+ (t
+ (if (with-current-buffer TeX-command-buffer
+ (and (equal (TeX-PDF-from-DVI) "Dvips") TeX-PDF-mode))
+ (setq TeX-command-next TeX-command-Show
+ TeX-output-extension "pdf"))
+ (message "ps2pdf finished successfully. "))))
+
+(defun TeX-index-sentinel (_process _name)
+ "Cleanup TeX output buffer after compiling index."
+ (goto-char (point-max))
+ (cond
+ ((search-backward "TeX Output exited abnormally" nil t)
+ (message "Index failed. Type `%s' to display output."
+ (substitute-command-keys
+ "\\<TeX-mode-map>\\[TeX-recenter-output-buffer]")))
+ (t
+ (setq TeX-command-next TeX-command-default)
+ (message (concat "Index finished successfully. "
+ "Run LaTeX again to get index right.")))))
+
+(defun TeX-command-sequence-sentinel (process string)
+ "Call the appropriate sentinel for the current PROCESS.
+Pass two arguments PROCESS and STRING to the sentinel.
+
+If there are no errors, call back `TeX-command-sequence' using
+`TeX-command-sequence-command' as command argument, unless this
+variable is nil."
+ (with-current-buffer (process-buffer process)
+ (funcall TeX-command-sequence-sentinel process string)
+ (if (string-match "\\(finished\\|exited\\)" string)
+ (with-current-buffer TeX-command-buffer
+ (unless
+ (or
+ (TeX-error-report-has-errors-p)
+ (null TeX-command-sequence-command))
+ (TeX-command-sequence TeX-command-sequence-command nil
+ TeX-command-sequence-file-function))))))
+
+;;; Process Control
+
+;; COMPATIBILITY for emacs < 27
+(if (< emacs-major-version 27)
+ (or (assq 'compilation-in-progress minor-mode-alist)
+ (setq minor-mode-alist (cons '(compilation-in-progress " Compiling")
+ minor-mode-alist))))
+
+(defun TeX-process-get-variable (name symbol &optional default)
+ "Return the value in the process buffer for NAME of SYMBOL.
+
+Return DEFAULT if the process buffer does not exist or SYMBOL is not
+defined."
+ (let ((buffer (TeX-process-buffer name)))
+ (if (and buffer
+ (local-variable-p symbol buffer))
+ (with-current-buffer buffer
+ (symbol-value symbol))
+ default)))
+
+(defun TeX-process-set-variable (name symbol value)
+ "Set the variable SYMBOL in the process buffer to VALUE.
+Return nil only if no process buffer exists."
+ (let ((buffer (TeX-process-buffer name)))
+ (if buffer
+ (with-current-buffer buffer
+ (set symbol value)
+ t)
+ nil)))
+
+(defun TeX-process-check (name)
+ "Check if a process for the TeX document NAME already exist.
+If so, give the user the choice of aborting the process or the current
+command."
+ (let (process)
+ (while (and (setq process (TeX-process name))
+ (eq (process-status process) 'run))
+ (cond
+ ((yes-or-no-p (concat "Process `"
+ (process-name process)
+ "' for document `"
+ name
+ "' running, kill it? "))
+ (delete-process process))
+ ((eq (process-status process) 'run)
+ (error "Cannot have two processes for the same document"))))))
+
+(defun TeX-process-buffer-name (name)
+ "Return name of AUCTeX buffer associated with the document NAME."
+ (concat "*" (abbreviate-file-name (expand-file-name name)) " output*"))
+
+(defun TeX-process-buffer (name)
+ "Return the AUCTeX buffer associated with the document NAME."
+ (get-buffer (TeX-process-buffer-name name)))
+
+(defun TeX-process (name)
+ "Return AUCTeX process associated with the document NAME."
+ (and TeX-process-asynchronous
+ (get-buffer-process (TeX-process-buffer name))))
+
+;;; Process Filters
+
+(defun TeX-command-mode-line (process)
+ "Format the mode line for a buffer containing output from PROCESS."
+ (setq mode-line-process (concat ": "
+ (symbol-name (process-status process))))
+ (force-mode-line-update))
+
+(defun TeX-command-filter (process string)
+ "Filter to process normal output."
+ (with-current-buffer (process-buffer process)
+ (save-excursion
+ (goto-char (process-mark process))
+ (insert-before-markers string)
+ (set-marker (process-mark process) (point)))))
+
+(defvar TeX-current-page nil
+ "The page number currently being formatted, enclosed in brackets.")
+
+ (make-variable-buffer-local 'TeX-current-page)
+
+(defun TeX-format-mode-line (process)
+ "Format the mode line for a buffer containing TeX output from PROCESS."
+ (setq mode-line-process (concat " " TeX-current-page ": "
+ (symbol-name (process-status process))))
+ (force-mode-line-update))
+
+(defun TeX-format-filter (process string)
+ "Filter to process TeX output."
+ (with-current-buffer (process-buffer process)
+ (let (str pos end (pt (marker-position (process-mark process))))
+ (save-excursion
+ (goto-char pt)
+ (insert-before-markers string)
+ (set-marker (process-mark process) (point))
+ ;; Remove line breaks at columns 79 and 80
+ (while (> (point) pt)
+ (end-of-line 0)
+ (when (and (memq (- (point) (line-beginning-position)) '(79 80))
+ ;; Heuristic: Don't delete the linebreak if the next line
+ ;; is empty or starts with an opening parenthesis, or if
+ ;; point is located after a period and in the next line no
+ ;; word char follows.
+ (not (memq (char-after (1+ (point))) '(?\n ?\()))
+ (not (and (eq (char-before) ?.)
+ (char-after (1+ (point)))
+ (not (eq ?w (char-syntax (char-after (1+ (point)))))))))
+ (delete-char 1)))
+ (goto-char (marker-position (process-mark process)))
+ ;; Determine current page
+ (while (and pt
+ (skip-chars-backward "^]" pt)
+ (> (point) pt))
+ (setq end (point))
+ (backward-char)
+ (skip-chars-backward "-0-9\n." (max (point-min) (- pt 128)))
+ (when (and (eq ?\[ (char-before))
+ (not (eq ?\] (char-after)))
+ (progn
+ (setq str (buffer-substring (1- (point)) end)
+ pos nil)
+ (while (setq pos (string-match "\n" str pos))
+ (setq str (replace-match "" t t str)))
+ (string-match
+ "\\`\\[-?[0-9]+\\(\\.-?[0-9]+\\)\\{0,9\\}\\]\\'"
+ str)))
+ (setq TeX-current-page str
+ pt nil)
+ (TeX-format-mode-line process)))))))
+
+(defvar TeX-parse-function nil
+ "Function to call to parse content of TeX output buffer.")
+(make-variable-buffer-local 'TeX-parse-function)
+
+(defun TeX-background-filter (_process string)
+ "Filter to process background output."
+ (let ((old-window (selected-window))
+ (pop-up-windows t))
+ (TeX-pop-to-buffer "*TeX background*" nil t)
+ (goto-char (point-max))
+ (insert string)
+ (select-window old-window)))
+
+;; Copy and adaption of `comint-postoutput-scroll-to-bottom' from CVS
+;; Emacs of 2005-04-24.
+(defun TeX-interactive-goto-prompt (string)
+ "Move point to prompt of an interactive TeX run."
+ (let* ((selected (selected-window))
+ (current (current-buffer))
+ (process (get-buffer-process current)))
+ (unwind-protect
+ (when process
+ (walk-windows
+ (lambda (window)
+ (when (eq (window-buffer window) current)
+ (select-window window)
+ (when (and (< (point) (process-mark process))
+ (string-match "^\\? $" string))
+ (goto-char (process-mark process)))
+ (select-window selected)))
+ nil t))
+ (set-buffer current))))
+
+
+;;; Active Process
+
+(defvar TeX-current-process-region-p nil
+ "Non-nil means that the last TeX command is on a region.")
+
+(defun TeX-active-process ()
+ "Return the active process for the current buffer."
+ (TeX-process (TeX-active-master)))
+
+(defun TeX-active-buffer ()
+ "Return the buffer of the active process for this buffer."
+ (and TeX-command-buffer
+ (with-current-buffer TeX-command-buffer
+ (TeX-process-buffer (TeX-active-master)))))
+
+(defun TeX-active-master (&optional extension nondirectory _ignore)
+ "The master file currently being compiled.
+
+If optional argument EXTENSION is non-nil, add that file extension to
+the name. Special value t means use `TeX-default-extension'.
+
+If optional second argument NONDIRECTORY is non-nil, do not include
+the directory.
+
+The compatibility argument IGNORE is ignored."
+ ;; The third argument `_ignore' is kept for symmetry with
+ ;; `TeX-master-file's third argument `ask'. For example, it's used
+ ;; in `TeX-active-master-with-quotes' for backward compatibility.
+ ;; Keep this in mind should you want to use another argument here.
+ ;; See also the similar comment in `TeX-region-file'.
+ (if TeX-current-process-region-p
+ (TeX-region-file extension nondirectory)
+ (TeX-master-file extension nondirectory)))
+
+(defvar TeX-command-buffer nil
+ "The buffer from where the last TeX command was issued.")
+
+;;; Region File
+
+
+(defvar TeX-region-hook nil
+ "List of hooks to run before the region file is saved.
+The hooks are run in the region buffer, you may use the variable
+`TeX-region-master-buffer' to access the buffer of the master
+file and `TeX-region-orig-buffer' to access the buffer where
+\\[TeX-command-region] or \\[TeX-command-buffer] is invoked
+from.")
+
+(defun TeX-quote-filename (file)
+ "Convert file name FILE into a form acceptable to TeX."
+ (let (pos)
+ (while (setq pos (string-match "\\\\" file pos))
+ (setq file (replace-match "/" t t file 0)
+ pos (1+ pos)))
+ (while (setq pos (string-match "[~#]" file pos))
+ (setq file (replace-match "\\\\string\\&" t nil file 0)
+ pos (+ pos 8))))
+ ;; Use \unexpanded so that \message outputs the raw file name.
+ ;; When \usepackage[utf8]{inputenc} is used in standard (pdf)latex,
+ ;; \message does not output non-ascii file name in raw form without
+ ;; \unexpanded, which makes AUCTeX to fail to recognize the file
+ ;; names right when analysing the process output buffer.
+ ;; Note that \usepackage[utf8]{inputenc} is enabled by default in
+ ;; standard (pdf)latex since TeXLive 2018.
+ (if (and (memq major-mode '(latex-mode doctex-mode))
+ ;; Japanese upLaTeX requires the same treatment with
+ ;; respect to non-ascii characters other than Japanese, in
+ ;; file names within \message{}.
+ ;; However, pLaTeX (non u- version) does not support
+ ;; non-ascii file name encoded in UTF-8. So considering
+ ;; `ptex' doesn't make sense here. We cater for only
+ ;; `default' and `uptex' engines.
+ (memq TeX-engine '(default uptex)))
+ ;; It would fail to put entire `file' inside \unexpanded{} when
+ ;; the above loop injects \string before "#" and "~". So put
+ ;; only multibyte characters inside \unexpanded{}.
+ ;; It is safe in upLaTeX to use \unexpanded{} on Japanese
+ ;; characters though they are handled by upLaTeX in a totally
+ ;; different way from inputenc.
+ ;; Thus put all multibyte characters, without considering
+ ;; whether they are Japanese or not, inside \unexpanded{}.
+ (replace-regexp-in-string "[[:multibyte:]]+"
+ "\\\\unexpanded{\\&}" file t)
+ file))
+
+(defvar-local TeX-region-orig-buffer nil
+ "The original buffer in which the TeX-region was created.")
+
+(defvar-local TeX-region-master-buffer nil
+ "The TeX-master buffer of the document for which the TeX-region
+was created.")
+
+(defun TeX-region-create (file region original offset)
+ "Create a new file named FILE with the string REGION.
+The region is taken from ORIGINAL starting at line OFFSET.
+
+The current buffer and master file is searched, in order to ensure
+that the TeX header and trailer information is also included.
+
+The OFFSET is used to provide the debugger with information about the
+original file."
+ (if (fboundp 'preview--skip-preamble-region)
+ (let ((temp (preview--skip-preamble-region region offset)))
+ (if temp
+ ;; Skip preamble for the sake of predumped formats.
+ (setq region (car temp)
+ offset (cdr temp)))))
+
+ (let* (;; We shift buffer a lot, so we must keep track of the buffer
+ ;; local variables.
+ (header-end TeX-header-end)
+ (trailer-start TeX-trailer-start)
+
+ ;; We seach for header and trailer in the master file.
+ (orig-buffer (current-buffer))
+ (master-name (TeX-master-file TeX-default-extension))
+ (master-buffer (find-file-noselect master-name))
+
+ ;; Attempt to disable font lock.
+ (font-lock-mode-hook nil)
+ ;; And insert them into the FILE buffer.
+ (file-buffer (let (;; Don't query for master file
+ (TeX-transient-master t)
+ ;; Don't choose a special mode (and call its hooks)
+ (auto-mode-alist nil)
+ (magic-mode-alist nil)
+ (enable-local-variables nil)
+ ;; Don't run any f-f hooks
+ (find-file-hook nil))
+ (find-file-noselect file t)))
+ ;; But remember original content.
+ original-content
+
+ ;; We search for the header from the master file, if it is
+ ;; not present in the region.
+ (header (if (string-match header-end region)
+ ""
+ (save-excursion
+ (save-restriction
+ (set-buffer master-buffer)
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ ;; NOTE: We use the local value of
+ ;; TeX-header-end from the master file.
+ (if (not (re-search-forward TeX-header-end nil t))
+ ""
+ (re-search-forward "[\r\n]" nil t)
+ (buffer-substring-no-properties
+ (point-min) (point)))))))))
+ (header-offset 0)
+ first-line
+ ;; We search for the trailer from the master file, if it is
+ ;; not present in the region.
+ (trailer-offset 0)
+ (trailer (if (string-match trailer-start region)
+ ""
+ (save-excursion
+ (save-restriction
+ (set-buffer master-buffer)
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-max))
+ ;; NOTE: We use the local value of
+ ;; TeX-trailer-start from the master file.
+ (if (not (re-search-backward TeX-trailer-start nil t))
+ ""
+ ;;(beginning-of-line 1)
+ (re-search-backward "[\r\n]" nil t)
+ (setq trailer-offset (TeX-current-offset))
+ (buffer-substring-no-properties
+ (point) (point-max))))))))))
+ ;; file name should be relative to master
+ (setq original (TeX-quote-filename (file-relative-name
+ original (TeX-master-directory)))
+ master-name (TeX-quote-filename master-name))
+
+ ;; If the first line begins with "%&", put that line separately on
+ ;; the very first line of the region file so that the first line
+ ;; parsing will work.
+ (setq first-line (if (and (> (length header) 1)
+ (string= (substring header 0 2) "%&"))
+ ;; This would work even if header has no newline.
+ (substring header 0 (string-match "\n" header))
+ ""))
+ (unless (string= first-line "")
+ ;; Remove first-line from header.
+ (setq header (substring header (length first-line)))
+ (setq first-line (concat first-line "\n")))
+
+ (with-current-buffer file-buffer
+ (setq buffer-read-only t
+ buffer-undo-list t)
+ (setq original-content (buffer-string))
+ (let ((inhibit-read-only t))
+ (erase-buffer)
+ (setq buffer-file-coding-system
+ (with-current-buffer master-buffer buffer-file-coding-system))
+ (insert first-line
+ "\\message{ !name(" master-name ")}"
+ header
+ TeX-region-extra
+ "\n\\message{ !name(" original ") !offset(")
+ (setq header-offset (- offset
+ (1+ (TeX-current-offset))))
+ (insert (int-to-string header-offset)
+ ") }\n"
+ region
+ "\n\\message{ !name(" master-name ") !offset(")
+ (insert (int-to-string (- trailer-offset
+ (1+ (TeX-current-offset))))
+ ") }\n"
+ trailer)
+ (setq TeX-region-orig-buffer orig-buffer)
+ (setq TeX-region-master-buffer master-buffer)
+ (run-hooks 'TeX-region-hook)
+ (if (string-equal (buffer-string) original-content)
+ (set-buffer-modified-p nil)
+ (save-buffer 0))))))
+
+(defun TeX-region-file (&optional extension nondirectory _ignore)
+ "Return TeX-region file name with EXTENSION.
+If optional second argument NONDIRECTORY is non-nil, do not include
+the directory.
+
+The compatibility argument IGNORE is ignored."
+ ;; The third argument `_ignore' is kept for symmetry with `TeX-master-file's
+ ;; third argument `ask'. For example, it's used in `TeX-command-sequence',
+ ;; where we don't know which function has to be called. Keep this in mind
+ ;; should you want to use another argument here.
+ (let ((master-dir (TeX-master-directory)))
+ (concat (or (TeX--master-output-dir master-dir nondirectory)
+ (if nondirectory "" master-dir))
+ (cond ((eq extension t)
+ (concat TeX-region "." TeX-default-extension))
+ (extension
+ (concat TeX-region "." extension))
+ (t
+ TeX-region)))))
+
+(defcustom TeX-region "_region_"
+ "Base name of temporary file for `TeX-command-region' and `TeX-command-buffer'."
+ :group 'TeX-command
+ :type 'string)
+
+(defvar LaTeX-command-section-level nil
+ "The section level used for `LaTeX-command-section'.
+Will be initialized to `LaTeX-largest-level' buffer-locally.")
+(make-variable-buffer-local 'LaTeX-command-section-level)
+
+(defun LaTeX-command-section-level ()
+ "Return the value of `LaTeX-command-section-level'.
+Initialize it to `LaTeX-largest-level' if needed."
+ (unless LaTeX-command-section-level
+ (setq LaTeX-command-section-level LaTeX-largest-level))
+ LaTeX-command-section-level)
+
+
+(defun LaTeX-command-section-change-level (arg)
+ "Change `LaTeX-command-section-level' by ARG.
+`LaTeX-command-section-level' is the sectioning level used to
+determine the current section by `LaTeX-command-section'.
+The levels are defined by `LaTeX-section-list'."
+ (interactive "p")
+ (let ((old-level (car (rassoc (list (LaTeX-command-section-level))
+ LaTeX-section-list))))
+ (setq LaTeX-command-section-level (+ LaTeX-command-section-level arg))
+ (cond
+ ((> LaTeX-command-section-level 6)
+ (setq LaTeX-command-section-level 6)
+ (message "Cannot shrink LaTeX-command-section-level below subparagraph."))
+ ((< LaTeX-command-section-level 0)
+ (setq LaTeX-command-section-level 0)
+ (message "Cannot enlarge LaTeX-command-section-level above part."))
+ (t (message "Changed level from %s to %s."
+ old-level (car (rassoc (list LaTeX-command-section-level)
+ LaTeX-section-list)))))))
+
+(defun LaTeX-command-section-boundaries ()
+ "Return the boundaries of the current section as (start . end).
+The section is determined by `LaTeX-command-section-level'."
+ (let* ((case-fold-search nil)
+ (rx (concat "\\\\" (regexp-opt
+ (mapcar
+ (lambda (level)
+ (car (rassoc (list level) LaTeX-section-list)))
+ (let (r)
+ (dotimes (i (1+ (LaTeX-command-section-level)))
+ (push i r))
+ r)))
+ "{")))
+ (cons (save-excursion
+ (re-search-backward rx nil t)
+ (point))
+ (save-excursion
+ (re-search-forward (concat rx "\\|\\\\end{document}") nil t)
+ (forward-line 0)
+ (point)))))
+
+(defun LaTeX-command-section (&optional override-confirm)
+ "Run a command on the current section.
+
+What makes the current section is defined by
+`LaTeX-command-section-level' which can be enlarged or shrunken
+with `LaTeX-command-section-change-level'.
+
+Query the user for a command to run on the temporary file
+specified by the variable `TeX-region'. The region file will be
+recreated from current section.
+
+If a prefix argument OVERRIDE-CONFIRM is given, confirmation will
+depend on it being positive instead of the entry in
+`TeX-command-list'."
+ (interactive "P")
+ (if (eq major-mode 'latex-mode)
+ (let* ((bounds (LaTeX-command-section-boundaries))
+ (TeX-command-region-begin (car bounds))
+ (TeX-command-region-end (cdr bounds)))
+ (TeX-command-region override-confirm))
+ (error "LaTeX-command-section can only be run on LaTeX documents")))
+
+(defun TeX-command-run-all-region ()
+ "Compile the current region until an error occurs or it is finished."
+ (interactive)
+ (TeX-region-update)
+ (TeX-command-sequence t t #'TeX-region-file))
+
+(defun LaTeX-command-run-all-section ()
+ "Compile the current section until an error occurs or it is finished."
+ (interactive)
+ (if (eq major-mode 'latex-mode)
+ (let* ((bounds (LaTeX-command-section-boundaries))
+ (TeX-command-region-begin (car bounds))
+ (TeX-command-region-end (cdr bounds)))
+ (TeX-region-update)
+ (TeX-command-sequence t t #'TeX-region-file))
+ (error "LaTeX-command-run-all-section can only be run on LaTeX documents")))
+
+(defun TeX-command-run-all (arg)
+ "Compile the current document until an error occurs or it is finished.
+With a prefix ARG (`\\[universal-argument] \\[TeX-command-run-all]'),
+compile the current region instead, that is, call
+`TeX-command-run-all-region'. With multiple prefix
+arguments (`\\[universal-argument] \\[universal-argument] \\[TeX-command-run-all]'),
+compile the current section instead, that is, call
+`LaTeX-command-run-all-section'."
+ (interactive "P")
+ (cond
+ ((null arg) (TeX-command-sequence t t))
+ ((= 4 (car arg)) (TeX-command-run-all-region))
+ (t (LaTeX-command-run-all-section))))
+
+;;; Parsing
+
+;;; - Global Parser Variables
+
+(defvar TeX-error-point nil
+ "How far we have parsed until now.")
+
+(make-variable-buffer-local 'TeX-error-point)
+
+(defvar TeX-error-file nil
+ "Stack of files in which errors have occurred.")
+
+(make-variable-buffer-local 'TeX-error-file)
+
+(defvar TeX-error-offset nil
+ "Add this to any line numbers from TeX. Stack like `TeX-error-file'.")
+
+(make-variable-buffer-local 'TeX-error-offset)
+
+(defun TeX-parse-reset (&optional reparse)
+ "Reset all variables used for parsing TeX output.
+If optional argument REPARSE is non-nil, reparse the output log."
+ (setq TeX-error-point (point-min)
+ TeX-error-offset nil
+ TeX-error-file nil
+ TeX-error-list nil
+ TeX-error-last-visited -1)
+ (if reparse
+ (TeX-parse-all-errors)))
+
+;;; - Parsers Hooks
+
+;; All this parsers hooks should have the same arguments even though they will
+;; be ignored, because `TeX-next-error' can call any of these functions.
+(defun TeX-parse-command (_arg _reparse)
+ "We can't parse anything but TeX."
+ (error "I cannot parse %s output, sorry"
+ (if (TeX-active-process)
+ (process-name (TeX-active-process))
+ "this")))
+
+(defun TeX-error-list-skip-warning-p (type ignore)
+ "Decide if a warning of `TeX-error-list' should be skipped.
+
+TYPE is one of the types listed in `TeX-error-list', IGNORE
+is the flag to choose if the warning should be skipped."
+ ;; The warning should be skipped if it...
+ (or
+ ;; ...is a warning and we want to ignore all warnings, or...
+ (and (null TeX-debug-warnings)
+ (equal type 'warning))
+ ;; ...is a bad-box and we want to ignore all bad-boxes, or...
+ (and (null TeX-debug-bad-boxes)
+ (equal type 'bad-box))
+ ;; ...is a warning to be ignored.
+ (and TeX-suppress-ignored-warnings
+ ignore)))
+
+(defun TeX-parse-TeX (arg reparse)
+ "Find the next error produced by running TeX.
+
+ARG specifies how many error messages to move, when possible;
+negative means move back to previous error messages.
+
+If REPARSE is non-nil, reparse the output log.
+
+If the file occurs in an included file, the file is loaded (if not
+already in an Emacs buffer) and the cursor is placed at the error."
+ (let ((old-buffer (current-buffer))
+ max-index item)
+
+ ;; Switch to the output buffer.
+ (with-current-buffer (TeX-active-buffer)
+ (if reparse
+ (TeX-parse-reset reparse))
+ (if TeX-parse-all-errors
+ (progn
+ (setq arg (or arg 1)
+ max-index (length TeX-error-list))
+ ;; This loop is needed to skip ignored warnings, when
+ ;; `TeX-suppress-ignored-warnings' is non-nil and there are ignore
+ ;; warnings.
+ (while (null (zerop arg))
+ (setq TeX-error-last-visited
+ ;; Increase or decrese `TeX-error-last-visited' depending on
+ ;; the sign of `arg'. Note: `signum' is a function from
+ ;; `cl' library, do not be tempted to use it.
+ (if (> arg 0)
+ (1+ TeX-error-last-visited)
+ (1- TeX-error-last-visited))
+ item (nth TeX-error-last-visited TeX-error-list))
+ ;; Increase or decrease `arg' only if the warning isn't to be
+ ;; skipped.
+ (unless (TeX-error-list-skip-warning-p (nth 0 item) (nth 10 item))
+ ;; Note: `signum' is a function from `cl' library, do not be
+ ;; tempted to use it.
+ (setq arg (if (> arg 0)
+ (1- arg)
+ (1+ arg)))))
+ (if (< TeX-error-last-visited -1)
+ (setq TeX-error-last-visited -1))
+ (cond ((or (null item)
+ (< TeX-error-last-visited 0))
+ (if (> TeX-error-last-visited max-index)
+ (setq TeX-error-last-visited max-index))
+ (message "No more errors.")
+ (beep)
+ (TeX-pop-to-buffer old-buffer))
+ (t
+ (apply #'TeX-find-display-help item))))
+
+ (goto-char TeX-error-point)
+ (TeX-parse-error old-buffer)))))
+
+;;; - Parsing (La)TeX
+
+(defvar TeX-translate-location-file nil)
+(defvar TeX-translate-location-offset nil)
+(defvar TeX-translate-location-line nil)
+(defvar TeX-translate-location-string nil)
+(defvar TeX-translate-location-error nil)
+(defvar TeX-translate-location-context nil)
+
+(defvar TeX-translate-location-hook nil
+ "List of functions to be called before showing an error or warning.
+
+You might want to examine and modify the dynamically bound
+variables
+ `TeX-translate-location-file',
+ `TeX-translate-location-offset',
+ `TeX-translate-location-line',
+ `TeX-translate-location-string',
+ `TeX-translate-location-error', and
+ `TeX-translate-location-context'
+from this hook.")
+
+;; `ignore' flag should be the always the last one in the list of information
+;; for each error/warning, because it can be set within `TeX-warning' by a
+;; custom function taking as argument all information present in
+;; `TeX-error-list' but `ignore', see `TeX-ignore-warnings'.
+(defvar TeX-error-list nil
+ "List of warnings and errors.
+
+Each element of the list is a list of information for a specific
+error or warning. This is the structure of each element:
+ * 0: type (error, warning, bad-box)
+ * 1: file
+ * 2: line
+ * 3: message of the error or warning
+ * 4: offset
+ * 5: context, to be displayed in the help window
+ * 6: string to search in the buffer, in order to find location
+ of the error or warning
+ * 7: for warnings referring to multiple lines (for exapmle, bad boxes),
+ the last line mentioned in the warning message
+ * 8: t if it is a bad-box, nil otherwise
+ * 9: value of `TeX-error-point'
+ * 10: whether the warning should be ignored
+
+This variable is intended to be set only in output buffer so it
+will be shared among all files of the same document.")
+(make-variable-buffer-local 'TeX-error-list)
+
+(defun TeX-parse-all-errors ()
+ "Parse TeX output buffer to collect all warnings and errors."
+ ;; Reset error list.
+ (setq TeX-error-list nil)
+ (save-excursion
+ (goto-char (point-min))
+ (while (TeX-parse-error nil t)))
+ ;; Reset last visited error.
+ (setq TeX-error-last-visited -1))
+
+(defun TeX-parse-error (old &optional store)
+ "Goto next error. Pop to OLD buffer if no more errors are found.
+
+If the optional argument STORE is non-nil, the function will
+store the found warning or error in `TeX-error-list' instead of
+displaying the issue.
+
+Return non-nil if an error or warning is found."
+ (let ((regexp
+ (concat
+ ;; TeX error
+ "^\\(!\\|\\(.*?\\):[0-9]+:\\) \\|"
+ ;; New file
+ "(\n?\\([^\n()]+\\)\\|"
+ ;; End of file.
+ "\\()\\)\\|"
+ ;; Hook to change line numbers
+ " !\\(?:offset(\\([---0-9]+\\))\\|"
+ ;; Hook to change file name
+ "name(\\([^)]+\\))\\)\\|"
+ ;; Start of LaTeX bad box
+ "^\\(\\(?:Overfull\\|Underfull\\|Tight\\|Loose\\) "
+ ;; Horizontal bad box
+ "\\(?:\\\\hbox.* at lines? [0-9]+\\(?:--[0-9]+\\)?$\\|"
+ ;; Vertical bad box. See also `TeX-warning'.
+ "\\\\vbox ([ a-z0-9]+) has occurred while \\\\output is active \\[[^]]+\\]\\)\\)\\|"
+ ;; LaTeX warning
+ "^\\(" LaTeX-warnings-regexp ".*\\)"))
+ (error-found nil))
+ (while
+ (cond
+ ((null
+ (re-search-forward regexp nil t))
+ ;; No more errors.
+ (unless store
+ (message "No more errors.")
+ (beep)
+ (TeX-pop-to-buffer old))
+ nil)
+ ;; TeX error
+ ((match-beginning 1)
+ (when (match-beginning 2)
+ (unless TeX-error-file
+ (push nil TeX-error-file)
+ (push nil TeX-error-offset))
+ (unless (car TeX-error-offset)
+ (rplaca TeX-error-file (TeX-match-buffer 2))))
+ (setq error-found t)
+ (if (looking-at "Preview ")
+ t
+ (TeX-error store)
+ nil))
+ ;; LaTeX bad box
+ ((match-beginning 7)
+ ;; In `TeX-error-list' we collect all warnings, also if they're going
+ ;; to be actually skipped.
+ (if (or store TeX-debug-bad-boxes)
+ (progn
+ (setq error-found t)
+ (TeX-warning (TeX-match-buffer 7) (match-beginning 7) t store)
+ nil)
+ (re-search-forward "\r?\n\
+\\(?:.\\{79\\}\r?\n\
+\\)*.*\r?$")
+ t))
+ ;; LaTeX warning
+ ((match-beginning 8)
+ ;; In `TeX-error-list' we collect all warnings, also if they're going
+ ;; to be actually skipped.
+ (if (or store TeX-debug-warnings)
+ (progn
+ (setq error-found t)
+ (TeX-warning (TeX-match-buffer 8) (match-beginning 8) nil store)
+ nil)
+ t))
+
+ ;; New file -- Push on stack
+ ((match-beginning 3)
+ (let ((file (TeX-match-buffer 3))
+ (end (match-end 3)))
+ ;; Strip quotation marks and remove newlines if necessary
+ (when (or (eq (string-to-char file) ?\")
+ (string-match "[ \t\n]" file))
+ (setq file (mapconcat #'identity (split-string file "[\"\n]+") "")))
+ ;; Polish `file' string
+ (setq file
+ (let ((string file))
+ (setq string
+ (if (string-match "\\`[ \t\n\r]+" string)
+ (replace-match "" t t string)
+ string))
+ ;; Sometimes `file' is something like
+ ;; "./path/to/file.tex [9] [10 <./path/to/file>] "
+ ;; where "[9]" and "[10 <./path/to/file>]" are pages of the
+ ;; output file, with path to an included file. Remove these
+ ;; numbers together with whitespaces at the end of the
+ ;; string.
+ (if (string-match "\\( *\\(\\[[^]]+\\]\\)? *\\)*\\'" string)
+ (replace-match "" t t string)
+ string)))
+ (push file TeX-error-file)
+ (push nil TeX-error-offset)
+ (goto-char end))
+ t)
+
+ ;; End of file -- Pop from stack
+ ((match-beginning 4)
+ (when (> (length TeX-error-file) 0)
+ (pop TeX-error-file)
+ (pop TeX-error-offset))
+ (goto-char (match-end 4))
+ t)
+
+ ;; Hook to change line numbers
+ ((match-beginning 5)
+ (setq TeX-error-offset
+ (list (string-to-number (TeX-match-buffer 5))))
+ t)
+
+ ;; Hook to change file name
+ ((match-beginning 6)
+ (setq TeX-error-file
+ (list (TeX-match-buffer 6)))
+ t)))
+ error-found))
+
+(defun TeX-find-display-help (type file line error offset context string
+ line-end _bad-box error-point _ignore)
+ "Find the error and display the help.
+
+For a description of arguments, see `TeX-error-list'. IGNORE
+value is not used here."
+ ;; Go back to TeX-buffer
+ (let ((runbuf (TeX-active-buffer))
+ (master (with-current-buffer TeX-command-buffer
+ (expand-file-name (TeX-master-file))))
+ (command-buffer TeX-command-buffer)
+ (TeX-translate-location-file file)
+ (TeX-translate-location-line line)
+ (TeX-translate-location-error error)
+ (TeX-translate-location-offset offset)
+ (TeX-translate-location-context context)
+ (TeX-translate-location-string string)
+ error-file-buffer start)
+
+ (run-hooks 'TeX-translate-location-hook)
+
+ (if TeX-translate-location-file
+ (progn
+ (setq error-file-buffer
+ (find-file
+ (expand-file-name TeX-translate-location-file
+ (file-name-directory master))))
+ ;; Use the major mode of `TeX-command-buffer' when visiting
+ ;; the error point.
+ (if (eq major-mode (default-value 'major-mode))
+ (funcall (buffer-local-value 'major-mode command-buffer)))
+ ;; Set the value of `TeX-command-buffer' in the next file
+ ;; with an error to be displayed to the value it has in the
+ ;; current buffer.
+ (setq-local TeX-command-buffer command-buffer)
+
+ ;; Find the location of the error or warning.
+ (when TeX-translate-location-line
+ (goto-char (point-min))
+ (forward-line (+ TeX-translate-location-offset
+ TeX-translate-location-line -1))
+ (cond
+ ;; Error.
+ ((equal type 'error)
+ (if (not (string= TeX-translate-location-string " "))
+ (search-forward TeX-translate-location-string nil t)))
+ ;; Warning or bad box.
+ (t
+ (beginning-of-line 0)
+ (setq start (point))
+ (goto-char (point-min))
+ (forward-line (+ TeX-translate-location-offset
+ line-end -1))
+ (end-of-line)
+ (when TeX-translate-location-string
+ (search-backward TeX-translate-location-string start t)
+ (search-forward TeX-translate-location-string nil t))))))
+ ;; When the file cannot be determined stay here but issue a
+ ;; warning.
+ (message "Could not determine file for %s"
+ (if (eq type 'error) "error" "warning"))
+ (beep))
+
+ ;; Display the help.
+ (cond ((eq TeX-display-help 'expert)
+ (TeX-pop-to-buffer runbuf nil t)
+ (goto-char error-point)
+ (if error-file-buffer
+ (TeX-pop-to-buffer error-file-buffer nil t)))
+ (TeX-display-help
+ (TeX-help-error
+ TeX-translate-location-error
+ (if (equal type 'warning)
+ (concat "\n" TeX-translate-location-context)
+ TeX-translate-location-context)
+ runbuf type))
+ (t
+ (message "! %s" TeX-translate-location-error)))))
+
+(defun TeX-error (&optional store)
+ "Display an error.
+
+If optional argument STORE is non-nil, store the error
+information in `TeX-error-list' instead of displaying the error."
+
+ (let* ( ;; We need the error message to show the user.
+ (error (progn
+ (re-search-forward "\\(.*\\)")
+ (TeX-match-buffer 1)))
+
+ ;; And the context for the help window.
+ (context-start (point))
+ context-available
+
+ ;; And the line number to position the cursor.
+ (line (cond
+ ;; regular style
+ ((re-search-forward "l\\.\\([0-9]+\\)" nil t)
+ (setq context-available t)
+ (string-to-number (TeX-match-buffer 1)))
+ ;; file:line:error style
+ ((save-excursion
+ (re-search-backward ":\\([0-9]+\\): "
+ (line-beginning-position) t))
+ (string-to-number (TeX-match-buffer 1)))
+ ;; nothing found
+ (t 1)))
+
+ ;; And a string of the context to search for.
+ (string (progn
+ (beginning-of-line)
+ (re-search-forward " \\(\\([^ \t]*$\\)\\|\\($\\)\\)")
+ (TeX-match-buffer 1)))
+
+ ;; And we have now found to the end of the context.
+ (context (if context-available
+ (buffer-substring context-start (progn (forward-line 1)
+ (end-of-line)
+ (point)))
+ ;; There is no real context available, so we
+ ;; simply show the line with the error message.
+ (buffer-substring (1- (line-beginning-position))
+ context-start)))
+ ;; We may use these in another buffer.
+ (offset (or (car TeX-error-offset) 0))
+ (file (car TeX-error-file))
+ info-list)
+
+ ;; Remember where we was.
+ (setq TeX-error-point (point)
+ info-list (list 'error file line error offset context string nil nil
+ TeX-error-point nil))
+ (if store
+ ;; Store the error information.
+ (add-to-list 'TeX-error-list info-list t)
+ ;; Find the error point and display the help.
+ (apply #'TeX-find-display-help info-list))))
+
+(defun TeX-warning (warning warning-start bad-box &optional store)
+ "Display a warning for WARNING.
+
+WARNING-START is the position where WARNING starts. If BAD-BOX
+is non-nil, the warning refers to a bad-box, otherwise it is a
+generic warning.
+
+If optional argument STORE is non-nil, store the warning
+information in `TeX-error-list' instead of displaying the
+warning."
+
+ (let* ( ;; line-string: match 1 is beginning line, match 2 is end line
+ (line-string (if bad-box
+ "at lines? \\([0-9]*\\)\\(?:--\\([0-9]*\\)\\)?"
+ ;; Traditional messages say "on input line X",
+ ;; the LaTeX3 \msg_line_context:. just reads
+ ;; "on line X".
+ "on \\(?:input \\)?line \\([0-9]*\\)\\."))
+ ;; word-string: match 1 is the word
+ (word-string (if bad-box "[][\\W() ---]\\(\\w+\\)[][\\W() ---]*$"
+ ;; Match "ref" in both "Reference `ref' on page NN
+ ;; undefined" and "Citation 'ref' on page NN undefined".
+ "\\(?:`\\|'\\)\\([-a-zA-Z0-9:]+\\)'"))
+
+ ;; Get error-line (warning). Don't search before `warning-start' to
+ ;; avoid catching completely unrelated line numbers.
+ (line (when (save-excursion (re-search-backward line-string
+ warning-start t))
+ (string-to-number (TeX-match-buffer 1))))
+ ;; If this is a bad box and the warning ends with "...at lines MM--NN"
+ ;; we can use "NN" as `line-end', in any other case (including bad
+ ;; boxes ending with "...at line NN") just use `line'.
+ (line-end (if (and bad-box (match-beginning 2))
+ (string-to-number (TeX-match-buffer 2))
+ line))
+
+ ;; Find the context
+ (context-start (progn (cond
+ ((and bad-box (string-match "\\\\hbox" warning))
+ ;; Horizontal bad box
+ (end-of-line))
+ (bad-box
+ ;; Vertical bad box (by exclusion), don't move
+ ;; point. In the output buffer, unlike in the
+ ;; actual *.log file, these warnings do not end
+ ;; with "...is active []", but in the same line
+ ;; there may be something else, including a new
+ ;; file opened. Thus, point shouldn't move
+ ;; from the end of the actual bad box warning.
+ ;; This is why the corresponding regexp in
+ ;; `TeX-parse-error' doesn't match everything
+ ;; until the end of the line.
+ nil)
+ (t
+ ;; Generic warning.
+ (beginning-of-line)))
+ (point)))
+
+ (context (cond ((string-match LaTeX-warnings-regexp warning)
+ ;; The warnings matching `LaTeX-warnings-regexp' are
+ ;; emitted by \GenericWarning macro, or macros based on
+ ;; it (\ClassWarning, \PackageWarning, etc). After
+ ;; such warnings there is an empty line, just look for
+ ;; it to find the end.
+ (beginning-of-line)
+ (while (null (eolp))
+ (forward-line 1))
+ (buffer-substring context-start (progn (end-of-line)
+ (point))))
+
+ ((and bad-box (string-match "\\\\vbox" warning))
+ ;; Vertical bad boxes don't provide any additional
+ ;; information. In this case, reuse the `warning' as
+ ;; `context' and don't move point, so that we avoid
+ ;; eating the next line that may contain another
+ ;; warning. See also comment for `context-start'.
+ (concat "\n" warning))
+
+ (t
+ ;; Horizontal bad boxes.
+ (forward-line 1)
+ (end-of-line)
+ (while (equal (current-column) 79)
+ (forward-line 1)
+ (end-of-line))
+ (buffer-substring context-start (point)))))
+
+ ;; This is where we want to be.
+ (error-point (point))
+
+ ;; Now find the error word.
+ (string (when (save-excursion
+ (re-search-backward word-string context-start t))
+ (TeX-match-buffer 1)))
+
+ ;; We might use these in another file.
+ (offset (or (car TeX-error-offset) 0))
+ (file (car TeX-error-file))
+ info-list ignore)
+
+ ;; Second chance to get line number right. If `line' is nil, check whether
+ ;; the reference to the line number is in `context'. For example, this is
+ ;; the case for warnings emitted with \ClassWarning and \PackageWarning.
+ ;; XXX: maybe it suffices to evaluate `line' after `context' above, but I
+ ;; don't know if there are cases in which it's important to get `line'
+ ;; before `context'.
+ (and (null line)
+ (string-match line-string context)
+ (setq line-end
+ (setq line (and (match-beginning 1)
+ (string-to-number (match-string 1 context))))))
+
+ ;; This is where we start next time.
+ (goto-char error-point)
+ (setq TeX-error-point (point))
+
+ ;; Explanation of what follows: we add the warning to `TeX-error-list' even
+ ;; if it has to be ignored, with a flag specifying whether it is ignored.
+ ;; We do so in order to be able to change between "ignore" and "dont-ignore"
+ ;; behavior by just looking to the flag, without the need to reparse the
+ ;; output log.
+
+ ;; Store the list of information about the warning.
+ (setq info-list (list (if bad-box 'bad-box 'warning) file line warning
+ offset context string line-end bad-box
+ TeX-error-point)
+ ;; Decide whether it should be ignored.
+ ignore (and TeX-ignore-warnings
+ (cond
+ ((stringp TeX-ignore-warnings)
+ (string-match TeX-ignore-warnings warning))
+ ((fboundp TeX-ignore-warnings)
+ (apply TeX-ignore-warnings info-list))))
+ ;; Update `info-list'.
+ info-list (append info-list (list ignore)))
+
+ (if store
+ ;; Store the warning information.
+ (add-to-list 'TeX-error-list info-list t)
+ ;; Find the warning point and display the help.
+ (apply #'TeX-find-display-help info-list))))
+
+;;; Error Messages
+
+(defcustom TeX-error-description-list nil
+ "User defined help messages for errors in TeX run.
+See `TeX-error-description-list-local' for its format. All
+entries have higher priority than those in
+`TeX-error-description-list-local'.
+It must not have a fallback entry that matches any error."
+ :group 'TeX-output
+ :type '(repeat (cons :tag "Entry"
+ (regexp :tag "Match")
+ (string :format "Description:\n%v"))))
+
+(defvar TeX-error-description-list-local
+ '((".*" . "No help available"))
+ "Buffer local help messages for errors in TeX run.
+A list of the form (ERR-REGEXP . CONTEXT) used by function
+`TeX-help-error' to display help-text on an error message or warning.
+ERR-REGEXP should be a regular expression matching the error message
+given from TeX/LaTeX, and CONTEXT should be some lines describing that
+error.
+Major modes of AUCTeX can set its own catalogue as buffer local
+value of this variable, as LaTeX mode does.
+Style files of AUCTeX can also add their own entries to buffer local
+value of this variable to provide their own help messages.
+It must end with a fallback entry that matches any error, for example
+\(\".*\" . \"No help available\")")
+
+;;; - Help
+
+(defgroup TeX-error-description-faces nil
+ "Faces used in error descriptions."
+ :prefix "TeX-error-description-"
+ :group 'TeX-output)
+
+(defface TeX-error-description-error
+ ;; This is the same as `error' face in latest GNU Emacs versions.
+ '((((class color) (min-colors 88) (background light))
+ :foreground "Red1" :weight bold)
+ (((class color) (min-colors 88) (background dark))
+ :foreground "Pink" :weight bold)
+ (((class color) (min-colors 16) (background light))
+ :foreground "Red1" :weight bold)
+ (((class color) (min-colors 16) (background dark))
+ :foreground "Pink" :weight bold)
+ (((class color) (min-colors 8))
+ :foreground "red" :weight bold)
+ (t (:inverse-video t :weight bold)))
+ "Face for \"Error\" string in error descriptions.")
+
+(defface TeX-error-description-warning
+ ;; This is the same as `warning' face in latest GNU Emacs versions.
+ '((((class color) (min-colors 16)) :foreground "DarkOrange" :weight bold)
+ (((class color)) :foreground "yellow" :weight bold))
+ "Face for \"Warning\" string in error descriptions.")
+
+(defface TeX-error-description-tex-said
+ ;; This is the same as `font-lock-function-name-face' face in latest GNU
+ ;; Emacs versions.
+ '((((class color) (min-colors 88) (background light))
+ :foreground "Blue1")
+ (((class color) (min-colors 88) (background dark))
+ :foreground "LightSkyBlue")
+ (((class color) (min-colors 16) (background light))
+ :foreground "Blue")
+ (((class color) (min-colors 16) (background dark))
+ :foreground "LightSkyBlue")
+ (((class color) (min-colors 8))
+ :foreground "blue" :weight bold)
+ (t (:inverse-video t :weight bold)))
+ "Face for \"TeX said\" string in error descriptions.")
+
+(defface TeX-error-description-help
+ '((t (:inherit TeX-error-description-tex-said)))
+ "Face for \"Help\" string in error descriptions.")
+
+(defun TeX-help-error (error output runbuffer type)
+ "Print ERROR in context OUTPUT from RUNBUFFER in another window.
+TYPE is a symbol specifing if ERROR is a real error, a warning or
+a bad box."
+
+ (let ((old-buffer (current-buffer))
+ (log-file (with-current-buffer runbuffer
+ (with-current-buffer TeX-command-buffer
+ (expand-file-name (TeX-active-master "log")))))
+ (error-description-list
+ (append TeX-error-description-list
+ (buffer-local-value 'TeX-error-description-list-local
+ (buffer-local-value
+ 'TeX-command-buffer
+ runbuffer))))
+ (TeX-error-pointer 0))
+
+ ;; Find help text entry.
+ (while (not (string-match (car (nth TeX-error-pointer
+ error-description-list))
+ error))
+ (setq TeX-error-pointer (+ TeX-error-pointer 1)))
+
+ (TeX-pop-to-buffer (get-buffer-create "*TeX Help*") nil t)
+ (let ((inhibit-read-only t))
+ (erase-buffer)
+ (insert
+ (cond
+ ((equal type 'error)
+ (propertize "ERROR" 'font-lock-face 'TeX-error-description-error))
+ ((equal type 'warning)
+ (propertize "WARNING" 'font-lock-face 'TeX-error-description-warning))
+ ((equal type 'bad-box)
+ (propertize "BAD BOX" 'font-lock-face 'TeX-error-description-warning)))
+ ": " error
+ (propertize "\n\n--- TeX said ---" 'font-lock-face
+ 'TeX-error-description-tex-said)
+ output
+ (propertize "\n--- HELP ---\n" 'font-lock-face
+ 'TeX-error-description-help)
+ (let ((help (cdr (nth TeX-error-pointer
+ error-description-list))))
+ (save-excursion
+ (if (and (= (1+ TeX-error-pointer)
+ (length error-description-list))
+ (let* ((log-buffer (find-buffer-visiting log-file)))
+ (if log-buffer
+ (progn
+ (set-buffer log-buffer)
+ (revert-buffer t t))
+ (setq log-buffer
+ (find-file-noselect log-file))
+ (set-buffer log-buffer))
+ (auto-save-mode nil)
+ (setq buffer-read-only t)
+ (goto-char (point-min))
+ (search-forward error nil t 1))
+ (re-search-forward "^l\\." nil t)
+ (re-search-forward "^ [^\n]+$" nil t))
+ (let ((start (1+ (point))))
+ (forward-char 1)
+ (re-search-forward "^$")
+ (concat "From the .log file...\n\n"
+ (buffer-substring start (point))))
+ help)))))
+ (goto-char (point-min))
+ (TeX-special-mode)
+ (TeX-pop-to-buffer old-buffer nil t)))
+
+;;; Error Overview
+
+(defvar TeX-error-overview-active-buffer nil
+ "The active buffer for the current error overview.")
+
+(defvar TeX-error-overview-orig-frame nil
+ "Frame from which the error overview has been launched.")
+
+(defvar TeX-error-overview-orig-window nil
+ "Window from which the error overview has been launched.")
+
+(defcustom TeX-error-overview-setup nil
+ "The frame setup of the error overview.
+
+The possible value is: `separate-frame' (error oveview in a
+separate frame); with a nil value the current frame is used.
+
+If the display does not support multi frame, the current frame
+will be used regardless of the value of this variable."
+ :group 'TeX-output
+ :type '(choice
+ (const :tag "Error overview in separate frame" separate-frame)
+ (const :tag "Use current frame" nil)))
+
+(defun TeX-error-overview-setup ()
+ "Return the frame setup of the error overview for the current display."
+ (and (display-multi-frame-p) TeX-error-overview-setup))
+
+(defun TeX-error-overview-goto-source (&optional button)
+ "Go to the error point in the source.
+If optional argument BUTTON is non-nil, go to source associated
+to the selected error."
+ (interactive)
+ (let ((index (if button (button-get button 'id) (tabulated-list-get-id)))
+ item window)
+ (if index
+ (progn
+ ;; Select the source frame/window, if still live.
+ (if (TeX-error-overview-setup)
+ (if (frame-live-p TeX-error-overview-orig-frame)
+ (select-frame TeX-error-overview-orig-frame)
+ (error "You have deleted a vital frame---\
+please restart TeX error overview"))
+ (if (window-live-p TeX-error-overview-orig-window)
+ (select-window TeX-error-overview-orig-window)
+ (error "You have deleted a vital window---\
+please restart TeX error overview")))
+ ;; Get the error details.
+ (with-current-buffer TeX-error-overview-active-buffer
+ (setq item (nth index TeX-error-list)
+ TeX-error-last-visited index))
+ ;; Find the error and display the help.
+ (with-current-buffer TeX-command-buffer
+ ;; Find the error and display the help.
+ (apply #'TeX-find-display-help item))
+ ;; Return to the error overview.
+ (if (TeX-error-overview-setup)
+ (select-frame TeX-error-overview-frame)
+ (if (setq window
+ (get-buffer-window TeX-error-overview-buffer-name))
+ ;; If error overview window is visible just select it.
+ (select-window window)
+ ;; Otherwise, split the help window and display the error overview
+ ;; near to it. This should be the only reason for the error
+ ;; overview window not being still visible after the beginning of
+ ;; the function.
+ (select-window
+ (get-buffer-window (cond
+ ((eq TeX-display-help 'expert)
+ TeX-error-overview-active-buffer)
+ (TeX-display-help "*TeX Help*"))))
+ (if (window-splittable-p (selected-window) t)
+ (split-window-horizontally)
+ (split-window-vertically))
+ (switch-to-buffer TeX-error-overview-buffer-name))))
+ (message "No more errors.")
+ (beep))))
+
+(defun TeX-error-overview-make-entries (&optional master-dir active-buffer)
+ "Generate the list of errors to be printed using `tabulated-list-entries'.
+Write file names relative to MASTER-DIR when they are not absolute.
+
+ACTIVE-BUFFER is used as buffer from which to extract the list of
+errors. If nil, defaults to `TeX-error-overview-active-buffer'."
+ (with-current-buffer (or active-buffer TeX-error-overview-active-buffer)
+ (let ((id 0)
+ type file line msg entries)
+ (mapc
+ (lambda (entry)
+ (setq type (nth 0 entry)
+ file (nth 1 entry)
+ line (nth 2 entry)
+ msg (nth 3 entry))
+ ;; Add the entry only if it isn't to be skipped.
+ (unless (TeX-error-list-skip-warning-p type (nth 10 entry))
+ (push
+ (list
+ ;; ID.
+ id
+ (vector
+ ;; File.
+ (if (stringp file)
+ (if (file-name-absolute-p file)
+ file
+ (file-relative-name file master-dir))
+ "")
+ ;; Line.
+ (if (numberp line)
+ (number-to-string line)
+ "")
+ ;; Type.
+ (cond
+ ((equal type 'error)
+ (propertize "Error" 'font-lock-face 'TeX-error-description-error))
+ ((equal type 'warning)
+ (propertize "Warning" 'font-lock-face
+ 'TeX-error-description-warning))
+ ((equal type 'bad-box)
+ (propertize "Bad box" 'font-lock-face
+ 'TeX-error-description-warning))
+ (t
+ ""))
+ ;; Message.
+ (list (if (stringp msg)
+ ;; Sometimes, the message can be longer than one line,
+ ;; but print here only the first one.
+ (progn
+ (string-match "^.*" msg)
+ (match-string 0 msg))
+ "")
+ 'face 'link
+ 'follow-link t
+ 'id id
+ 'action #'TeX-error-overview-goto-source)))
+ entries))
+ ;; Increase the `id' counter in any case.
+ (setq id (1+ id)))
+ TeX-error-list)
+ (reverse entries))))
+
+(defun TeX-error-overview-next-error (&optional arg)
+ "Move to the next line and find the associated error.
+
+A prefix ARG specifies how many error messages to move; negative
+means move back to previous error messages."
+ (interactive "p")
+ (if (= (forward-line arg) 0)
+ (TeX-error-overview-goto-source)
+ ;; If there are lines left to move we are at the beginning or at the end of
+ ;; the buffer and there are no more errors.
+ (message "No more errors.")
+ (beep)))
+
+(defun TeX-error-overview-previous-error (&optional arg)
+ "Move to the previous line and find the associated error.
+
+Prefix ARG says how many error messages to move backward (or
+forward, if negative)."
+ (interactive "p")
+ (TeX-error-overview-next-error (- arg)))
+
+(defun TeX-error-overview-jump-to-source ()
+ "Display the help and move point to the error source."
+ (interactive)
+ (TeX-error-overview-goto-source)
+ (pop-to-buffer
+ (save-window-excursion
+ (select-window TeX-error-overview-orig-window)
+ (current-buffer))))
+
+(defun TeX-error-overview-goto-log ()
+ "Display the current error in log buffer."
+ (interactive)
+ (let ((TeX-display-help 'expert))
+ (TeX-error-overview-goto-source)))
+
+(defun TeX-error-overview-toggle-debug-bad-boxes ()
+ "Run `TeX-toggle-debug-bad-boxes' and update entries list."
+ (interactive)
+ (TeX-toggle-debug-bad-boxes)
+ (setq tabulated-list-entries
+ (TeX-error-overview-make-entries
+ (with-current-buffer TeX-command-buffer (TeX-master-directory))))
+ (tabulated-list-init-header)
+ (tabulated-list-print))
+
+(defun TeX-error-overview-toggle-debug-warnings ()
+ "Run `TeX-toggle-debug-warnings' and update entries list."
+ (interactive)
+ (TeX-toggle-debug-warnings)
+ (setq tabulated-list-entries
+ (TeX-error-overview-make-entries
+ (with-current-buffer TeX-command-buffer (TeX-master-directory))))
+ (tabulated-list-init-header)
+ (tabulated-list-print))
+
+(defun TeX-error-overview-toggle-suppress-ignored-warnings ()
+ "Toggle visibility of ignored warnings and update entries list."
+ (interactive)
+ (TeX-toggle-suppress-ignored-warnings)
+ (setq tabulated-list-entries
+ (TeX-error-overview-make-entries
+ (with-current-buffer TeX-command-buffer (TeX-master-directory))))
+ (tabulated-list-init-header)
+ (tabulated-list-print))
+
+(defun TeX-error-overview-quit ()
+ "Delete the window or the frame of the error overview."
+ (interactive)
+ (if (TeX-error-overview-setup)
+ (delete-frame TeX-error-overview-frame)
+ (delete-window))
+ (setq TeX-error-overview-orig-frame nil))
+
+(defvar TeX-error-overview-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "b" #'TeX-error-overview-toggle-debug-bad-boxes)
+ (define-key map "j" #'TeX-error-overview-jump-to-source)
+ (define-key map "l" #'TeX-error-overview-goto-log)
+ (define-key map "n" #'TeX-error-overview-next-error)
+ (define-key map "p" #'TeX-error-overview-previous-error)
+ (define-key map "q" #'TeX-error-overview-quit)
+ (define-key map "w" #'TeX-error-overview-toggle-debug-warnings)
+ (define-key map "x" #'TeX-error-overview-toggle-suppress-ignored-warnings)
+ (define-key map "\C-m" #'TeX-error-overview-goto-source)
+ map)
+ "Local keymap for `TeX-error-overview-mode' buffers.")
+
+(easy-menu-define TeX-error-overview-menu
+ TeX-error-overview-mode-map
+ "Menu used in TeX error overview mode."
+ '("TeX errors"
+ ["Next error" TeX-error-overview-next-error
+ :help "Jump to the next error"]
+ ["Previous error" TeX-error-overview-previous-error
+ :help "Jump to the previous error"]
+ ["Go to source" TeX-error-overview-goto-source
+ :help "Show the error in the source"]
+ ["Jump to source" TeX-error-overview-jump-to-source
+ :help "Move point to the error in the source"]
+ ["Go to log" TeX-error-overview-goto-log
+ :help "Show the error in the log buffer"]
+ "-"
+ ["Debug Bad Boxes" TeX-error-overview-toggle-debug-bad-boxes
+ :style toggle :selected TeX-debug-bad-boxes
+ :help "Show overfull and underfull boxes"]
+ ["Debug Warnings" TeX-error-overview-toggle-debug-warnings
+ :style toggle :selected TeX-debug-warnings
+ :help "Show warnings"]
+ ["Ignore Unimportant Warnings"
+ TeX-error-overview-toggle-suppress-ignored-warnings
+ :style toggle :selected TeX-suppress-ignored-warnings
+ :help "Hide specified warnings"]
+ "-"
+ ["Quit" TeX-error-overview-quit
+ :help "Quit"]))
+
+(defvar TeX-error-overview-list-entries nil
+ "List of errors to be used in the error overview.")
+
+(define-derived-mode TeX-error-overview-mode tabulated-list-mode
+ "TeX errors"
+ "Major mode for listing TeX errors."
+ (setq tabulated-list-format [("File" 25 nil)
+ ("Line" 4 nil :right-align t)
+ ("Type" 7 nil)
+ ("Message" 0 nil)]
+ tabulated-list-padding 1
+ tabulated-list-entries TeX-error-overview-list-entries)
+ (tabulated-list-init-header)
+ (tabulated-list-print))
+
+(defcustom TeX-error-overview-frame-parameters
+ '((name . "TeX errors")
+ (title . "TeX errors")
+ (height . 10)
+ (width . 80)
+ (top . (- 0))
+ (left . (- 0))
+ (unsplittable . t)
+ (minibuffer . nil)
+ (vertical-scroll-bars . t)
+ (tool-bar-lines . 0))
+ "Parameters of the error overview frame."
+ :group 'TeX-output
+ :type 'alist
+ :options '((name string) (title string) (height integer) (width integer)
+ (top integer) (left integer) (unsplittable boolean)
+ (minibuffer boolean) (vertical-scroll-bars boolean)
+ (tool-bar-lines integer)))
+
+(defcustom TeX-error-overview-open-after-TeX-run nil
+ "Whether to open automatically the error overview after running TeX."
+ :group 'TeX-output
+ :type 'boolean)
+
+(defun TeX-error-overview ()
+ "Show an overview of the errors occurred in the last TeX run."
+ (interactive)
+ ;; Check requirements before start.
+ (if (setq TeX-error-overview-active-buffer (TeX-active-buffer))
+ ;; `TeX-error-overview-list-entries' is going to be used only as value
+ ;; of `tabulated-list-entries' in `TeX-error-overview-mode'. In
+ ;; principle, we don't need `TeX-error-overview-list-entries', but
+ ;; `tabulated-list-entries' is buffer-local and we need the list of
+ ;; entries before creating the error overview buffer in order to
+ ;; decide whether we need to show anything.
+ (if (setq TeX-error-overview-list-entries
+ (TeX-error-overview-make-entries
+ (TeX-master-directory)))
+ (progn
+ (setq TeX-error-overview-orig-window (selected-window)
+ TeX-error-overview-orig-frame
+ (window-frame TeX-error-overview-orig-window))
+ ;; Create the error overview buffer. This is
+ ;; automatically killed before running TeX commands, so if
+ ;; exists it is up-to-date and doesn't need to be
+ ;; re-created.
+ (unless (get-buffer TeX-error-overview-buffer-name)
+ (with-current-buffer
+ (get-buffer-create TeX-error-overview-buffer-name)
+ (TeX-error-overview-mode)))
+ ;; Move point to the line associated to the last visited
+ ;; error.
+ (with-current-buffer TeX-error-overview-buffer-name
+ (goto-char (point-min))
+ (forward-line (with-current-buffer
+ TeX-error-overview-active-buffer
+ TeX-error-last-visited))
+ ;; Create a new frame for the error overview or display the
+ ;; buffer in the same frame, depending on the setup.
+ (if (TeX-error-overview-setup)
+ (if (frame-live-p TeX-error-overview-frame)
+ ;; Do not create a duplicate frame if there is
+ ;; already one, just select it.
+ (select-frame-set-input-focus
+ TeX-error-overview-frame)
+ ;; Create a new frame and store its name.
+ (select-frame
+ (setq TeX-error-overview-frame
+ (make-frame
+ TeX-error-overview-frame-parameters)))
+ (set-window-buffer (selected-window)
+ TeX-error-overview-buffer-name)
+ (set-window-dedicated-p (selected-window) t))
+ (TeX-pop-to-buffer TeX-error-overview-buffer-name))))
+ (error (concat "No error or warning to show"
+ ;; Suggest to display warnings and bad boxes with the
+ ;; appropriate key-bindings if there are such
+ ;; messages in the output buffer. Rationale of the
+ ;; test: `TeX-error-overview-list-entries' is nil,
+ ;; but if `TeX-error-list' is not nil it means that
+ ;; there are hidden warnings/bad boxes.
+ (when (TeX-process-get-variable (TeX-active-master)
+ 'TeX-error-list)
+ (format ". Type `%s' and `%s' to display \
+warnings and bad boxes"
+ (substitute-command-keys
+ "\\<TeX-mode-map>\\[TeX-toggle-debug-warnings]")
+ (substitute-command-keys
+ "\\<TeX-mode-map>\\[TeX-toggle-debug-bad-boxes]"))))))
+ (error "No process for this document")))
+
+;;; Output mode
+
+(define-derived-mode TeX-special-mode special-mode "TeX")
+
+(defvar TeX-output-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map TeX-special-mode-map)
+ (define-key map "n" #'TeX-next-error)
+ (define-key map "p" #'TeX-previous-error)
+ (define-key map "b" #'TeX-toggle-debug-bad-boxes)
+ (define-key map "w" #'TeX-toggle-debug-warnings)
+ (define-key map "i" (lambda ()
+ (interactive)
+ (with-current-buffer TeX-command-buffer
+ (TeX-interactive-mode (if TeX-interactive-mode -1 1)))))
+ (define-key map "s" (lambda ()
+ (interactive)
+ (with-current-buffer TeX-command-buffer
+ (TeX-source-correlate-mode (if TeX-source-correlate-mode -1 1)))))
+ map)
+ "Keymap for `TeX-output-mode'.")
+
+(define-derived-mode TeX-output-mode TeX-special-mode "TeX Output"
+ "Major mode for viewing TeX output.
+\\{TeX-output-mode-map} "
+ :syntax-table nil
+ (set (make-local-variable 'revert-buffer-function)
+ #'TeX-output-revert-buffer)
+ ;; special-mode makes it read-only which prevents input from TeX.
+ (setq buffer-read-only nil))
+
+(defun TeX-output-revert-buffer (_ignore-auto _noconfirm)
+ "Rerun the TeX command which of which this buffer was the output."
+ (goto-char (point-min))
+ (if (looking-at "Running `\\(.*\\)' on `\\(.*\\)' with ``\\(.*\\)''$")
+ (let ((name (match-string 1))
+ (file (match-string 2)))
+ (with-current-buffer TeX-command-buffer
+ (TeX-command name (if (string-match TeX-region file)
+ #'TeX-region-file
+ #'TeX-master-file))))
+ (error "Unable to find what command to run")))
+
+(provide 'tex)
+
+;; Local Variables:
+;; coding: utf-8
+;; End:
+
+;;; tex.el ends here