10228 lines
419 KiB
EmacsLisp
10228 lines
419 KiB
EmacsLisp
;;; 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
|