Fetching contributors…
Cannot retrieve contributors at this time
6364 lines (5817 sloc) 238 KB
;;; latex.el --- Support for LaTeX documents.
;; Copyright (C) 1991, 1993-2014 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 AUCTeX support for LaTeX.
;;; Code:
(require 'tex)
(require 'tex-style)
(eval-when-compile (require 'cl)) ;FIXME: Use cl-lib.
;;; Syntax
(defvar LaTeX-optop "["
"The LaTeX optional argument opening character.")
(defvar LaTeX-optcl "]"
"The LaTeX optional argument closeing character.")
;;; Style
(defcustom LaTeX-default-style "article"
"*Default when creating new documents."
:group 'LaTeX-environment
:type 'string)
(defcustom LaTeX-default-options nil
"Default options to documentclass.
A comma-seperated list of strings."
:group 'LaTeX-environment
:type '(repeat (string :format "%v")))
(make-variable-buffer-local 'LaTeX-default-options)
(defcustom LaTeX-insert-into-comments t
"*Whether insertion commands stay in comments.
This allows using the insertion commands even when
the lines are outcommented, like in dtx files."
:group 'LaTeX-environment
:type 'boolean)
(defun LaTeX-newline ()
"Start a new line potentially staying within comments.
This depends on `LaTeX-insert-into-comments'."
(if LaTeX-insert-into-comments
(cond ((and (save-excursion (skip-chars-backward " \t") (bolp))
(save-excursion
(skip-chars-forward " \t")
(looking-at (concat TeX-comment-start-regexp "+"))))
(beginning-of-line)
(insert (buffer-substring-no-properties
(line-beginning-position) (match-end 0)))
(newline))
((and (not (bolp))
(save-excursion
(skip-chars-forward " \t") (not (TeX-escaped-p)))
(looking-at
(concat "[ \t]*" TeX-comment-start-regexp "+[ \t]*")))
(delete-region (match-beginning 0) (match-end 0))
(indent-new-comment-line))
;; `indent-new-comment-line' does nothing when
;; `comment-auto-fill-only-comments' is non-il, so we must be sure
;; to be in a comment before calling it. In any other case
;; `newline' is used.
((TeX-in-comment)
(indent-new-comment-line))
(t
(newline)))
(newline)))
;;; Syntax Table
(defvar LaTeX-mode-syntax-table (copy-syntax-table TeX-mode-syntax-table)
"Syntax table used in LaTeX mode.")
(progn ; set [] to match for LaTeX.
(modify-syntax-entry (string-to-char LaTeX-optop)
(concat "(" LaTeX-optcl)
LaTeX-mode-syntax-table)
(modify-syntax-entry (string-to-char LaTeX-optcl)
(concat ")" LaTeX-optop)
LaTeX-mode-syntax-table))
;;; Sections
;; Declare dynamically scoped vars.
(defvar title)
(defvar name)
(defvar level)
(defvar done-mark)
(defvar toc)
(defun LaTeX-section (arg)
"Insert a template for a LaTeX section.
Determine the type of section to be inserted, by the argument ARG.
If ARG is nil or missing, use the current level.
If ARG is a list (selected by \\[universal-argument]), go downward one level.
If ARG is negative, go up that many levels.
If ARG is positive or zero, use absolute level:
0 : part
1 : chapter
2 : section
3 : subsection
4 : subsubsection
5 : paragraph
6 : subparagraph
The following variables can be set to customize:
`LaTeX-section-hook' Hooks to run when inserting a section.
`LaTeX-section-label' Prefix to all section labels."
(interactive "*P")
(let* ((val (prefix-numeric-value arg))
(level (cond ((null arg)
(LaTeX-current-section))
((listp arg)
(LaTeX-down-section))
((< val 0)
(LaTeX-up-section (- val)))
(t val)))
(name (LaTeX-section-name level))
(toc nil)
(title (if (TeX-active-mark)
(buffer-substring (region-beginning)
(region-end))
""))
(done-mark (make-marker)))
(run-hooks 'LaTeX-section-hook)
(LaTeX-newline)
(if (marker-position done-mark)
(goto-char (marker-position done-mark)))
(set-marker done-mark nil)))
(defun LaTeX-current-section ()
"Return the level of the section that contain point.
See also `LaTeX-section' for description of levels."
(save-excursion
(max (LaTeX-largest-level)
(if (re-search-backward (LaTeX-outline-regexp) nil t)
(- (LaTeX-outline-level) (LaTeX-outline-offset))
(LaTeX-largest-level)))))
(defun LaTeX-down-section ()
"Return the value of a section one level under the current.
Tries to find what kind of section that have been used earlier in the
text, if this fail, it will just return one less than the current
section."
(save-excursion
(let ((current (LaTeX-current-section))
(next nil)
(regexp (LaTeX-outline-regexp)))
(if (not (re-search-backward regexp nil t))
(1+ current)
(while (not next)
(cond
((eq (LaTeX-current-section) current)
(if (re-search-forward regexp nil t)
(if (<= (setq next (LaTeX-current-section)) current) ;Wow!
(setq next (1+ current)))
(setq next (1+ current))))
((not (re-search-backward regexp nil t))
(setq next (1+ current)))))
next))))
(defun LaTeX-up-section (arg)
"Return the value of the section ARG levels above this one."
(save-excursion
(if (zerop arg)
(LaTeX-current-section)
(let ((current (LaTeX-current-section)))
(while (and (>= (LaTeX-current-section) current)
(re-search-backward (LaTeX-outline-regexp)
nil t)))
(LaTeX-up-section (1- arg))))))
(defvar LaTeX-section-list '(("part" 0)
("chapter" 1)
("section" 2)
("subsection" 3)
("subsubsection" 4)
("paragraph" 5)
("subparagraph" 6))
"List which elements is the names of the sections used by LaTeX.")
(defun LaTeX-section-list-add-locally (sections &optional clean)
"Add SECTIONS to `LaTeX-section-list'.
SECTIONS can be a single list containing the section macro name
as a string and the the level as an integer or a list of such
lists.
If optional argument CLEAN is non-nil, remove any existing
entries from `LaTeX-section-list' before adding the new ones.
The function will make `LaTeX-section-list' buffer-local and
invalidate the section submenu in order to let the menu filter
regenerate it. It is mainly a convenience function which can be
used in style files."
(when (stringp (car sections))
(setq sections (list sections)))
(make-local-variable 'LaTeX-section-list)
(when clean (setq LaTeX-section-list nil))
(dolist (elt sections) (add-to-list 'LaTeX-section-list elt t))
(setq LaTeX-section-list
(sort (copy-sequence LaTeX-section-list)
(lambda (a b) (< (nth 1 a) (nth 1 b)))))
(setq LaTeX-section-menu nil))
(defun LaTeX-section-name (level)
"Return the name of the section corresponding to LEVEL."
(let ((entry (TeX-member level LaTeX-section-list
(lambda (a b) (equal a (nth 1 b))))))
(if entry
(nth 0 entry)
nil)))
(defun LaTeX-section-level (name)
"Return the level of the section NAME."
(let ((entry (TeX-member name LaTeX-section-list
(lambda (a b) (equal a (nth 0 b))))))
(if entry
(nth 1 entry)
nil)))
(defcustom TeX-outline-extra nil
"List of extra TeX outline levels.
Each element is a list with two entries. The first entry is the
regular expression matching a header, and the second is the level of
the header. See `LaTeX-section-list' for existing header levels."
:group 'LaTeX
:type '(repeat (group (regexp :tag "Match")
(integer :tag "Level"))))
(defun LaTeX-outline-regexp (&optional anywhere)
"Return regexp for LaTeX sections.
If optional argument ANYWHERE is not nil, do not require that the
header is at the start of a line."
(concat (if anywhere "" "^")
"[ \t]*"
(regexp-quote TeX-esc)
"\\(appendix\\|documentstyle\\|documentclass\\|"
(mapconcat 'car LaTeX-section-list "\\|")
"\\)\\b"
(if TeX-outline-extra
"\\|"
"")
(mapconcat 'car TeX-outline-extra "\\|")
"\\|" TeX-header-end
"\\|" TeX-trailer-start))
(defvar LaTeX-largest-level nil
"Largest sectioning level with current document class.")
(make-variable-buffer-local 'LaTeX-largest-level)
(defun LaTeX-largest-level ()
"Return largest sectioning level with current document class.
Run style hooks before it has not been done."
(TeX-update-style)
LaTeX-largest-level)
(defun LaTeX-largest-level-set (section)
"Set `LaTeX-largest-level' to the level of SECTION.
SECTION has to be a string contained in `LaTeX-section-list'.
Additionally the function will invalidate the section submenu in
order to let the menu filter regenerate it."
(setq LaTeX-largest-level (LaTeX-section-level section))
(let ((offset (LaTeX-outline-offset)))
(when (and (> offset 0)
;; XEmacs does not know `outline-heading-alist'.
(boundp 'outline-heading-alist))
(let (lst)
(dolist (tup outline-heading-alist)
(setq lst (cons (cons (car tup)
(+ offset (cdr tup)))
lst)))
(setq outline-heading-alist (nreverse lst)))))
(setq LaTeX-section-menu nil))
(defun LaTeX-outline-offset ()
"Offset to add to `LaTeX-section-list' levels to get outline level."
(- 2 (LaTeX-largest-level)))
(defun TeX-look-at (list)
"Check if we are looking at the first element of a member of LIST.
If so, return the second element, otherwise return nil."
(while (and list
(not (looking-at (nth 0 (car list)))))
(setq list (cdr list)))
(if list
(nth 1 (car list))
nil))
(defun LaTeX-outline-level ()
"Find the level of current outline heading in an LaTeX document."
(cond ((looking-at LaTeX-header-end) 1)
((looking-at LaTeX-trailer-start) 1)
((TeX-look-at TeX-outline-extra)
(max 1 (+ (TeX-look-at TeX-outline-extra)
(LaTeX-outline-offset))))
(t
(save-excursion
(skip-chars-forward " \t")
(forward-char 1)
(cond ((looking-at "appendix") 1)
((looking-at "documentstyle") 1)
((looking-at "documentclass") 1)
((TeX-look-at LaTeX-section-list)
(max 1 (+ (TeX-look-at LaTeX-section-list)
(LaTeX-outline-offset))))
(t (outline-level)))))))
(defun LaTeX-outline-name ()
"Guess a name for the current header line."
(save-excursion
(if (re-search-forward "{\\([^\}]*\\)}" (+ (point) fill-column 10) t)
(match-string 1)
(buffer-substring (point) (min (point-max) (+ 20 (point)))))))
(add-hook 'TeX-remove-style-hook
(lambda () (setq LaTeX-largest-level nil)))
(defcustom LaTeX-section-hook
'(LaTeX-section-heading
LaTeX-section-title
;; LaTeX-section-toc ; Most people won't want this
LaTeX-section-section
LaTeX-section-label)
"List of hooks to run when a new section is inserted.
The following variables are set before the hooks are run
level - numeric section level, see the documentation of `LaTeX-section'.
name - name of the sectioning command, derived from `level'.
title - The title of the section, default to an empty string.
toc - Entry for the table of contents list, default nil.
done-mark - Position of point afterwards, default nil (meaning end).
The following standard hook exist -
LaTeX-section-heading: Query the user about the name of the
sectioning command. Modifies `level' and `name'.
LaTeX-section-title: Query the user about the title of the
section. Modifies `title'.
LaTeX-section-toc: Query the user for the toc entry. Modifies
`toc'.
LaTeX-section-section: Insert LaTeX section command according to
`name', `title', and `toc'. If `toc' is nil, no toc entry is
inserted. If `toc' or `title' are empty strings, `done-mark' will be
placed at the point they should be inserted.
LaTeX-section-label: Insert a label after the section command.
Controled by the variable `LaTeX-section-label'.
To get a full featured `LaTeX-section' command, insert
(setq LaTeX-section-hook
'(LaTeX-section-heading
LaTeX-section-title
LaTeX-section-toc
LaTeX-section-section
LaTeX-section-label))
in your .emacs file."
:group 'LaTeX-macro
:type 'hook
:options '(LaTeX-section-heading
LaTeX-section-title
LaTeX-section-toc
LaTeX-section-section
LaTeX-section-label))
(defcustom LaTeX-section-label
'(("part" . "part:")
("chapter" . "chap:")
("section" . "sec:")
("subsection" . "sec:")
("subsubsection" . "sec:"))
"Default prefix when asking for a label.
Some LaTeX packages \(such as `fancyref'\) look at the prefix to generate some
text around cross-references automatically. When using those packages, you
should not change this variable.
If it is a string, it it used unchanged for all kinds of sections.
If it is nil, no label is inserted.
If it is a list, the list is searched for a member whose car is equal
to the name of the sectioning command being inserted. The cdr is then
used as the prefix. If the name is not found, or if the cdr is nil,
no label is inserted."
:group 'LaTeX-label
:type '(choice (const :tag "none" nil)
(string :format "%v" :tag "Common")
(repeat :menu-tag "Level specific"
:format "\n%v%i"
(cons :format "%v"
(string :tag "Type")
(choice :tag "Prefix"
(const :tag "none" nil)
(string :format "%v"))))))
;;; Section Hooks.
(defun LaTeX-section-heading ()
"Hook to prompt for LaTeX section name.
Insert this hook into `LaTeX-section-hook' to allow the user to change
the name of the sectioning command inserted with `\\[LaTeX-section]'."
(let ((string (completing-read
(concat "Level: (default " name ") ")
LaTeX-section-list
nil nil nil)))
; Update name
(if (not (zerop (length string)))
(setq name string))
; Update level
(setq level (LaTeX-section-level name))))
(defun LaTeX-section-title ()
"Hook to prompt for LaTeX section title.
Insert this hook into `LaTeX-section-hook' to allow the user to change
the title of the section inserted with `\\[LaTeX-section]."
(setq title (TeX-read-string "Title: " title))
(let ((region (and (TeX-active-mark)
(cons (region-beginning) (region-end)))))
(when region (delete-region (car region) (cdr region)))))
(defun LaTeX-section-toc ()
"Hook to prompt for the LaTeX section entry in the table of content .
Insert this hook into `LaTeX-section-hook' to allow the user to insert
a different entry for the section in the table of content."
(setq toc (TeX-read-string "Toc Entry: "))
(if (zerop (length toc))
(setq toc nil)))
(defun LaTeX-section-section ()
"Hook to insert LaTeX section command into the file.
Insert this hook into `LaTeX-section-hook' after those hooks that set
the `name', `title', and `toc' variables, but before those hooks that
assume that the section is already inserted."
;; insert a new line if the current line and the previous line are
;; not empty (except for whitespace), with one exception: do not
;; insert a new line if the previous (or current, sigh) line starts
;; an environment (i.e., starts with `[optional whitespace]\begin')
(unless (save-excursion
(re-search-backward
(concat "^\\s-*\n\\s-*\\=\\|^\\s-*" (regexp-quote TeX-esc)
"begin")
(line-beginning-position 0) t))
(LaTeX-newline))
(insert TeX-esc name)
(cond ((null toc))
((zerop (length toc))
(insert LaTeX-optop)
(set-marker done-mark (point))
(insert LaTeX-optcl))
(t
(insert LaTeX-optop toc LaTeX-optcl)))
(insert TeX-grop)
(if (zerop (length title))
(set-marker done-mark (point)))
(insert title TeX-grcl)
(LaTeX-newline)
;; If RefTeX is available, tell it that we've just made a new section
(and (fboundp 'reftex-notice-new-section)
(reftex-notice-new-section)))
(defun LaTeX-section-label ()
"Hook to insert a label after the sectioning command.
Insert this hook into `LaTeX-section-hook' to prompt for a label to be
inserted after the sectioning command.
The behaviour of this hook is controlled by variable `LaTeX-section-label'."
(and (LaTeX-label name 'section)
(LaTeX-newline)))
;;; Environments
(defgroup LaTeX-environment nil
"Environments in AUCTeX."
:group 'LaTeX-macro)
(defcustom LaTeX-default-environment "itemize"
"*The default environment when creating new ones with `LaTeX-environment'.
It is overridden by `LaTeX-default-document-environment' when it
is non-nil and the current environment is \"document\"."
:group 'LaTeX-environment
:type 'string)
(make-variable-buffer-local 'LaTeX-default-environment)
(defvar LaTeX-default-document-environment nil
"The default environment when creating new ones with
`LaTeX-environment' and the current one is \"document\". This
variable overrides `LaTeX-default-environment'.")
(make-variable-buffer-local 'LaTeX-default-document-environment)
(defvar LaTeX-default-tabular-environment "tabular"
"The default tabular-like environment used when inserting a table env.
Styles such as tabularx may set it according to their needs.")
(make-variable-buffer-local 'LaTeX-default-tabular-environment)
(defvar LaTeX-environment-history nil)
;; Variable used to cache the current environment, e.g. for repeated
;; tasks in an environment, like indenting each line in a paragraph to
;; be filled. It must not have a non-nil value in general. That
;; means it is usually let-bound for such operations.
(defvar LaTeX-current-environment nil)
(defun LaTeX-environment (arg)
"Make LaTeX environment (\\begin{...}-\\end{...} pair).
With optional ARG, modify current environment.
It may be customized with the following variables:
`LaTeX-default-environment' Your favorite environment.
`LaTeX-default-style' Your favorite document class.
`LaTeX-default-options' Your favorite document class options.
`LaTeX-float' Where you want figures and tables to float.
`LaTeX-table-label' Your prefix to labels in tables.
`LaTeX-figure-label' Your prefix to labels in figures.
`LaTeX-default-format' Format for array and tabular.
`LaTeX-default-width' Width for minipage and tabular*.
`LaTeX-default-position' Position for array and tabular."
(interactive "*P")
(let* ((default (cond
((TeX-near-bobp) "document")
((and LaTeX-default-document-environment
(string-equal (LaTeX-current-environment) "document"))
LaTeX-default-document-environment)
(t LaTeX-default-environment)))
(environment (completing-read (concat "Environment type: (default "
default ") ")
(LaTeX-environment-list-filtered) nil nil
nil 'LaTeX-environment-history default)))
;; Use `environment' as default for the next time only if it is different
;; from the current default.
(unless (equal environment default)
(setq LaTeX-default-environment environment))
(let ((entry (assoc environment (LaTeX-environment-list))))
(if (null entry)
(LaTeX-add-environments (list environment)))
(if arg
(LaTeX-modify-environment environment)
(LaTeX-environment-menu environment)))))
(defun LaTeX-environment-menu (environment)
"Insert ENVIRONMENT around point or region."
(let ((entry (assoc environment (LaTeX-environment-list))))
(cond ((not (and entry (nth 1 entry)))
(LaTeX-insert-environment environment))
((numberp (nth 1 entry))
(let ((count (nth 1 entry))
(args ""))
(while (> count 0)
(setq args (concat args TeX-grop TeX-grcl))
(setq count (- count 1)))
(LaTeX-insert-environment environment args)))
((or (stringp (nth 1 entry)) (vectorp (nth 1 entry)))
(let ((prompts (cdr entry))
(args ""))
(dolist (elt prompts)
(let* ((optional (vectorp elt))
(elt (if optional (elt elt 0) elt))
(arg (TeX-read-string (concat (when optional "(Optional) ")
elt ": "))))
(setq args (concat args
(cond ((and optional (> (length arg) 0))
(concat LaTeX-optop arg LaTeX-optcl))
((not optional)
(concat TeX-grop arg TeX-grcl)))))))
(LaTeX-insert-environment environment args)))
(t
(apply (nth 1 entry) environment (nthcdr 2 entry))))))
(defun LaTeX-close-environment (&optional reopen)
"Create an \\end{...} to match the current environment.
With prefix-argument, reopen environment afterwards."
(interactive "*P")
(if (> (point)
(save-excursion
(beginning-of-line)
(when LaTeX-insert-into-comments
(if (looking-at comment-start-skip)
(goto-char (match-end 0))))
(skip-chars-forward " \t")
(point)))
(LaTeX-newline))
(let ((environment (LaTeX-current-environment 1)) marker)
(insert "\\end{" environment "}")
(indent-according-to-mode)
(if (or (not (looking-at "[ \t]*$"))
(and (TeX-in-commented-line)
(save-excursion (beginning-of-line 2)
(not (TeX-in-commented-line)))))
(LaTeX-newline)
(unless (= (forward-line 1) 0)
(insert "\n")))
(indent-according-to-mode)
(when reopen
(save-excursion
(setq marker (point-marker))
(set-marker-insertion-type marker t)
(LaTeX-environment-menu environment)
(delete-region (point)
(if (save-excursion (goto-char marker)
(bolp))
(1- marker)
marker))
(move-marker marker nil)))))
(defvar LaTeX-after-insert-env-hooks nil
"List of functions to be run at the end of `LaTeX-insert-environment'.
Each function is called with three arguments: the name of the
environment just inserted, the buffer position just before
\\begin and the position just before \\end.")
(defun LaTeX-insert-environment (environment &optional extra)
"Insert LaTeX ENVIRONMENT with optional argument EXTRA."
(let ((active-mark (and (TeX-active-mark) (not (eq (mark) (point)))))
prefix content-start env-start env-end)
(when (and active-mark (< (mark) (point))) (exchange-point-and-mark))
;; Compute the prefix.
(when (and LaTeX-insert-into-comments (TeX-in-commented-line))
(save-excursion
(beginning-of-line)
(looking-at
(concat "^\\([ \t]*" TeX-comment-start-regexp "+\\)+[ \t]*"))
(setq prefix (match-string 0))))
;; What to do with the line containing point.
(cond ((save-excursion (beginning-of-line)
(looking-at (concat prefix "[ \t]*$")))
(delete-region (match-beginning 0) (match-end 0)))
((TeX-looking-at-backward (concat "^" prefix "[ \t]*")
(line-beginning-position))
(beginning-of-line)
(newline)
(beginning-of-line 0))
((bolp)
(delete-horizontal-space)
(newline)
(beginning-of-line 0))
(t
(delete-horizontal-space)
(newline 2)
(when prefix (insert prefix))
(beginning-of-line 0)))
;; What to do with the line containing mark.
(when active-mark
(save-excursion
(goto-char (mark))
(cond ((save-excursion (beginning-of-line)
(or (looking-at (concat prefix "[ \t]*$"))
(looking-at "[ \t]*$")))
(delete-region (match-beginning 0) (match-end 0)))
((TeX-looking-at-backward (concat "^" prefix "[ \t]*")
(line-beginning-position))
(beginning-of-line)
(newline)
(beginning-of-line 0))
(t
(delete-horizontal-space)
(insert-before-markers "\n")
(newline)
(when prefix (insert prefix))))))
;; Now insert the environment.
(when prefix (insert prefix))
(setq env-start (point))
(insert TeX-esc "begin" TeX-grop environment TeX-grcl)
(indent-according-to-mode)
(when extra (insert extra))
(setq content-start (line-beginning-position 2))
(unless active-mark
(newline)
(when prefix (insert prefix))
(newline))
(when active-mark (goto-char (mark)))
(when prefix (insert prefix))
(insert TeX-esc "end" TeX-grop environment TeX-grcl)
(end-of-line 0)
(if active-mark
(progn
(or (assoc environment LaTeX-indent-environment-list)
(LaTeX-fill-region content-start (line-beginning-position 2)))
(set-mark content-start))
(indent-according-to-mode))
(save-excursion (beginning-of-line 2) (indent-according-to-mode))
(TeX-math-input-method-off)
(setq env-end (save-excursion
(search-forward
(concat TeX-esc "end" TeX-grop
environment TeX-grcl))
(match-beginning 0)))
(run-hook-with-args 'LaTeX-after-insert-env-hooks
environment env-start env-end)))
(defun LaTeX-modify-environment (environment)
"Modify current ENVIRONMENT."
(save-excursion
(LaTeX-find-matching-end)
(re-search-backward (concat (regexp-quote TeX-esc)
"end"
(regexp-quote TeX-grop)
" *\\([a-zA-Z*]*\\)"
(regexp-quote TeX-grcl))
(save-excursion (beginning-of-line 1) (point)))
(replace-match (concat TeX-esc "end" TeX-grop environment TeX-grcl) t t)
(beginning-of-line 1)
(LaTeX-find-matching-begin)
(re-search-forward (concat (regexp-quote TeX-esc)
"begin"
(regexp-quote TeX-grop)
" *\\([a-zA-Z*]*\\)"
(regexp-quote TeX-grcl))
(save-excursion (end-of-line 1) (point)))
(replace-match (concat TeX-esc "begin" TeX-grop environment TeX-grcl) t t)))
(defun LaTeX-current-environment (&optional arg)
"Return the name (a string) of the enclosing LaTeX environment.
With optional ARG>=1, find that outer level.
If function is called inside a comment and
`LaTeX-syntactic-comments' is enabled, try to find the
environment in commented regions with the same comment prefix.
The functions `LaTeX-find-matching-begin' and `LaTeX-find-matching-end'
work analogously."
(setq arg (if arg (if (< arg 1) 1 arg) 1))
(let* ((in-comment (TeX-in-commented-line))
(comment-prefix (and in-comment (TeX-comment-prefix)))
(case-fold-search nil))
(save-excursion
(while (and (/= arg 0)
(re-search-backward
"\\\\\\(begin\\|end\\) *{ *\\([A-Za-z*]+\\) *}" nil t))
(when (or (and LaTeX-syntactic-comments
(eq in-comment (TeX-in-commented-line))
(or (not in-comment)
;; Consider only matching prefixes in the
;; commented case.
(string= comment-prefix (TeX-comment-prefix))))
(and (not LaTeX-syntactic-comments)
(not (TeX-in-commented-line))))
(setq arg (if (string= (match-string 1) "end") (1+ arg) (1- arg)))))
(if (/= arg 0)
"document"
(match-string-no-properties 2)))))
(defun docTeX-in-macrocode-p ()
"Determine if point is inside a macrocode environment."
(let ((case-fold-search nil))
(save-excursion
(re-search-backward
(concat "^% " (regexp-quote TeX-esc)
"\\(begin\\|end\\)[ \t]*{macrocode\\*?}") nil 'move)
(not (or (bobp)
(= (char-after (match-beginning 1)) ?e))))))
;;; Environment Hooks
(defvar LaTeX-document-style-hook nil
"List of hooks to run when inserting a document environment.
To insert a hook here, you must insert it in the appropiate style file.")
(defun LaTeX-env-document (&optional _ignore)
"Create new LaTeX document.
Also inserts a \\documentclass macro if there's none already and
prompts for the insertion of \\usepackage macros.
The compatibility argument IGNORE is ignored."
;; just assume a single valid \\documentclass, i.e., one not in a
;; commented line
(let ((found nil))
(save-excursion
(while (and (not found)
(re-search-backward
"\\\\documentclass\\(\\[[a-z0-9A-Z\-\_,]*\\]\\)?\\({[^}]+}\\)"
nil t))
(and (not (TeX-in-commented-line))
(setq found t))))
(when (not found)
(TeX-insert-macro "documentclass")
(LaTeX-newline)
(LaTeX-newline)
;; Add a newline only if some `\usepackage' has been inserted.
(if (LaTeX-insert-usepackages)
(LaTeX-newline))
(LaTeX-newline)
(end-of-line 0)))
(LaTeX-insert-environment "document")
(run-hooks 'LaTeX-document-style-hook)
(setq LaTeX-document-style-hook nil))
(defcustom LaTeX-float ""
"Default float position for figures and tables.
If nil, act like the empty string is given, but do not prompt.
\(The standard LaTeX classes use [tbp] as float position if the
optional argument is omitted.)"
:group 'LaTeX-environment
:type '(choice (const :tag "Do not prompt" nil)
(const :tag "Empty" "")
(string :format "%v")))
(make-variable-buffer-local 'LaTeX-float)
(defcustom LaTeX-top-caption-list nil
"*List of float environments with top caption."
:group 'LaTeX-environment
:type '(repeat (string :format "%v")))
(defgroup LaTeX-label nil
"Adding labels for LaTeX commands in AUCTeX."
:group 'LaTeX)
(defcustom LaTeX-label-function nil
"*A function inserting a label at point.
Sole argument of the function is the environment. The function has to return
the label inserted, or nil if no label was inserted."
:group 'LaTeX-label
:type 'function)
(defcustom LaTeX-figure-label "fig:"
"*Default prefix to figure labels."
:group 'LaTeX-label
:group 'LaTeX-environment
:type 'string)
(defcustom LaTeX-table-label "tab:"
"*Default prefix to table labels."
:group 'LaTeX-label
:group 'LaTeX-environment
:type 'string)
(defcustom LaTeX-default-format ""
"Default format for array and tabular environments."
:group 'LaTeX-environment
:type 'string)
(make-variable-buffer-local 'LaTeX-default-format)
(defcustom LaTeX-default-width "1.0\\linewidth"
"Default width for minipage and tabular* environments."
:group 'LaTeX-environment
:type 'string)
(make-variable-buffer-local 'LaTeX-default-width)
(defcustom LaTeX-default-position ""
"Default position for array and tabular environments.
If nil, act like the empty string is given, but do not prompt."
:group 'LaTeX-environment
:type '(choice (const :tag "Do not prompt" nil)
(const :tag "Empty" "")
string))
(make-variable-buffer-local 'LaTeX-default-position)
(defcustom LaTeX-equation-label "eq:"
"*Default prefix to equation labels."
:group 'LaTeX-label
:type 'string)
(defcustom LaTeX-eqnarray-label LaTeX-equation-label
"*Default prefix to eqnarray labels."
:group 'LaTeX-label
:type 'string)
(defun LaTeX-env-item (environment)
"Insert ENVIRONMENT and the first item."
(LaTeX-insert-environment environment)
(if (TeX-active-mark)
(progn
(LaTeX-find-matching-begin)
(end-of-line 1))
(end-of-line 0))
(delete-char 1)
(when (looking-at (concat "^[ \t]+$\\|"
"^[ \t]*" TeX-comment-start-regexp "+[ \t]*$"))
(delete-region (point) (line-end-position)))
(delete-horizontal-space)
;; Deactivate the mark here in order to prevent `TeX-parse-macro'
;; from swapping point and mark and the \item ending up right after
;; \begin{...}.
(TeX-deactivate-mark)
(LaTeX-insert-item)
;; The inserted \item may have outdented the first line to the
;; right. Fill it, if appropriate.
(when (and (not (looking-at "$"))
(not (assoc environment LaTeX-indent-environment-list))
(> (- (line-end-position) (line-beginning-position))
(current-fill-column)))
(LaTeX-fill-paragraph nil)))
(defcustom LaTeX-label-alist
'(("figure" . LaTeX-figure-label)
("table" . LaTeX-table-label)
("figure*" . LaTeX-figure-label)
("table*" . LaTeX-table-label)
("equation" . LaTeX-equation-label)
("eqnarray" . LaTeX-eqnarray-label))
"Lookup prefixes for labels.
An alist where the CAR is the environment name, and the CDR
either the prefix or a symbol referring to one.
If the name is not found, or if the CDR is nil, no label is
automatically inserted for that environment.
If you want to automatically insert a label for a environment but
with an empty prefix, use the empty string \"\" as the CDR of the
corresponding entry."
:group 'LaTeX-label
:type '(repeat (cons (string :tag "Environment")
(choice (string :tag "Label prefix")
(symbol :tag "Label prefix symbol")))))
(make-variable-buffer-local 'LaTeX-label-alist)
(defun LaTeX-label (name &optional type)
"Insert a label for NAME at point.
The optional TYPE argument can be either environment or section:
in the former case this function looks up `LaTeX-label-alist' to
choose which prefix to use for the label, in the latter case
`LaTeX-section-label' will be looked up instead. If TYPE is nil,
you will be always prompted for a label, with an empty default
prefix.
If `LaTeX-label-function' is a valid function, LaTeX label will
transfer the job to this function."
(let ((prefix (cond
((eq type 'environment)
(cdr (assoc name LaTeX-label-alist)))
((eq type 'section)
(if (assoc name LaTeX-section-list)
(if (stringp LaTeX-section-label)
LaTeX-section-label
(and (listp LaTeX-section-label)
(cdr (assoc name LaTeX-section-label))))
""))
((null type)
"")
(t
nil)))
label)
(when (symbolp prefix)
(setq prefix (symbol-value prefix)))
(when prefix
(if (and (boundp 'LaTeX-label-function)
LaTeX-label-function
(fboundp LaTeX-label-function))
(setq label (funcall LaTeX-label-function name))
;; Use completing-read as we do with `C-c C-m \label RET'
(setq label (completing-read
(TeX-argument-prompt t nil "What label")
(LaTeX-label-list) nil nil prefix))
;; No label or empty string entered?
(if (or (string= prefix label)
(string= "" label))
(setq label nil)
(insert TeX-esc "label" TeX-grop label TeX-grcl))
(if label
(progn
(LaTeX-add-labels label)
label)
nil)))))
(defun LaTeX-env-figure (environment)
"Create ENVIRONMENT with \\caption and \\label commands."
(let ((float (and LaTeX-float ; LaTeX-float can be nil, i.e.
; do not prompt
(TeX-read-string "(Optional) Float position: " LaTeX-float)))
(caption (TeX-read-string "Caption: "))
(center (y-or-n-p "Center? "))
(active-mark (and (TeX-active-mark)
(not (eq (mark) (point)))))
start-marker end-marker)
(when active-mark
(if (< (mark) (point))
(exchange-point-and-mark))
(setq start-marker (point-marker))
(set-marker-insertion-type start-marker t)
(setq end-marker (copy-marker (mark))))
(setq LaTeX-float float)
(LaTeX-insert-environment environment
(unless (zerop (length float))
(concat LaTeX-optop float
LaTeX-optcl)))
(when active-mark (goto-char start-marker))
(when center
(insert TeX-esc "centering")
(indent-according-to-mode)
(LaTeX-newline)
(indent-according-to-mode))
;; Insert caption and ask for a label, do nothing if user skips caption
(unless (zerop (length caption))
(if (member environment LaTeX-top-caption-list)
;; top caption
(progn
(insert TeX-esc "caption" TeX-grop caption TeX-grcl)
;; If `auto-fill-mode' is active, fill the caption.
(if auto-fill-function (LaTeX-fill-paragraph))
(LaTeX-newline)
(indent-according-to-mode)
;; ask for a label and insert a new line only if a label is
;; actually inserted
(when (LaTeX-label environment 'environment)
(LaTeX-newline)
(indent-according-to-mode)))
;; bottom caption (default)
(when active-mark (goto-char end-marker))
(save-excursion
(LaTeX-newline)
(indent-according-to-mode)
;; If there is an active region point is before the backslash of
;; "\end" macro, go one line upwards.
(when active-mark (forward-line -1) (indent-according-to-mode))
(insert TeX-esc "caption" TeX-grop caption TeX-grcl)
;; If `auto-fill-mode' is active, fill the caption.
(if auto-fill-function (LaTeX-fill-paragraph))
;; ask for a label and if necessary insert a new line between caption
;; and label
(when (save-excursion (LaTeX-label environment 'environment))
(LaTeX-newline)
(indent-according-to-mode)))
;; Insert an empty line between caption and marked region, if any.
(when active-mark (LaTeX-newline) (forward-line -1))
(indent-according-to-mode)))
(when (and (member environment '("table" "table*"))
;; Suppose an existing tabular environment should just
;; be wrapped into a table if there is an active region.
(not active-mark))
(LaTeX-environment-menu LaTeX-default-tabular-environment))))
(defun LaTeX-env-array (environment)
"Insert ENVIRONMENT with position and column specifications.
Just like array and tabular."
(let ((pos (and LaTeX-default-position ; LaTeX-default-position can
; be nil, i.e. do not prompt
(TeX-read-string "(Optional) Position: " LaTeX-default-position)))
(fmt (TeX-read-string "Format: " LaTeX-default-format)))
(setq LaTeX-default-position pos)
(setq LaTeX-default-format fmt)
(LaTeX-insert-environment environment
(concat
(unless (zerop (length pos))
(concat LaTeX-optop pos LaTeX-optcl))
(concat TeX-grop fmt TeX-grcl)))
(LaTeX-item-array t)))
(defun LaTeX-env-label (environment)
"Insert ENVIRONMENT and prompt for label."
(LaTeX-insert-environment environment)
(when (LaTeX-label environment 'environment)
(LaTeX-newline)
(indent-according-to-mode)))
(defun LaTeX-env-list (environment)
"Insert ENVIRONMENT and the first item."
(let ((label (TeX-read-string "Default Label: ")))
(LaTeX-insert-environment environment
(format "{%s}{}" label))
(end-of-line 0)
(delete-char 1)
(delete-horizontal-space))
(LaTeX-insert-item))
(defun LaTeX-env-minipage (environment)
"Create new LaTeX minipage or minipage-like ENVIRONMENT."
(let ((pos (and LaTeX-default-position ; LaTeX-default-position can
; be nil, i.e. do not prompt
(TeX-read-string "(Optional) Position: " LaTeX-default-position)))
(width (TeX-read-string "Width: " LaTeX-default-width)))
(setq LaTeX-default-position pos)
(setq LaTeX-default-width width)
(LaTeX-insert-environment environment
(concat
(unless (zerop (length pos))
(concat LaTeX-optop pos LaTeX-optcl))
(concat TeX-grop width TeX-grcl)))))
(defun LaTeX-env-tabular* (environment)
"Insert ENVIRONMENT with width, position and column specifications."
(let ((width (TeX-read-string "Width: " LaTeX-default-width))
(pos (and LaTeX-default-position ; LaTeX-default-position can
; be nil, i.e. do not prompt
(TeX-read-string "(Optional) Position: " LaTeX-default-position)))
(fmt (TeX-read-string "Format: " LaTeX-default-format)))
(setq LaTeX-default-width width)
(setq LaTeX-default-position pos)
(setq LaTeX-default-format fmt)
(LaTeX-insert-environment environment
(concat
(concat TeX-grop width TeX-grcl) ;; not optional!
(unless (zerop (length pos))
(concat LaTeX-optop pos LaTeX-optcl))
(concat TeX-grop fmt TeX-grcl)))
(LaTeX-item-tabular* t)))
(defun LaTeX-env-picture (environment)
"Insert ENVIRONMENT with width, height specifications."
(let ((width (TeX-read-string "Width: "))
(height (TeX-read-string "Height: "))
(x-offset (TeX-read-string "X Offset: "))
(y-offset (TeX-read-string "Y Offset: ")))
(if (zerop (length x-offset))
(setq x-offset "0"))
(if (zerop (length y-offset))
(setq y-offset "0"))
(LaTeX-insert-environment environment
(concat
(format "(%s,%s)" width height)
(if (not (and (string= x-offset "0")
(string= y-offset "0")))
(format "(%s,%s)" x-offset y-offset))))))
(defun LaTeX-env-bib (environment)
"Insert ENVIRONMENT with label for bibitem."
(LaTeX-insert-environment environment
(concat TeX-grop
(TeX-read-string "Label for BibItem: " "99")
TeX-grcl))
(end-of-line 0)
(delete-char 1)
(delete-horizontal-space)
(LaTeX-insert-item))
(defun LaTeX-env-contents (environment)
"Insert ENVIRONMENT with filename for contents."
(save-excursion
(when (re-search-backward LaTeX-header-end nil t)
(error "Put %s environment before \\begin{document}" environment)))
(LaTeX-insert-environment environment
(concat TeX-grop
(TeX-read-string "File: ")
TeX-grcl))
(delete-horizontal-space))
(defun LaTeX-env-args (environment &rest args)
"Insert ENVIRONMENT and arguments defined by ARGS."
(LaTeX-insert-environment environment)
(save-excursion
(LaTeX-find-matching-begin)
(end-of-line)
(TeX-parse-arguments args)))
;;; Item hooks
(defvar LaTeX-item-list nil
"A list of environments where items have a special syntax.
The cdr is the name of the function, used to insert this kind of items.")
(defun LaTeX-insert-item ()
"Insert a new item in an environment.
You may use `LaTeX-item-list' to change the routines used to insert the item."
(interactive "*")
(let ((environment (LaTeX-current-environment)))
(when (and (TeX-active-mark)
(> (point) (mark)))
(exchange-point-and-mark))
(unless (bolp) (LaTeX-newline))
(if (assoc environment LaTeX-item-list)
(funcall (cdr (assoc environment LaTeX-item-list)))
(TeX-insert-macro "item"))
(indent-according-to-mode)))
(defvar TeX-arg-item-label-p)
(defun LaTeX-item-argument ()
"Insert a new item with an optional argument."
(let ((TeX-arg-item-label-p t))
(TeX-insert-macro "item")))
(defun LaTeX-item-bib ()
"Insert a new bibitem."
(TeX-insert-macro "bibitem"))
(defvar LaTeX-array-skipping-regexp (regexp-opt '("[t]" "[b]" ""))
"Regexp matching between \\begin{xxx} and column specification.
For array and tabular environments. See `LaTeX-insert-ampersands' for
detail.")
(defvar LaTeX-tabular*-skipping-regexp
;; Assume width specification contains neither nested curly brace
;; pair nor escaped "}".
(concat "{[^}]*}[ \t]*" (regexp-opt '("[t]" "[b]" "")))
"Regexp matching between \\begin{tabular*} and column specification.
For tabular* environment only. See `LaTeX-insert-ampersands' for detail.")
(defun LaTeX-item-array (&optional suppress)
"Insert line break macro on the last line and suitable number of &'s.
For array and tabular environments.
If SUPPRESS is non-nil, do not insert line break macro."
(unless suppress
(save-excursion
(end-of-line 0)
(just-one-space)
(TeX-insert-macro "\\")))
(LaTeX-insert-ampersands
LaTeX-array-skipping-regexp 'LaTeX-array-count-columns))
(defun LaTeX-item-tabular* (&optional suppress)
"Insert line break macro on the last line and suitable number of &'s.
For tabular* environment only.
If SUPPRESS is non-nil, do not insert line break macro."
(unless suppress
(save-excursion
(end-of-line 0)
(just-one-space)
(TeX-insert-macro "\\")))
(LaTeX-insert-ampersands
LaTeX-tabular*-skipping-regexp 'LaTeX-array-count-columns))
(defun LaTeX-insert-ampersands (regexp func)
"Insert suitable number of ampersands for the current environment.
The number is calculated from REGEXP and FUNC.
Example 1:
Consider the case that the current environment begins with
\\begin{array}[t]{|lcr|}
. REGEXP must be chosen to match \"[t]\", i.e., the text between just
after \"\\begin{array}\" and just before \"{|lcr|}\", which encloses
the column specification. FUNC must return the number of ampersands to
be inserted, which is 2 since this example specifies three columns.
FUNC is called with two arguments START and END, which spans the column
specification (without enclosing braces.) REGEXP is used to determine
these START and END.
Example 2:
This time the environment begins with
\\begin{tabular*}{1.0\\linewidth}[b]{c@{,}p{5ex}}
. REGEXP must match \"{1.0\\linewidth}[b]\" and FUNC must return 1 from
the text \"c@{,}p{5ex}\" between START and END specified two columns.
FUNC should return nil if it cannot determine the number of ampersands."
(let* ((cur (point))
(num
(save-excursion
(ignore-errors
(LaTeX-find-matching-begin)
;; Skip over "\begin{xxx}" and possible whitespaces.
(forward-list 1)
(skip-chars-forward " \t")
;; Skip over the text specified by REGEXP and whitespaces.
(when (let ((case-fold-search nil))
(re-search-forward regexp cur))
(skip-chars-forward " \t")
(when (eq (following-char) ?{)
;; We have reached the target "{yyy}" part.
(forward-char 1)
;; The next line doesn't move point, so point
;; is left just after the opening brace.
(let ((pos (TeX-find-closing-brace)))
(if pos
;; Calculate number of ampersands to be inserted.
(funcall func (point) (1- pos))))))))))
(if (natnump num)
(save-excursion (insert (make-string num ?&))))))
(defvar LaTeX-array-column-letters "clrp"
"Column letters for array-like environments.
See `LaTeX-array-count-columns' for detail.")
(defun LaTeX-array-count-columns (start end)
"Count number of ampersands to be inserted.
The columns are specified by the letters found in the string
`LaTeX-array-column-letters' and the number of those letters within the
text between START and END is basically considered to be the number of
columns. The arguments surrounded between braces such as p{30pt} do not
interfere the count of columns.
Return one less number than the columns, or nil on failing to count the
right number."
(save-excursion
(let (p (cols 0))
(goto-char start)
(while (< (setq p (point)) end)
;; The below block accounts for one unit of move for
;; one column.
(setq cols (+ cols (skip-chars-forward
LaTeX-array-column-letters end)))
(skip-chars-forward (concat
"^" LaTeX-array-column-letters
TeX-grop) end)
(if (eq (following-char) ?{) (forward-list 1))
;; Not sure whether this is really necessary or not, but
;; prepare for possible infinite loop anyway.
(when (eq p (point))
(setq cols nil)
(goto-char end)))
;; The number of ampersands is one less than column.
(if cols (1- cols)))))
;;; Parser
(defvar LaTeX-auto-style nil)
(defvar LaTeX-auto-arguments nil)
(defvar LaTeX-auto-optional nil)
(defvar LaTeX-auto-env-args nil)
(TeX-auto-add-type "label" "LaTeX")
(TeX-auto-add-type "bibitem" "LaTeX")
(TeX-auto-add-type "environment" "LaTeX")
(TeX-auto-add-type "bibliography" "LaTeX" "bibliographies")
(TeX-auto-add-type "index-entry" "LaTeX" "index-entries")
(TeX-auto-add-type "pagestyle" "LaTeX")
(TeX-auto-add-type "counter" "LaTeX")
(TeX-auto-add-type "length" "LaTeX")
(TeX-auto-add-type "savebox" "LaTeX" "saveboxes")
(defvar LaTeX-auto-minimal-regexp-list
'(("\\\\document\\(style\\|class\\)\
\\(\\[\\(\\([^#\\%]\\|%[^\n\r]*[\n\r]\\)*\\)\\]\\)?\
{\\([^#\\.\n\r]+?\\)}"
(3 5 1) LaTeX-auto-style)
("\\\\use\\(package\\)\\(\\[\\([^\]\\]*\\)\\]\\)?\
{\\(\\([^#}\\.%]\\|%[^\n\r]*[\n\r]\\)+?\\)}"
(3 4 1) LaTeX-auto-style))
"Minimal list of regular expressions matching LaTeX macro definitions.")
(defvar LaTeX-auto-label-regexp-list
'(("\\\\label{\\([^\n\r%\\{}]+\\)}" 1 LaTeX-auto-label))
"List of regular expression matching LaTeX labels only.")
(defvar LaTeX-auto-index-regexp-list
'(("\\\\\\(index\\|glossary\\){\\([^}{]*\\({[^}{]*\\({[^}{]*\\({[^}{]*}[^}{]*\\)*}[^}{]*\\)*}[^}{]*\\)*\\)}"
2 LaTeX-auto-index-entry))
"List of regular expression matching LaTeX index/glossary entries only.
Regexp allows for up to 3 levels of parenthesis inside the index argument.
This is necessary since index entries may contain commands and stuff.")
(defvar LaTeX-auto-class-regexp-list
'(;; \RequirePackage[<options>]{<package>}[<date>]
("\\\\Require\\(Package\\)\\(\\[\\([^#\\.%]*?\\)\\]\\)?\
{\\([^#\\.\n\r]+?\\)}"
(3 4 1) LaTeX-auto-style)
;; \RequirePackageWithOptions{<package>}[<date>],
("\\\\Require\\(Package\\)WithOptions\\(\\){\\([^#\\.\n\r]+?\\)}"
(2 3 1) LaTeX-auto-style)
;; \LoadClass[<options>]{<package>}[<date>]
("\\\\Load\\(Class\\)\\(\\[\\([^#\\.%]*?\\)\\]\\)?{\\([^#\\.\n\r]+?\\)}"
(3 4 1) LaTeX-auto-style)
;; \LoadClassWithOptions{<package>}[<date>]
("\\\\Load\\(Class\\)WithOptions\\(\\){\\([^#\\.\n\r]+?\\)}"
(2 3 1) LaTeX-auto-style)
;; \DeclareRobustCommand{<cmd>}[<num>][<default>]{<definition>},
;; \DeclareRobustCommand*{<cmd>}[<num>][<default>]{<definition>}
("\\\\DeclareRobustCommand\\*?{?\\\\\\([A-Za-z]+\\)}?\
\\[\\([0-9]+\\)\\]\\[\\([^\n\r]*?\\)\\]"
(1 2 3) LaTeX-auto-optional)
("\\\\DeclareRobustCommand\\*?{?\\\\\\([A-Za-z]+\\)}?\\[\\([0-9]+\\)\\]"
(1 2) LaTeX-auto-arguments)
("\\\\DeclareRobustCommand\\*?{?\\\\\\([A-Za-z]+\\)}?"
1 TeX-auto-symbol)
;; Patterns for commands described in "LaTeX2e font selection" (fntguide)
("\\\\DeclareMath\\(?:Symbol\\|Delimiter\\|Accent\\|Radical\\)\
{?\\\\\\([A-Za-z]+\\)}?"
1 TeX-auto-symbol)
("\\\\\\(Declare\\|Provide\\)Text\
\\(?:Command\\|Symbol\\|Accent\\|Composite\\){?\\\\\\([A-Za-z]+\\)}?"
1 TeX-auto-symbol)
("\\\\Declare\\(?:Text\\|Old\\)FontCommand{?\\\\\\([A-Za-z]+\\)}?"
1 TeX-auto-symbol))
"List of regular expressions matching macros in LaTeX classes and packages.")
(defvar LaTeX-auto-pagestyle-regexp-list
'(("\\\\ps@\\([A-Za-z]+\\)" 1 LaTeX-auto-pagestyle))
"List of regular expressions matching LaTeX pagestyles only.")
(defvar LaTeX-auto-counter-regexp-list
'(("\\\\newcounter *{\\([A-Za-z]+\\)}" 1 LaTeX-auto-counter)
("\\\\@definecounter{\\([A-Za-z]+\\)}" 1 LaTeX-auto-counter))
"List of regular expressions matching LaTeX counters only.")
(defvar LaTeX-auto-length-regexp-list
'(("\\\\newlength *{?\\\\\\([A-Za-z]+\\)}?" 1 LaTeX-auto-length))
"List of regular expressions matching LaTeX lengths only.")
(defvar LaTeX-auto-savebox-regexp-list
'(("\\\\newsavebox *{?\\\\\\([A-Za-z]+\\)}?" 1 LaTeX-auto-savebox))
"List of regular expressions matching LaTeX saveboxes only.")
(defvar LaTeX-auto-regexp-list
(append
(let ((token TeX-token-char))
`((,(concat "\\\\\\(?:new\\|provide\\)command\\*?{?\\\\\\(" token "+\\)}?\\[\\([0-9]+\\)\\]\\[\\([^\n\r]*\\)\\]")
(1 2 3) LaTeX-auto-optional)
(,(concat "\\\\\\(?:new\\|provide\\)command\\*?{?\\\\\\(" token "+\\)}?\\[\\([0-9]+\\)\\]")
(1 2) LaTeX-auto-arguments)
(,(concat "\\\\\\(?:new\\|provide\\)command\\*?{?\\\\\\(" token "+\\)}?")
1 TeX-auto-symbol)
(,(concat "\\\\newenvironment\\*?{?\\(" token "+\\)}?\\[\\([0-9]+\\)\\]\\[")
1 LaTeX-auto-environment)
(,(concat "\\\\newenvironment\\*?{?\\(" token "+\\)}?\\[\\([0-9]+\\)\\]")
(1 2) LaTeX-auto-env-args)
(,(concat "\\\\newenvironment\\*?{?\\(" token "+\\)}?")
1 LaTeX-auto-environment)
(,(concat "\\\\newtheorem{\\(" token "+\\)}") 1 LaTeX-auto-environment)
("\\\\input{\\(\\.*[^#}%\\\\\\.\n\r]+\\)\\(\\.[^#}%\\\\\\.\n\r]+\\)?}"
1 TeX-auto-file)
("\\\\include{\\(\\.*[^#}%\\\\\\.\n\r]+\\)\\(\\.[^#}%\\\\\\.\n\r]+\\)?}"
1 TeX-auto-file)
(, (concat "\\\\bibitem{\\(" token "[^, \n\r\t%\"#'()={}]*\\)}")
1 LaTeX-auto-bibitem)
(, (concat "\\\\bibitem\\[[^][\n\r]+\\]{\\(" token "[^, \n\r\t%\"#'()={}]*\\)}")
1 LaTeX-auto-bibitem)
("\\\\bibliography{\\([^#}\\\\\n\r]+\\)}" 1 LaTeX-auto-bibliography)
("\\\\addbibresource\\(?:\\[[^]]+\\]\\)?{\\([^#}\\\\\n\r\.]+\\)\\..+}"
1 LaTeX-auto-bibliography)
("\\\\add\\(?:global\\|section\\)bib\\(?:\\[[^]]+\\]\\)?{\\([^#}\\\\\n\r\.]+\\)\\(?:\\..+\\)?}" 1 LaTeX-auto-bibliography)
("\\\\newrefsection\\[\\([^]]+\\)\\]" 1 LaTeX-split-bibs)
("\\\\begin{refsection}\\[\\([^]]+\\)\\]" 1 LaTeX-split-bibs)))
LaTeX-auto-class-regexp-list
LaTeX-auto-label-regexp-list
LaTeX-auto-index-regexp-list
LaTeX-auto-minimal-regexp-list
LaTeX-auto-pagestyle-regexp-list
LaTeX-auto-counter-regexp-list
LaTeX-auto-length-regexp-list
LaTeX-auto-savebox-regexp-list)
"List of regular expression matching common LaTeX macro definitions.")
(defun LaTeX-split-bibs (match)
"Extract bibliography resources from MATCH.
Split the string at commas and remove Biber file extensions."
(let ((bibs (TeX-split-string " *, *" (TeX-match-buffer match))))
(dolist (bib bibs)
(LaTeX-add-bibliographies (replace-regexp-in-string
(concat "\\(?:\\."
(mapconcat 'regexp-quote
TeX-Biber-file-extensions
"\\|\\.")
"\\)")
"" bib)))))
(defun LaTeX-auto-prepare ()
"Prepare for LaTeX parsing."
(setq LaTeX-auto-arguments nil
LaTeX-auto-optional nil
LaTeX-auto-env-args nil
LaTeX-auto-style nil
LaTeX-auto-end-symbol nil))
(add-hook 'TeX-auto-prepare-hook 'LaTeX-auto-prepare)
(defun LaTeX-listify-package-options (options)
"Return a list from a comma-separated string of package OPTIONS.
The input string may include LaTeX comments and newlines."
;; We jump through all those hoops and don't just use `split-string'
;; or the like in order to be able to deal with key=value package
;; options which can look like this: "pdftitle={A Perfect Day},
;; colorlinks=false"
(let (opts match start)
(with-temp-buffer
(set-syntax-table LaTeX-mode-syntax-table)
(insert options)
(newline) ; So that the last entry can be found.
(goto-char (point-min))
(setq start (point))
(while (re-search-forward "[{ ,%\n\r]" nil t)
(setq match (match-string 0))
(cond
;; Step over groups. (Let's hope nobody uses escaped braces.)
((string= match "{")
(up-list))
;; Get rid of whitespace.
((string= match " ")
(delete-region (1- (point))
(save-excursion
(skip-chars-forward " ")
(point))))
;; Add entry to output.
((or (string= match ",") (= (point) (point-max)))
(let ((entry (buffer-substring-no-properties
start (1- (point)))))
(unless (member entry opts)
(setq opts (append opts (list entry)))))
(setq start (point)))
;; Get rid of comments.
((string= match "%")
(delete-region (1- (point))
(line-beginning-position 2)))
;; Get rid of newlines.
((or (string= match "\n") (string= match "\r"))
(delete-char -1)))))
opts))
(defvar LaTeX-provided-class-options nil
"Alist of options provided to LaTeX classes.
For each element, the CAR is the name of the class, the CDR is
the list of options provided to it.
E.g., its value will be
\(\(\"book\" \"a4paper\" \"11pt\" \"openany\" \"fleqn\"\)
...\)
See also `LaTeX-provided-package-options'.")
(make-variable-buffer-local 'LaTeX-provided-class-options)
(defun LaTeX-provided-class-options-member (class option)
"Return non-nil if OPTION has been given to CLASS at load time.
The value is actually the tail of the list of options given to CLASS."
(member option (cdr (assoc class LaTeX-provided-class-options))))
(defvar LaTeX-provided-package-options nil
"Alist of options provided to LaTeX packages.
For each element, the CAR is the name of the package, the CDR is
the list of options provided to it.
E.g., its value will be
\(\(\"babel\" \"german\"\)
\(\"geometry\" \"a4paper\" \"top=2cm\" \"bottom=2cm\" \"left=2.5cm\" \"right=2.5cm\"\)
...\)
See also `LaTeX-provided-class-options'.")
(make-variable-buffer-local 'LaTeX-provided-package-options)
(defun LaTeX-provided-package-options-member (package option)
"Return non-nil if OPTION has been given to PACKAGE at load time.
The value is actually the tail of the list of options given to PACKAGE."
(member option (cdr (assoc package LaTeX-provided-package-options))))
(defun LaTeX-auto-cleanup ()
"Cleanup after LaTeX parsing."
;; Cleanup BibTeX/Biber files
(setq LaTeX-auto-bibliography
(apply 'append (mapcar (lambda (arg)
(TeX-split-string "," arg))
LaTeX-auto-bibliography)))
;; Reset class and packages options for the current buffer
(setq LaTeX-provided-class-options nil)
(setq LaTeX-provided-package-options nil)
;; Cleanup document classes and packages
(unless (null LaTeX-auto-style)
(while LaTeX-auto-style
(let* ((entry (car LaTeX-auto-style))
(options (nth 0 entry))
(style (nth 1 entry))
(class (nth 2 entry)))
;; Next document style.
(setq LaTeX-auto-style (cdr LaTeX-auto-style))
;; Get the options.
(setq options (LaTeX-listify-package-options options))
;; Treat documentclass/documentstyle specially.
(if (or (string-equal "package" class)
(string-equal "Package" class))
(dolist (elt (TeX-split-string
"\\([ \t\r\n]\\|%[^\n\r]*[\n\r]\\|,\\)+" style))
;; Append style to the style list.
(add-to-list 'TeX-auto-file elt t)
;; Append to `LaTeX-provided-package-options' the name of the
;; package and the options provided to it at load time.
(unless (equal options '(""))
(TeX-add-to-alist 'LaTeX-provided-package-options
(list (cons elt options)))))
;; And a special "art10" style file combining style and size.
(add-to-list 'TeX-auto-file style t)
(add-to-list 'TeX-auto-file
(concat
(cond ((string-equal "article" style)
"art")
((string-equal "book" style)
"bk")
((string-equal "report" style)
"rep")
((string-equal "jarticle" style)
"jart")
((string-equal "jbook" style)
"jbk")
((string-equal "jreport" style)
"jrep")
((string-equal "j-article" style)
"j-art")
((string-equal "j-book" style)
"j-bk")
((string-equal "j-report" style )
"j-rep")
(t style))
(cond ((member "11pt" options)
"11")
((member "12pt" options)
"12")
(t
"10"))) t)
(unless (equal options '(""))
(TeX-add-to-alist 'LaTeX-provided-class-options
(list (cons style options)))))
;; The third argument if "class" indicates LaTeX2e features.
(cond ((equal class "class")
(add-to-list 'TeX-auto-file "latex2e"))
((equal class "style")
(add-to-list 'TeX-auto-file "latex2"))))))
;; Cleanup optional arguments
(mapc (lambda (entry)
(add-to-list 'TeX-auto-symbol
(list (nth 0 entry)
(string-to-number (nth 1 entry)))))
LaTeX-auto-arguments)
;; Cleanup default optional arguments
(mapc (lambda (entry)
(add-to-list 'TeX-auto-symbol
(list (nth 0 entry)
(vector "argument")
(1- (string-to-number (nth 1 entry))))))
LaTeX-auto-optional)
;; Cleanup environments arguments
(mapc (lambda (entry)
(add-to-list 'LaTeX-auto-environment
(list (nth 0 entry)
(string-to-number (nth 1 entry)))))
LaTeX-auto-env-args)
;; Cleanup use of def to add environments
;; NOTE: This uses an O(N^2) algorithm, while an O(N log N)
;; algorithm is possible.
(mapc (lambda (symbol)
(if (not (TeX-member symbol TeX-auto-symbol 'equal))
;; No matching symbol, insert in list
(add-to-list 'TeX-auto-symbol (concat "end" symbol))
;; Matching symbol found, remove from list
(if (equal (car TeX-auto-symbol) symbol)
;; Is it the first symbol?
(setq TeX-auto-symbol (cdr TeX-auto-symbol))
;; Nope! Travel the list
(let ((list TeX-auto-symbol))
(while (consp (cdr list))
;; Until we find it.
(if (equal (car (cdr list)) symbol)
;; Then remove it.
(setcdr list (cdr (cdr list))))
(setq list (cdr list)))))
;; and add the symbol as an environment.
(add-to-list 'LaTeX-auto-environment symbol)))
LaTeX-auto-end-symbol))
(add-hook 'TeX-auto-cleanup-hook 'LaTeX-auto-cleanup)
(defadvice LaTeX-add-bibliographies (after run-bib-style-hooks (&rest bibliographies) activate)
"Add BIBLIOGRAPHIES to the list of known bibliographies and style files."
(apply 'TeX-run-style-hooks bibliographies))
;;; Biber support
(defvar LaTeX-using-Biber nil
"Used to track whether Biber is in use.")
(make-variable-buffer-local 'LaTeX-using-Biber)
;;; BibTeX
;;;###autoload
(defun BibTeX-auto-store ()
"This function should be called from `bibtex-mode-hook'.
It will setup BibTeX to store keys in an auto file."
;; We want this to be early in the list, so we do not
;; add it before we enter BibTeX mode the first time.
(if (boundp 'local-write-file-hooks)
(add-hook 'local-write-file-hooks 'TeX-safe-auto-write)
(add-hook 'write-file-hooks 'TeX-safe-auto-write))
(set (make-local-variable 'TeX-auto-update) 'BibTeX)
(set (make-local-variable 'TeX-auto-untabify) nil)
(set (make-local-variable 'TeX-auto-parse-length) 999999)
(set (make-local-variable 'TeX-auto-regexp-list) BibTeX-auto-regexp-list)
(set (make-local-variable 'TeX-master) t))
(defvar BibTeX-auto-regexp-list
'(("@[Ss][Tt][Rr][Ii][Nn][Gg]" 1 ignore)
("@[a-zA-Z]+[{(][ \t]*\\([^, \n\r\t%\"#'()={}]*\\)" 1 LaTeX-auto-bibitem))
"List of regexp-list expressions matching BibTeX items.")
;;; Macro Argument Hooks
(defun TeX-arg-conditional (optional expr then else)
"Implement if EXPR THEN ELSE.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one.
If EXPR evaluate to true, parse THEN as an argument list, else parse
ELSE as an argument list."
(TeX-parse-arguments (if (eval expr) then else)))
(defun TeX-arg-eval (optional &rest args)
"Evaluate ARGS and insert value in buffer.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one."
(TeX-argument-insert (eval args) optional))
(defun TeX-arg-label (optional &optional prompt definition)
"Prompt for a label completing with known labels.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string. If DEFINITION is non-nil, add the chosen label to the
list of defined labels."
(let ((label (completing-read (TeX-argument-prompt optional prompt "Key")
(LaTeX-label-list))))
(if (and definition (not (string-equal "" label)))
(LaTeX-add-labels label))
(TeX-argument-insert label optional optional)))
(defvar reftex-ref-macro-prompt)
(defun TeX-arg-ref (optional &optional prompt definition)
"Let-bind `reftex-ref-macro-prompt' to nil and pass arguments
to `TeX-arg-label'.
See the documentation of `TeX-arg-label' for details on the
arguments: OPTIONAL, PROMPT, and DEFINITION."
(let ((reftex-ref-macro-prompt nil))
(TeX-arg-label optional prompt definition)))
(defun TeX-arg-index-tag (optional &optional prompt &rest _args)
"Prompt for an index tag.
This is the name of an index, not the entry.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string. ARGS is unused."
(TeX-argument-insert
(TeX-read-string (TeX-argument-prompt optional prompt "Index tag")) optional))
(defun TeX-arg-index (optional &optional prompt &rest args)
"Prompt for an index entry completing with known entries.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string. ARGS is unused."
(let ((entry (completing-read (TeX-argument-prompt optional prompt "Key")
(LaTeX-index-entry-list))))
(if (and (not (string-equal "" entry))
(not (member (list entry) (LaTeX-index-entry-list))))
(LaTeX-add-index-entries entry))
(TeX-argument-insert entry optional optional)))
(defalias 'TeX-arg-define-index 'TeX-arg-index)
(defun TeX-arg-macro (optional &optional prompt definition)
"Prompt for a TeX macro with completion.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string. If DEFINITION is non-nil, add the chosen macro to the
list of defined macros."
(let ((macro (completing-read (TeX-argument-prompt optional prompt
(concat "Macro: "
TeX-esc)
t)
(TeX-symbol-list))))
(if (and definition (not (string-equal "" macro)))
(TeX-add-symbols macro))
(TeX-argument-insert macro optional TeX-esc)))
(defun TeX-arg-environment (optional &optional prompt definition)
"Prompt for a LaTeX environment with completion.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string. If DEFINITION is non-nil, add the chosen environment to
the list of defined environments."
(let ((environment (completing-read (TeX-argument-prompt optional prompt
"Environment")
(LaTeX-environment-list))))
(if (and definition (not (string-equal "" environment)))
(LaTeX-add-environments environment))
(TeX-argument-insert environment optional)))
;; Why is DEFINITION unused?
(defun TeX-arg-cite (optional &optional prompt definition)
"Prompt for a BibTeX citation with completion.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string. DEFINITION is unused."
(let ((items (multi-prompt "," t (TeX-argument-prompt optional prompt "Key")
(LaTeX-bibitem-list))))
(apply 'LaTeX-add-bibitems items)
(TeX-argument-insert (mapconcat 'identity items ",") optional optional)))
(defun TeX-arg-counter (optional &optional prompt definition)
"Prompt for a LaTeX counter.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string. If DEFINITION is non-nil, add the chosen counter to
the list of defined counters."
(let ((counter (completing-read (TeX-argument-prompt optional prompt
"Counter")
(LaTeX-counter-list))))
(if (and definition (not (string-equal "" counter)))
(LaTeX-add-counters counter))
(TeX-argument-insert counter optional)))
(defun TeX-arg-savebox (optional &optional prompt definition)
"Prompt for a LaTeX savebox.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string. If definition is non-nil, the savebox is added to the
list of defined saveboxes."
(let ((savebox (completing-read (TeX-argument-prompt optional prompt
(concat "Savebox: "
TeX-esc) t)
(LaTeX-savebox-list))))
(if (and definition (not (zerop (length savebox))))
(LaTeX-add-saveboxes savebox))
(TeX-argument-insert savebox optional TeX-esc)))
(defun TeX-arg-length (optional &optional prompt initial-input definition)
"Prompt for a LaTeX length.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string. If INITIAL-INPUT is non-nil, insert it in the minibuffer
initially, with point positioned at the end. If DEFINITION is
non-nil, the length is added to the list of defined length."
(let ((length (completing-read (TeX-argument-prompt optional prompt "Length")
;; A valid length can be a macro or a length of
;; the form <value><dimension>. Input starting
;; with a `\' can be completed with length
;; macros.
(mapcar (lambda(elt) (concat TeX-esc (car elt)))
(LaTeX-length-list))
;; Some macros takes as argument only a length
;; macro (e.g., `\setlength' in its first
;; argument, and `\newlength'), in this case is
;; convenient to set `\\' as initial input.
nil nil initial-input)))
(if (and definition (not (zerop (length length))))
;; Strip leading TeX-esc from macro name
(LaTeX-add-lengths (substring length 1)))
(TeX-argument-insert length optional)))
(defun TeX-arg-file (optional &optional prompt)
"Prompt for a filename in the current directory.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(TeX-argument-insert (read-file-name (TeX-argument-prompt optional
prompt "File")
"" "" nil)
optional))
(defun TeX-arg-file-name (optional &optional prompt)
"Prompt for a file name.
Initial input is the name of the file being visited in the
current buffer, with extension. If OPTIONAL is non-nil, insert
it as an optional argument. Use PROMPT as the prompt string."
(TeX-argument-insert
(TeX-read-string
(TeX-argument-prompt optional prompt "Name")
(file-name-nondirectory buffer-file-name))
optional))
(defun TeX-arg-file-name-sans-extension (optional &optional prompt)
"Prompt for a file name.
Initial input is the name of the file being visited in the
current buffer, without extension. If OPTIONAL is non-nil,
insert it as an optional argument. Use PROMPT as the prompt
string."
(TeX-argument-insert
(TeX-read-string
(TeX-argument-prompt optional prompt "Name")
(file-name-sans-extension (file-name-nondirectory buffer-file-name)))
optional))
(defun TeX-arg-define-label (optional &optional prompt)
"Prompt for a label completing with known labels.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(TeX-arg-label optional prompt t))
(defun TeX-arg-define-macro (optional &optional prompt)
"Prompt for a TeX macro with completion.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(TeX-arg-macro optional prompt t))
(defun TeX-arg-define-environment (optional &optional prompt)
"Prompt for a LaTeX environment with completion.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(TeX-arg-environment optional prompt t))
(defun TeX-arg-define-cite (optional &optional prompt)
"Prompt for a BibTeX citation.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(TeX-arg-cite optional prompt t))
(defun TeX-arg-define-counter (optional &optional prompt)
"Prompt for a LaTeX counter.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(TeX-arg-counter optional prompt t))
(defun TeX-arg-define-savebox (optional &optional prompt)
"Prompt for a LaTeX savebox.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(TeX-arg-savebox optional prompt t))
(defun TeX-arg-define-length (optional &optional prompt)
"Prompt for a LaTeX length.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(TeX-arg-length optional prompt "\\" t))
(defcustom LaTeX-style-list '(("amsart")
("amsbook")
("article")
("beamer")
("book")
("dinbrief")
("foils")
("letter")
("memoir")
("minimal")
("prosper")
("report")
("scrartcl")
("scrbook")
("scrlttr2")
("scrreprt")
("slides"))
"List of document classes offered when inserting a document environment.
If `TeX-arg-input-file-search' is set to `t', you will get
completion with all LaTeX classes available in your distribution
and this variable will be ignored."
:group 'LaTeX-environment
:type '(repeat (group (string :format "%v"))))
(defvar LaTeX-global-class-files nil
"List of the LaTeX class files.
Initialized once at the first time you prompt for a LaTeX class.
May be reset with `\\[universal-argument] \\[TeX-normal-mode]'.")
(defvar TeX-after-document-hook nil
"List of functions to be run at the end of `TeX-arg-document'.
To insert a hook here, you must insert it in the appropiate style file.")
(defun TeX-arg-document (optional &optional _ignore)
"Insert arguments to documentclass.
OPTIONAL and IGNORE are ignored."
(let* ((TeX-file-extensions '("cls"))
(crm-separator ",")
style var options)
(unless LaTeX-global-class-files
(if (if (eq TeX-arg-input-file-search 'ask)
(not (y-or-n-p "Find class yourself? "))
TeX-arg-input-file-search)
(progn
(message "Searching for LaTeX classes...")
(setq LaTeX-global-class-files
(mapcar 'identity (TeX-search-files-by-type 'texinputs 'global t t))))
LaTeX-style-list))
(setq style (completing-read
(concat "Document class: (default " LaTeX-default-style ") ")
LaTeX-global-class-files nil nil nil nil LaTeX-default-style))
;; Clean up hook before use.
(setq TeX-after-document-hook nil)
(TeX-run-style-hooks style)
(setq var (intern (format "LaTeX-%s-class-options" style)))
(if (or (and (boundp var)
(listp (symbol-value var)))
(fboundp var))
(if (functionp var)
(setq options (funcall var))
(when (symbol-value var)
(setq options
(mapconcat 'identity
(TeX-completing-read-multiple
"Options: " (mapcar 'list (symbol-value var)) nil nil
(if (stringp LaTeX-default-options)
LaTeX-default-options
(mapconcat 'identity LaTeX-default-options ",")))
","))))
(setq options (TeX-read-string "Options: ")))
(unless (zerop (length options))
(insert LaTeX-optop options LaTeX-optcl)
(let ((opts (LaTeX-listify-package-options options)))
(TeX-add-to-alist 'LaTeX-provided-class-options
(list (cons style opts)))))
(insert TeX-grop style TeX-grcl))
;; remove old information
(TeX-remove-style)
;; defined in individual style hooks
(TeX-update-style)
(run-hooks 'TeX-after-document-hook))
(defvar LaTeX-after-usepackage-hook nil
"List of functions to be run at the end of `LaTeX-arg-usepackage'.
To insert a hook here, you must insert it in the appropiate style file.")
(defun LaTeX-arg-usepackage-read-packages-with-options ()
"Read the packages and the options for the usepackage macro.
If at least one package is provided, this function returns a cons
cell, whose CAR is the list of packages and the CDR is the string
of the options, nil otherwise."
(let* ((TeX-file-extensions '("sty"))
(crm-separator ",")
packages var options)
(unless TeX-global-input-files
(if (if (eq TeX-arg-input-file-search 'ask)
(not (y-or-n-p "Find packages yourself? "))
TeX-arg-input-file-search)
(progn
(message "Searching for LaTeX packages...")
(setq TeX-global-input-files
(mapcar 'list (TeX-search-files-by-type
'texinputs 'global t t))))))
(setq packages (TeX-completing-read-multiple
"Packages: " TeX-global-input-files))
;; Clean up hook before use in `LaTeX-arg-usepackage-insert'.
(setq LaTeX-after-usepackage-hook nil)
(mapc 'TeX-run-style-hooks packages)
;; Prompt for options only if at least one package has been supplied, return
;; nil otherwise.
(when packages
(setq var (if (= 1 (length packages))
(intern (format "LaTeX-%s-package-options" (car packages)))
;; Something like `\usepackage[options]{pkg1,pkg2,pkg3,...}' is
;; allowed (provided that pkg1, pkg2, pkg3, ... accept same
;; options). When there is more than one package, set `var' to
;; a dummy value so next `if' enters else form.
t))
(if (or (and (boundp var)
(listp (symbol-value var)))
(fboundp var))
(if (functionp var)
(setq options (funcall var))
(when (symbol-value var)
(setq options
(mapconcat 'identity
(TeX-completing-read-multiple
"Options: " (mapcar 'list (symbol-value var)))
","))))
(setq options (TeX-read-string "Options: ")))
(cons packages options))))
(defun LaTeX-arg-usepackage-insert (packages options)
"Actually insert arguments to usepackage."
(unless (zerop (length options))
(let ((opts (LaTeX-listify-package-options options)))
(mapc (lambda (elt)
(TeX-add-to-alist 'LaTeX-provided-package-options
(list (cons elt opts))))
packages))
(insert LaTeX-optop options LaTeX-optcl))
(insert TeX-grop (mapconcat 'identity packages ",") TeX-grcl)
(run-hooks 'LaTeX-after-usepackage-hook))
(defun LaTeX-arg-usepackage (_optional)
"Insert arguments to usepackage.
OPTIONAL is ignored."
(let* ((packages-options (LaTeX-arg-usepackage-read-packages-with-options))
(packages (car packages-options))
(options (cdr packages-options)))
(LaTeX-arg-usepackage-insert packages options)))
(defun LaTeX-insert-usepackages ()
"Prompt for the insertion of usepackage macros until empty
input is reached.
Return t if at least one \\usepackage has been inserted, nil
otherwise."
(let (packages-options packages options (inserted nil))
(while (setq packages-options
(LaTeX-arg-usepackage-read-packages-with-options))
(setq packages (car packages-options))
(setq options (cdr packages-options))
(insert TeX-esc "usepackage")
(LaTeX-arg-usepackage-insert packages options)
(LaTeX-newline)
(setq inserted t))
inserted))
(defcustom LaTeX-search-files-type-alist
'((texinputs "${TEXINPUTS.latex}" ("tex/generic/" "tex/latex/")
TeX-file-extensions)
(docs "${TEXDOCS}" ("doc/") TeX-doc-extensions)
(graphics "${TEXINPUTS}" ("tex/") LaTeX-includegraphics-extensions)
(bibinputs "${BIBINPUTS}" ("bibtex/bib/") BibTeX-file-extensions)
(bstinputs "${BSTINPUTS}" ("bibtex/bst/") BibTeX-style-extensions)
(bbxinputs "" ("tex/latex/") BibLaTeX-style-extensions)
(biberinputs "${BIBINPUTS}" ("bibtex/bib/") TeX-Biber-file-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.
Reset the mode for a change of this variable to take effect."
:group 'TeX-file
:type '(alist :key-type symbol
:value-type
(group (string :tag "Kpathsea variable")
(choice :tag "Directories"
(repeat :tag "TDS subdirectories" string)
(repeat :tag "Absolute directories" directory)
(repeat :tag "Variables" variable))
(choice :tag "Extensions"
variable (repeat string)))))
(defcustom TeX-arg-input-file-search t
"If `TeX-arg-input-file' should search for files.
If the value is t, files in TeX's search path are searched for
and provided for completion. The file name is then inserted
without directory and extension. If the value is nil, the file
name can be specified manually and is inserted with a path
relative to the directory of the current buffer's file and with
extension. If the value is `ask', you are asked for the method
to use every time `TeX-arg-input-file' is called."
:group 'LaTeX-macro
:type '(choice (const t) (const nil) (const ask)))
(defvar TeX-global-input-files nil
"List of the non-local TeX input files.
Initialized once at the first time you prompt for an input file.
May be reset with `\\[universal-argument] \\[TeX-normal-mode]'.")
(defun TeX-arg-input-file (optional &optional prompt local)
"Prompt for a tex or sty file.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. PROMPT is the prompt,
LOCAL is a flag. If the flag is set, only complete with local
files."
(let ((search (if (eq TeX-arg-input-file-search 'ask)
(not (y-or-n-p "Find file yourself? "))
TeX-arg-input-file-search))
file style)
(if search
(progn
(unless (or TeX-global-input-files local)
(message "Searching for files...")
(setq TeX-global-input-files
(mapcar 'list (TeX-search-files-by-type
'texinputs 'global t t))))
(setq file (completing-read
(TeX-argument-prompt optional prompt "File")
(TeX-delete-dups-by-car
(append (mapcar 'list (TeX-search-files-by-type
'texinputs 'local t t))
(unless local
TeX-global-input-files))))
style file))
(setq file (read-file-name
(TeX-argument-prompt optional prompt "File") nil ""))
(unless (string-equal file "")
(setq file (file-relative-name file)))
(setq style (file-name-sans-extension (file-name-nondirectory file))))
(unless (string-equal "" style)
(TeX-run-style-hooks style))
(TeX-argument-insert file optional)))
(defvar BibTeX-global-style-files nil
"Association list of BibTeX style files.
Initialized once at the first time you prompt for an input file.
May be reset with `\\[universal-argument] \\[TeX-normal-mode]'.")
(defvar BibLaTeX-global-style-files nil
"Association list of BibLaTeX style files.
Initialized once at the first time you prompt for a BibLaTeX
style. May be reset with `\\[universal-argument] \\[TeX-normal-mode]'.")
(defun TeX-arg-bibstyle (optional &optional prompt)
"Prompt for a BibTeX style file.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(message "Searching for BibTeX styles...")
(or BibTeX-global-style-files
(setq BibTeX-global-style-files
(mapcar 'list (TeX-search-files-by-type 'bstinputs 'global t t))))
(TeX-argument-insert
(completing-read (TeX-argument-prompt optional prompt "BibTeX style")
(append (mapcar 'list (TeX-search-files-by-type
'bstinputs 'local t t))
BibTeX-global-style-files))
optional))
(defvar BibTeX-global-files nil
"Association list of BibTeX files.
Initialized once at the first time you prompt for a BibTeX file.
May be reset with `\\[universal-argument] \\[TeX-normal-mode]'.")
(defvar TeX-Biber-global-files nil
"Association list of Biber files.
Initialized once at the first time you prompt for an Biber file.
May be reset with `\\[universal-argument] \\[TeX-normal-mode]'.")
(defun TeX-arg-bibliography (optional &optional prompt)
"Prompt for a BibTeX database file.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(message "Searching for BibTeX files...")
(or BibTeX-global-files
(setq BibTeX-global-files
(mapcar 'list (TeX-search-files-by-type 'bibinputs 'global t t))))
(let ((styles (multi-prompt
"," t
(TeX-argument-prompt optional prompt "BibTeX files")
(append (mapcar 'list (TeX-search-files-by-type
'bibinputs 'local t t))
BibTeX-global-files))))
(apply 'LaTeX-add-bibliographies styles)
;; Run style files associated to the bibliography database files in order to
;; immediately fill `LaTeX-bibitem-list'.
(mapc 'TeX-run-style-hooks styles)
(TeX-argument-insert (mapconcat 'identity styles ",") optional)))
(defun TeX-arg-corner (optional &optional prompt)
"Prompt for a LaTeX side or corner position with completion.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(TeX-argument-insert
(completing-read (TeX-argument-prompt optional prompt "Position")
'(("") ("l") ("r") ("t") ("b") ("tl") ("tr") ("bl") ("br"))
nil t)
optional))
(defun TeX-arg-lr (optional &optional prompt)
"Prompt for a LaTeX side with completion.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(TeX-argument-insert
(completing-read (TeX-argument-prompt optional prompt "Position")
'(("") ("l") ("r"))
nil t)
optional))
(defun TeX-arg-tb (optional &optional prompt)
"Prompt for a LaTeX side with completion.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(TeX-argument-insert
(completing-read (TeX-argument-prompt optional prompt "Position")
'(("") ("t") ("b"))
nil t)
optional))
(defcustom TeX-date-format "%Y/%m/%d"
"The default date format prompted by `TeX-arg-date'."
:group 'LaTeX-macro
:type 'string)
(defun TeX-arg-date (optional &optional prompt)
"Prompt for a date, defaulting to the current date.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(let ((default (format-time-string TeX-date-format (current-time))))
(TeX-argument-insert
(TeX-read-string (TeX-argument-prompt
optional prompt (format "Date (default %s)" default))
nil nil default)
optional)))
(defun TeX-arg-version (optional &optional prompt)
"Prompt for the version of a file.
Use as initial input the current date. If OPTIONAL is non-nil,
insert the resulting value as an optional argument, otherwise as
a mandatory one. Use PROMPT as the prompt string."
(TeX-argument-insert
(TeX-read-string (TeX-argument-prompt optional prompt "Version")
(format-time-string "%Y/%m/%d" (current-time)))
optional))
(defun TeX-arg-pagestyle (optional &optional prompt definition)
"Prompt for a LaTeX pagestyle with completion.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string. If DEFINITION is non-nil, add the chosen pagestyle to
the list of defined pagestyles."
(let ((pagestyle (completing-read (TeX-argument-prompt optional prompt
"Pagestyle")
(LaTeX-pagestyle-list))))
(if (and definition (not (string-equal "" pagestyle)))
(LaTeX-add-pagestyles pagestyle))
(TeX-argument-insert pagestyle optional)))
(defcustom LaTeX-default-verb-delimiter ?|
"Default delimiter for `\\verb' macros."
:group 'LaTeX-macro
:type 'character)
(defun TeX-arg-verb (optional &optional _ignore)
"Prompt for delimiter and text.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. IGNORE is ignored."
(let ((del (read-quoted-char
(concat "Delimiter: (default "
(char-to-string LaTeX-default-verb-delimiter) ") "))))
(when (<= del ?\ ) (setq del LaTeX-default-verb-delimiter))
(if (TeX-active-mark)
(progn
(insert del)
(goto-char (mark))
(insert del))
(insert del (read-from-minibuffer "Text: ") del))
(setq LaTeX-default-verb-delimiter del)))
(defun TeX-arg-pair (optional first second)
"Insert a pair of number, prompted by FIRST and SECOND.
The numbers are surounded by parenthesizes and separated with a
comma.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one."
(insert "(" (TeX-read-string (concat first ": ")) ","
(TeX-read-string (concat second ": ")) ")"))
(defun TeX-arg-size (optional)
"Insert width and height as a pair.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one."
(TeX-arg-pair optional "Width" "Height"))
(defun TeX-arg-coordinate (optional)
"Insert x and y coordinate as a pair.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one."
(TeX-arg-pair optional "X position" "Y position"))
(defconst TeX-braces-default-association
'(("[" . "]")
("\\{" . "\\}")
("(" . ")")
("|" . "|")
("\\|" . "\\|")
("/" . "/")
("\\backslash" . "\\backslash")
("\\lfloor" . "\\rfloor")
("\\lceil" . "\\rceil")
("\\langle" . "\\rangle")))
(defcustom TeX-braces-user-association nil
"A list of your personal association of brace symbols.
These are used for \\left and \\right.
The car of each entry is the brace used with \\left,
the cdr is the brace used with \\right."
:group 'LaTeX-macro
:group 'LaTeX-math
:type '(repeat (cons :format "%v"
(string :tag "Left")
(string :tag "Right"))))
(defvar TeX-braces-association
(append TeX-braces-user-association
TeX-braces-default-association)
"A list of association of brace symbols for \\left and \\right.
The car of each entry is the brace used with \\left,
the cdr is the brace used with \\right.")
(defcustom LaTeX-electric-left-right-brace nil
"If non-nil, insert right brace with suitable macro after typing left brace."
:group 'LaTeX-macro
:type 'boolean)
(defvar TeX-left-right-braces
'(("[") ("]") ("\\{") ("\\}") ("(") (")") ("|") ("\\|")
("/") ("\\backslash") ("\\lfloor") ("\\rfloor")
("\\lceil") ("\\rceil") ("\\langle") ("\\rangle")
("\\uparrow") ("\\Uparrow") ("\\downarrow") ("\\Downarrow")
("\\updownarrow") ("\\Updownarrow") ("."))
"List of symbols which can follow the \\left or \\right command.")
(defvar LaTeX-left-right-macros-association
'(("left" . "right")
("bigl" . "bigr") ("Bigl" . "Bigr")
("biggl" . "biggr") ("Biggl" . "Biggr"))
"Alist of macros for adjusting size of left and right braces.
The car of each entry is for left brace and the cdr is for right brace.")
(defun TeX-arg-insert-braces (optional &optional prompt)
"Prompt for a brace for \\left and insert the corresponding \\right.
If OPTIONAL is non-nil, insert the resulting value as an optional
argument, otherwise as a mandatory one. Use PROMPT as the prompt
string."
(let (left-macro)
(save-excursion
;; Obtain macro name such as "left", "bigl" etc.
(setq left-macro (buffer-substring-no-properties
(point)
(progn (backward-word 1) (point))))
(backward-char)
(LaTeX-newline)
(indent-according-to-mode)
;; Delete possibly produced blank line.
(beginning-of-line 0)
(if (looking-at "^[ \t]*$")
(progn (delete-horizontal-space)
(delete-char 1))))
(let ((left-brace (completing-read
(TeX-argument-prompt optional prompt
"Which brace")
TeX-left-right-braces)))
(insert left-brace)
(LaTeX-newline)
(save-excursion
(if (TeX-active-mark)
(goto-char (mark)))
(LaTeX-newline)
(LaTeX-insert-corresponding-right-macro-and-brace
left-macro left-brace optional prompt)
(indent-according-to-mode))
(indent-according-to-mode))))
(defun TeX-arg-insert-right-brace-maybe (optional)
"Insert the suitable right brace macro such as \\rangle.
Insertion is done when `TeX-arg-right-insert-p' is non-nil.
If the left brace macro is preceeded by \\left, \\bigl etc.,
supply the corresponding macro such as \\right before the right brace macro.
OPTIONAL is ignored."
;; Nothing is done when TeX-arg-right-insert-p is nil.
(when TeX-arg-right-insert-p
(let (left-brace left-macro)
(save-excursion
;; Obtain left brace macro name such as "\langle".
(setq left-brace (buffer-substring-no-properties
(point)
(progn (backward-word) (backward-char)
(point)))
;; Obtain the name of preceeding left macro, if any,
;; such as "left", "bigl" etc.
left-macro (LaTeX-find-preceeding-left-macro-name)))
(save-excursion
(if (TeX-active-mark)
(goto-char (mark)))
(LaTeX-insert-corresponding-right-macro-and-brace
left-macro left-brace optional)))))
(defvar TeX-arg-right-insert-p)
(defun LaTeX-insert-left-brace (arg)
"Insert typed left brace ARG times and possibly a correspondig right brace.
Automatic right brace insertion is done only if no prefix ARG is given and
`LaTeX-electric-left-right-brace' is non-nil.
Normally bound to keys \(, { and [."
(interactive "*P")
(let ((auto-p (and LaTeX-electric-left-right-brace (not arg))))
(if (and auto-p
(TeX-active-mark)
(> (point) (mark)))
(exchange-point-and-mark))
(self-insert-command (prefix-numeric-value arg))
(if auto-p
(let ((lbrace (char-to-string last-command-event)) lmacro skip-p)
(save-excursion
(backward-char)
;; The brace "{" is exceptional in two aspects.
;; 1. "\{" should be considered as a single brace
;; like "(" and "[".
;; 2. "\left{" is nonsense while "\left\{" and
;; "\left(" are not.
(if (string= lbrace TeX-grop)
;; If "{" follows "\", set lbrace to "\{".
(if (TeX-escaped-p)
(progn
(backward-char)
(setq lbrace (concat TeX-esc TeX-grop)))
;; Otherwise, don't search for left macros.
(setq skip-p t)))
(unless skip-p
;; Obtain the name of preceeding left macro, if any,
;; such as "left", "bigl" etc.
(setq lmacro (LaTeX-find-preceeding-left-macro-name))))
(let ((TeX-arg-right-insert-p t)
;; "{" and "}" are paired temporally so that typing
;; a single "{" should insert a pair "{}".
(TeX-braces-association
(cons (cons TeX-grop TeX-grcl) TeX-braces-association)))
(save-excursion
(if (TeX-active-mark)
(goto-char (mark)))
(LaTeX-insert-corresponding-right-macro-and-brace
lmacro lbrace)))))))
(defun LaTeX-insert-corresponding-right-macro-and-brace
(lmacro lbrace &optional optional prompt)
"Insert right macro and brace correspoinding to LMACRO and LBRACE.
Left-right association is determined through
`LaTeX-left-right-macros-association' and `TeX-braces-association'.
If brace association can't be determined or `TeX-arg-right-insert-p'
is nil, consult user which brace should be used."
;; This function is called with LMACRO being one of the following
;; possibilities.
;; (1) nil, which means LBRACE is isolated.
;; (2) null string, which means LBRACE follows right after "\" to
;; form "\(" or "\[".
;; (3) a string in CARs of `LaTeX-left-right-macros-association'.
(let ((rmacro (cdr (assoc lmacro LaTeX-left-right-macros-association)))
(rbrace (cdr (assoc lbrace TeX-braces-association))))
;; Since braces like "\(" and "\)" should be paired, RMACRO
;; should be considered as null string in the case (2).
(if (string= lmacro "")
(setq rmacro ""))
;; Insert right macros such as "\right", "\bigr" etc., if necessary.
;; Even single "\" will be inserted so that "\)" or "\]" is
;; inserted after "\(", "\[".
(if rmacro
(insert TeX-esc rmacro))
(cond
((and TeX-arg-right-insert-p rbrace)
(insert rbrace))
(rmacro
(insert (completing-read
(TeX-argument-prompt
optional prompt
(format "Which brace (default %s)"
(or rbrace "."))) TeX-left-right-braces
nil nil nil nil (or rbrace ".")))))))
(defun LaTeX-find-preceeding-left-macro-name ()
"Return the left macro name just before the point, if any.
If the preceeding macro isn't left macros such as \\left, \\bigl etc.,
return nil.
If the point is just after unescaped `TeX-esc', return the null string."
;; \left-!- => "left"
;; \-!- => ""
;; \infty-!- => nil
;; \&-!- => nil
;; \mathrm{abc}-!- => nil
;; {blah blah blah}-!- => nil
;; \\-!- => nil
(let ((name (buffer-substring-no-properties
(point)
;; This is only a helper function, so we do not
;; preserve point by save-excursion.
(progn
;; Assume left macro names consist of only A-Z and a-z.
(skip-chars-backward "A-Za-z")
(point)))))
(if (and (TeX-escaped-p)
(or (string= name "")
(assoc name LaTeX-left-right-macros-association)))
name)))
(defcustom LaTeX-default-author 'user-full-name
"Initial input to `LaTeX-arg-author' prompt.
If nil, do not prompt at all."
:group 'LaTeX-macro
:type '(choice (const :tag "User name in Emacs" user-full-name)
(const :tag "Do not prompt" nil)
string))
(defun LaTeX-arg-author (optional &optional prompt)
"Prompt for author name.
Insert the given value as a TeX macro argument. If OPTIONAL is
non-nil, insert it as an optional argument. Use PROMPT as the
prompt string. `LaTeX-default-author' is the initial input."
(let ((author (if LaTeX-default-author
(TeX-read-string
(TeX-argument-prompt optional prompt "Author(s)")
(if (symbolp LaTeX-default-author)
(symbol-value LaTeX-default-author)
LaTeX-default-author))
"")))
(TeX-argument-insert author optional nil)))
(defun TeX-read-key-val (optional key-val-alist &optional prompt)
"Prompt for keys and values in KEY-VAL-ALIST and return them.
If OPTIONAL is non-nil, indicate in the prompt that we are
reading an optional argument. KEY-VAL-ALIST is an alist. The
car of each element should be a string representing a key and the
optional cdr should be a list with strings to be used as values
for the key. Use PROMPT as the prompt string."
(multi-prompt-key-value
(TeX-argument-prompt optional prompt "Options (k=v)")
(if (symbolp key-val-alist)
(eval key-val-alist)
key-val-alist)))
(defun TeX-arg-key-val (optional key-val-alist &optional prompt)
"Prompt for keys and values in KEY-VAL-ALIST.
Insert the given value as a TeX macro argument. If OPTIONAL is
non-nil, insert it as an optional argument. KEY-VAL-ALIST is an
alist. The car of each element should be a string representing a
key and the optional cdr should be a list with strings to be used
as values for the key. Use PROMPT as the prompt string."
(let ((options (TeX-read-key-val optional key-val-alist prompt)))
(TeX-argument-insert options optional)))
;;; Verbatim constructs
(defcustom LaTeX-verbatim-macros-with-delims
'("verb" "verb*")
"Macros for inline verbatim with arguments in delimiters, like \\foo|...|.
Programs should not use this variable directly but the function
`LaTeX-verbatim-macros-with-delims' which returns a value
including buffer-local keyword additions via
`LaTeX-verbatim-macros-with-delims-local' as well."
:group 'LaTeX-macro
:type '(repeat (string)))
(defvar LaTeX-verbatim-macros-with-delims-local nil
"Buffer-local variable for inline verbatim with args in delimiters.
Style files should add constructs to this variable and not to
`LaTeX-verbatim-macros-with-delims'.
Programs should not use this variable directly but the function
`LaTeX-verbatim-macros-with-delims' which returns a value
including values of the variable
`LaTeX-verbatim-macros-with-delims' as well.")
(make-variable-buffer-local 'LaTeX-verbatim-macros-with-delims-local)
(defcustom LaTeX-verbatim-macros-with-braces nil
"Macros for inline verbatim with arguments in braces, like \\foo{...}.
Programs should not use this variable directly but the function
`LaTeX-verbatim-macros-with-braces' which returns a value
including buffer-local keyword additions via
`LaTeX-verbatim-macros-with-braces-local' as well."
:group 'LaTeX-macro
:type '(repeat (string)))
(defvar LaTeX-verbatim-macros-with-braces-local nil
"Buffer-local variable for inline verbatim with args in braces.
Style files should add constructs to this variable and not to
`LaTeX-verbatim-macros-with-braces'.
Programs should not use this variable directly but the function
`LaTeX-verbatim-macros-with-braces' which returns a value
including values of the variable
`LaTeX-verbatim-macros-with-braces' as well.")
(make-variable-buffer-local 'LaTeX-verbatim-macros-with-braces-local)
(defcustom LaTeX-verbatim-environments
'("verbatim" "verbatim*")
"Verbatim environments.
Programs should not use this variable directly but the function
`LaTeX-verbatim-environments' which returns a value including
buffer-local keyword additions via
`LaTeX-verbatim-environments-local' as well."
:group 'LaTeX-environment
:type '(repeat (string)))
(defvar LaTeX-verbatim-environments-local nil
"Buffer-local variable for inline verbatim environments.
Style files should add constructs to this variable and not to
`LaTeX-verbatim-environments'.
Programs should not use this variable directly but the function
`LaTeX-verbatim-environments' which returns a value including
values of the variable `LaTeX-verbatim-environments' as well.")
(make-variable-buffer-local 'LaTeX-verbatim-environments-local)
(defun LaTeX-verbatim-macros-with-delims ()
"Return list of verbatim macros with delimiters."
(append LaTeX-verbatim-macros-with-delims
LaTeX-verbatim-macros-with-delims-local))
(defun LaTeX-verbatim-macros-with-braces ()
"Return list of verbatim macros with braces."
(append LaTeX-verbatim-macros-with-braces
LaTeX-verbatim-macros-with-braces-local))
(defun LaTeX-verbatim-environments ()
"Return list of verbatim environments."
(append LaTeX-verbatim-environments
LaTeX-verbatim-environments-local))
(defun LaTeX-verbatim-macro-boundaries ()
"Return boundaries of verbatim macro.
Boundaries are returned as a cons cell where the car is the macro
start and the cdr the macro end.
Only macros which enclose their arguments with special
non-parenthetical delimiters, like \\verb+foo+, are recognized."
(save-excursion
(let ((orig (point))
(verbatim-regexp (regexp-opt (LaTeX-verbatim-macros-with-delims) t)))
;; Search backwards for the macro start, unless we are facing one
(unless (looking-at (concat (regexp-quote TeX-esc) verbatim-regexp))
(catch 'found
(while (progn
(skip-chars-backward (concat "^\n" (regexp-quote TeX-esc))
(line-beginning-position))
(when (looking-at verbatim-regexp) (throw 'found nil))
(or (bobp) (forward-char -1))
(/= (point) (line-beginning-position))))))
;; Search forward for the macro end, unless we failed to find a start
(unless (bolp)
(let* ((beg (1- (point)))
(macro-end (match-end 0))
;; XXX: Here we assume we are dealing with \verb which
;; expects the delimiter right behind the command.
;; However, \lstinline can also cope with whitespace as
;; well as an optional argument after the command.
(delimiter (buffer-substring-no-properties
macro-end (1+ macro-end))))
;; Heuristic: If an opening brace is encountered, search for
;; both the opening and the closing brace as an end marker.
;; Like that the function should work for \verb|...| as well
;; as for \url{...}.
(when (string= delimiter TeX-grop)
(setq delimiter (concat delimiter TeX-grcl)))
(goto-char (1+ macro-end))
(skip-chars-forward (concat "^" delimiter))
(when (<= orig (point))
(cons beg (1+ (point)))))))))
(defun LaTeX-current-verbatim-macro ()
"Return name of verbatim macro containing point, nil if none is present."
(let ((macro-boundaries (LaTeX-verbatim-macro-boundaries)))
(when macro-boundaries
(save-excursion
(goto-char (car macro-boundaries))
(forward-char (length TeX-esc))
(buffer-substring-no-properties
(point) (progn (skip-chars-forward "@A-Za-z") (point)))))))
(defun LaTeX-verbatim-p (&optional pos)
"Return non-nil if position POS is in a verbatim-like construct."
(when pos (goto-char pos))
(save-match-data
(or (when (fboundp 'font-latex-faces-present-p)
(font-latex-faces-present-p 'font-latex-verbatim-face))
(member (LaTeX-current-verbatim-macro)
(LaTeX-verbatim-macros-with-delims))
(member (TeX-current-macro) (LaTeX-verbatim-macros-with-braces))
(member (LaTeX-current-environment) (LaTeX-verbatim-environments)))))
;;; Formatting
(defcustom LaTeX-syntactic-comments t
"If non-nil comments will be handled according to LaTeX syntax.
This variable influences, among others, the behavior of
indentation and filling which will take LaTeX syntax into
consideration just as is in the non-commented source code."
:type 'boolean
:group 'LaTeX)
;;; Indentation
;; We are distinguishing two different types of comments:
;;
;; 1) Comments starting in column one (line comments)
;;
;; 2) Comments starting after column one with only whitespace
;; preceding it.
;;
;; (There is actually a third type: Comments preceded not only by
;; whitespace but by some code as well; so-called code comments. But
;; they are not relevant for the following explanations.)
;;
;; Additionally we are distinguishing two different types of
;; indentation:
;;
;; a) Outer indentation: Indentation before the comment character(s).
;;
;; b) Inner indentation: Indentation after the comment character(s)
;; (taking into account possible comment padding).
;;
;; Comments can be filled syntax-aware or not.
;;
;; In `doctex-mode' line comments should always be indented
;; syntax-aware and the comment character has to be anchored at the
;; first column (unless the appear in a macrocode environment). Other
;; comments not in the documentation parts always start after the
;; first column and can be indented syntax-aware or not. If they are
;; indented syntax-aware both the indentation before and after the
;; comment character(s) have to be checked and adjusted. Indentation
;; should not move the comment character(s) to the first column. With
;; `LaTeX-syntactic-comments' disabled, line comments should still be
;; indented syntax-aware.
;;
;; In `latex-mode' comments starting in different columns don't have
;; to be handled differently. They don't have to be anchored in
;; column one. That means that in any case indentation before and
;; after the comment characters has to be checked and adjusted.
(defgroup LaTeX-indentation nil
"Indentation of LaTeX code in AUCTeX"
:group 'LaTeX
:group 'TeX-indentation)
(defcustom LaTeX-indent-level 2
"*Indentation of begin-end blocks in LaTeX."
:group 'LaTeX-indentation
:type 'integer)
(defcustom LaTeX-item-indent (- LaTeX-indent-level)
"*Extra indentation for lines beginning with an item."
:group 'LaTeX-indentation
:type 'integer)
(defcustom LaTeX-item-regexp "\\(bib\\)?item\\b"
"*Regular expression matching macros considered items."
:group 'LaTeX-indentation
:type 'regexp)
(defcustom LaTeX-indent-environment-list
'(("verbatim" current-indentation)
("verbatim*" current-indentation)
("tabular" LaTeX-indent-tabular)
("tabular*" LaTeX-indent-tabular)
("align" LaTeX-indent-tabular)
("align*" LaTeX-indent-tabular)
("array" LaTeX-indent-tabular)
("eqnarray" LaTeX-indent-tabular)
("eqnarray*" LaTeX-indent-tabular)
;; The following should have their own, smart indentation function.
;; Some other day.
("displaymath")
("equation")
("equation*")
("picture")
("tabbing")
("table")
("table*"))
"Alist of environments with special indentation.
The second element in each entry is the function to calculate the
indentation level in columns."
:group 'LaTeX-indentation
:type '(repeat (list (string :tag "Environment")
(option function))))
(defcustom LaTeX-indent-environment-check t
"*If non-nil, check for any special environments."
:group 'LaTeX-indentation
:type 'boolean)
(defcustom LaTeX-document-regexp "document"
"Regexp matching environments in which the indentation starts at col 0."
:group 'LaTeX-indentation
:type 'regexp)
(defcustom LaTeX-verbatim-regexp "verbatim\\*?"
"*Regexp matching environments with indentation at col 0 for begin/end."
:group 'LaTeX-indentation
:type 'regexp)
(defcustom LaTeX-begin-regexp "begin\\b"
"*Regexp matching macros considered begins."
:group 'LaTeX-indentation
:type 'regexp)
(defcustom LaTeX-end-regexp "end\\b"
"*Regexp matching macros considered ends."
:group 'LaTeX-indentation
:type 'regexp)
(defcustom LaTeX-left-right-indent-level LaTeX-indent-level
"*The level of indentation produced by a \\left macro."
:group 'LaTeX-indentation
:type 'integer)
(defcustom LaTeX-indent-comment-start-regexp "%"
"*Regexp matching comments ending the indent level count.
This means, we just count the LaTeX tokens \\left, \\right, \\begin,
and \\end up to the first occurence of text matching this regexp.
Thus, the default \"%\" stops counting the tokens at a comment. A
value of \"%[^>]\" would allow you to alter the indentation with
comments, e.g. with comment `%> \\begin'.
Lines which start with `%' are not considered at all, regardless if this
value."
:group 'LaTeX-indentation
:type 'regexp)
(defvar docTeX-indent-inner-fixed
`((,(concat (regexp-quote TeX-esc)
"\\(begin\\|end\\)[ \t]*{macrocode\\*?}") 4 t)
(,(concat (regexp-quote TeX-esc)
"\\(begin\\|end\\)[ \t]*{\\(macro\\|environment\\)\\*?}") 0 nil))
"List of items which should have a fixed inner indentation.
The items consist of three parts. The first is a regular
expression which should match the respective string. The second
is the amount of spaces to be used for indentation. The third
toggles if comment padding is relevant or not. If t padding is
part of the amount given, if nil the amount of spaces will be
inserted after potential padding.")
(defun LaTeX-indent-line ()
"Indent the line containing point, as LaTeX source.
Add `LaTeX-indent-level' indentation in each \\begin{ - \\end{ block.
Lines starting with an item is given an extra indentation of
`LaTeX-item-indent'."
(interactive)
(let* ((case-fold-search nil)
;; Compute a fill prefix. Whitespace after the comment
;; characters will be disregarded and replaced by
;; `comment-padding'.
(fill-prefix
(and (TeX-in-commented-line)
(save-excursion
(beginning-of-line)
(looking-at
(concat "\\([ \t]*" TeX-comment-start-regexp "+\\)+"))
(concat (match-string 0) (TeX-comment-padding-string)))))
(overlays (when (featurep 'xemacs)
;; Isn't that fun? In Emacs an `(overlays-at
;; (line-beginning-position))' would do the
;; trick. How boring.
(extent-list
nil (line-beginning-position) (line-beginning-position)
'all-extents-closed-open 'overlay)))
ol-specs)
;; XEmacs' `indent-to' function (at least in version 21.4.15) has
;; a bug which leads to the insertion of whitespace in front of an
;; invisible overlay. So during indentation we temporarily remove
;; the 'invisible property.
(dolist (ol overlays)
(when (extent-property ol 'invisible)
(pushnew (list ol (extent-property ol 'invisible))
ol-specs :test #'equal)
(set-extent-property ol 'invisible nil)))
(save-excursion
(cond ((and fill-prefix
(TeX-in-line-comment)
(eq major-mode 'doctex-mode))
;; If point is in a line comment in `doctex-mode' we only
;; consider the inner indentation.
(let ((inner-indent (LaTeX-indent-calculate 'inner)))
(when (/= (LaTeX-current-indentation 'inner) inner-indent)
(LaTeX-indent-inner-do inner-indent))))
((and fill-prefix
LaTeX-syntactic-comments)
;; In any other case of a comment we have to consider
;; outer and inner indentation if we do syntax-aware
;; indentation.
(let ((inner-indent (LaTeX-indent-calculate 'inner))
(outer-indent (LaTeX-indent-calculate 'outer)))
(when (/= (LaTeX-current-indentation 'inner) inner-indent)
(LaTeX-indent-inner-do inner-indent))
(when (/= (LaTeX-current-indentation 'outer) outer-indent)
(LaTeX-indent-outer-do outer-indent))))
(t
;; The default is to adapt whitespace before any
;; non-whitespace character, i.e. to do outer
;; indentation.
(let ((outer-indent (LaTeX-indent-calculate 'outer)))
(when (/= (LaTeX-current-indentation 'outer) outer-indent)
(LaTeX-indent-outer-do outer-indent))))))
;; Make the overlays invisible again.
(dolist (ol-spec ol-specs)
(set-extent-property (car ol-spec) 'invisible (cadr ol-spec)))
(when (< (current-column) (save-excursion
(LaTeX-back-to-indentation) (current-column)))
(LaTeX-back-to-indentation))))
(defun LaTeX-indent-inner-do (inner-indent)
;; Small helper function for `LaTeX-indent-line' to perform
;; indentation after a comment character. It requires that
;; `LaTeX-indent-line' already set the appropriate variables and
;; should not be used outside of `LaTeX-indent-line'.
(move-to-left-margin)
(TeX-re-search-forward-unescaped
(concat "\\(" TeX-comment-start-regexp "+[ \t]*\\)+") (line-end-position) t)
(delete-region (line-beginning-position) (point))
(insert fill-prefix)
(indent-to (+ inner-indent (length fill-prefix))))
(defun LaTeX-indent-outer-do (outer-indent)
;; Small helper function for `LaTeX-indent-line' to perform
;; indentation of normal lines or before a comment character in a
;; commented line. It requires that `LaTeX-indent-line' already set
;; the appropriate variables and should not be used outside of
;; `LaTeX-indent-line'.
(back-to-indentation)
(delete-region (line-beginning-position) (point))
(indent-to outer-indent))
(defun LaTeX-indent-calculate (&optional force-type)
"Return the indentation of a line of LaTeX source.
FORCE-TYPE can be used to force the calculation of an inner or
outer indentation in case of a commented line. The symbols
'inner and 'outer are recognized."
(save-excursion
(LaTeX-back-to-indentation force-type)
(let ((i 0)
(list-length (safe-length docTeX-indent-inner-fixed))
(case-fold-search nil)
entry
found)
(cond ((save-excursion (beginning-of-line) (bobp)) 0)
((and (eq major-mode 'doctex-mode)
fill-prefix
(TeX-in-line-comment)
(progn
(while (and (< i list-length)
(not found))
(setq entry (nth i docTeX-indent-inner-fixed))
(when (looking-at (nth 0 entry))
(setq found t))
(setq i (1+ i)))
found))
(if (nth 2 entry)
(- (nth 1 entry) (if (integerp comment-padding)
comment-padding
(length comment-padding)))
(nth 1 entry)))
((looking-at (concat (regexp-quote TeX-esc)
"\\(begin\\|end\\){\\("
LaTeX-verbatim-regexp
"\\)}"))
;; \end{verbatim} must be flush left, otherwise an unwanted
;; empty line appears in LaTeX's output.
0)
((and LaTeX-indent-environment-check
;; Special environments.
(let ((entry (assoc (or LaTeX-current-environment
(LaTeX-current-environment))
LaTeX-indent-environment-list)))
(and entry
(nth 1 entry)
(funcall (nth 1 entry))))))
((looking-at (concat (regexp-quote TeX-esc)
"\\("
LaTeX-end-regexp
"\\)"))
;; Backindent at \end.
(- (LaTeX-indent-calculate-last force-type) LaTeX-indent-level))
((looking-at (concat (regexp-quote TeX-esc) "right\\b"))
;; Backindent at \right.
(- (LaTeX-indent-calculate-last force-type)
LaTeX-left-right-indent-level))
((looking-at (concat (regexp-quote TeX-esc)
"\\("
LaTeX-item-regexp
"\\)"))
;; Items.
(+ (LaTeX-indent-calculate-last force-type) LaTeX-item-indent))
((looking-at "}")
;; End brace in the start of the line.
(- (LaTeX-indent-calculate-last force-type)
TeX-brace-indent-level))
(t (LaTeX-indent-calculate-last force-type))))))
(defun LaTeX-indent-level-count ()
"Count indentation change caused by all \\left, \\right, \\begin, and
\\end commands in the current line."
(save-excursion
(save-restriction
(let ((count 0))
(narrow-to-region (point)
(save-excursion
(re-search-forward
(concat "[^" TeX-esc "]"
"\\(" LaTeX-indent-comment-start-regexp
"\\)\\|\n\\|\\'"))
(backward-char)
(point)))
(while (search-forward TeX-esc nil t)
(cond
((looking-at "left\\b")
(setq count (+ count LaTeX-left-right-indent-level)))
((looking-at "right\\b")
(setq count (- count LaTeX-left-right-indent-level)))
((looking-at LaTeX-begin-regexp)
(setq count (+ count LaTeX-indent-level)))
((looking-at LaTeX-end-regexp)
(setq count (- count LaTeX-indent-level)))
((looking-at (regexp-quote TeX-esc))
(forward-char 1))))
count))))
(defun LaTeX-indent-calculate-last (&optional force-type)
"Return the correct indentation of a normal line of text.
The point is supposed to be at the beginning of the current line.
FORCE-TYPE can be used to force the calculation of an inner or
outer indentation in case of a commented line. The symbols
'inner and 'outer are recognized."
(let (line-comment-current-flag
line-comment-last-flag
comment-current-flag
comment-last-flag)
(beginning-of-line)
(setq line-comment-current-flag (TeX-in-line-comment)
comment-current-flag (TeX-in-commented-line))
(if comment-current-flag
(skip-chars-backward "%\n\t ")
(skip-chars-backward "\n\t "))
(beginning-of-line)
;; If we are called in a non-comment line, skip over comment
;; lines. The computation of indentation should in this case
;; rather take the last non-comment line into account.
;; Otherwise there might arise problems with e.g. multi-line
;; code comments. This behavior is not enabled in docTeX mode
;; where large amounts of line comments may have to be skipped
;; and indentation should not be influenced by unrelated code in
;; other macrocode environments.
(while (and (not (eq major-mode 'doctex-mode))
(not comment-current-flag)
(TeX-in-commented-line)
(not (bobp)))
(skip-chars-backward "\n\t ")
(beginning-of-line))
(setq line-comment-last-flag (TeX-in-line-comment)
comment-last-flag (TeX-in-commented-line))
(LaTeX-back-to-indentation force-type)
;; Separate line comments and other stuff (normal text/code and
;; code comments). Additionally we don't want to compute inner
;; indentation when a commented and a non-commented line are
;; compared.
(cond ((or (and (eq major-mode 'doctex-mode)
(or (and line-comment-current-flag
(not line-comment-last-flag))
(and (not line-comment-current-flag)
line-comment-last-flag)))
(and force-type
(eq force-type 'inner)
(or (and comment-current-flag
(not comment-last-flag))
(and (not comment-current-flag)
comment-last-flag))))
0)
((looking-at (concat (regexp-quote TeX-esc)
"begin *{\\("
LaTeX-document-regexp
"\\)}"))
;; I dislike having all of the document indented...
(+ (LaTeX-current-indentation force-type)
;; Some people have opening braces at the end of the
;; line, e.g. in case of `\begin{letter}{%'.
(TeX-brace-count-line)))
((and (eq major-mode 'doctex-mode)
(looking-at (concat (regexp-quote TeX-esc)
"end[ \t]*{macrocode\\*?}"))
fill-prefix
(TeX-in-line-comment))
;; Reset indentation to zero after a macrocode
;; environment.
0)
((looking-at (concat (regexp-quote TeX-esc)
"begin *{\\("
LaTeX-verbatim-regexp
"\\)}"))
0)
((looking-at (concat (regexp-quote TeX-esc)
"end *{\\("
LaTeX-verbatim-regexp
"\\)}"))
;; If I see an \end{verbatim} in the previous line I skip
;; back to the preceding \begin{verbatim}.
(save-excursion
(if (re-search-backward (concat (regexp-quote TeX-esc)
"begin *{\\("
LaTeX-verbatim-regexp
"\\)}") 0 t)
(LaTeX-indent-calculate-last force-type)
0)))
(t (+ (LaTeX-current-indentation force-type)
(if (not (and force-type
(eq force-type 'outer)
(TeX-in-commented-line)))
(+ (LaTeX-indent-level-count)
(TeX-brace-count-line))
0)
(cond ((looking-at (concat (regexp-quote TeX-esc)
"\\("
LaTeX-end-regexp
"\\)"))
LaTeX-indent-level)
((looking-at
(concat (regexp-quote TeX-esc) "right\\b"))
LaTeX-left-right-indent-level)
((looking-at (concat (regexp-quote TeX-esc)
"\\("
LaTeX-item-regexp
"\\)"))
(- LaTeX-item-indent))
((looking-at "}")
TeX-brace-indent-level)
(t 0)))))))
(defun LaTeX-current-indentation (&optional force-type)
"Return the indentation of a line.
FORCE-TYPE can be used to force the calculation of an inner or
outer indentation in case of a commented line. The symbols
'inner and 'outer are recognized."
(if (and fill-prefix
(or (and force-type
(eq force-type 'inner))
(and (not force-type)
(or
;; If `LaTeX-syntactic-comments' is not enabled,
;; do conventional indentation
LaTeX-syntactic-comments
;; Line comments in `doctex-mode' are always
;; indented syntax-aware so we need their inner
;; indentation.
(and (TeX-in-line-comment)
(eq major-mode 'doctex-mode))))))
;; INNER indentation
(save-excursion
(beginning-of-line)
(looking-at (concat "\\(?:[ \t]*" TeX-comment-start-regexp "+\\)+"
"\\([ \t]*\\)"))
(- (length (match-string 1)) (length (TeX-comment-padding-string))))
;; OUTER indentation
(current-indentation)))
(defun LaTeX-back-to-indentation (&optional force-type)
"Move point to the first non-whitespace character on this line.
If it is commented and comments are formatted syntax-aware move
point to the first non-whitespace character after the comment
character(s). The optional argument FORCE-TYPE can be used to
force point being moved to the inner or outer indentation in case
of a commented line. The symbols 'inner and 'outer are
recognized."
(if (or (and force-type
(eq force-type 'inner))
(and (not force-type)
(or (and (TeX-in-line-comment)
(eq major-mode 'doctex-mode))
(and (TeX-in-commented-line)
LaTeX-syntactic-comments))))
(progn
(beginning-of-line)
;; Should this be anchored at the start of the line?
(TeX-re-search-forward-unescaped
(concat "\\(?:" TeX-comment-start-regexp "+[ \t]*\\)+")
(line-end-position) t))
(back-to-indentation)))
;;; Filling
(defcustom LaTeX-fill-break-at-separators '(\\\( \\\) \\\[ \\\])
"List of separators before or after which respectively a line
break will be inserted if they do not fit into one line."
:group 'LaTeX
:type '(set :tag "Contents"
(const :tag "Opening Brace" \{)
(const :tag "Closing Brace" \})
(const :tag "Opening Bracket" \[)
(const :tag "Opening Inline Math Switches" \\\()
(const :tag "Closing Inline Math Switches" \\\))
(const :tag "Opening Display Math Switch" \\\[)
(const :tag "Closing Display Math Switch" \\\])))
(defcustom LaTeX-fill-break-before-code-comments t
"If non-nil, a line with some code followed by a comment will
be broken before the last non-comment word in case the comment
does not fit into the line."
:group 'LaTeX
:type 'boolean)
(defvar LaTeX-nospace-between-char-regexp
(if (featurep 'xemacs)
(if (and (boundp 'word-across-newline) word-across-newline)
word-across-newline
;; NOTE: Ensure not to have a value of nil for such a rare case that
;; somebody removes the mule test in `LaTeX-fill-delete-newlines' so that
;; it could match only "\n" and this could lead to problem. XEmacs does
;; not have a category `\c|' and `\ct' means `Chinese Taiwan' in XEmacs.
"\\(\\cj\\|\\cc\\|\\ct\\)")
"\\c|")
"Regexp matching a character where no interword space is necessary.
Words formed by such characters can be broken across newlines.")
(defvar LaTeX-fill-newline-hook nil
"Hook run after `LaTeX-fill-newline' inserted and indented a new line.")
(defun LaTeX-fill-region-as-paragraph (from to &optional justify-flag)
"Fill region as one paragraph.
Break lines to fit `fill-column', but leave all lines ending with
\\\\ \(plus its optional argument) alone. Lines with code
comments and lines ending with `\par' are included in filling but
act as boundaries. Prefix arg means justify too. From program,
pass args FROM, TO and JUSTIFY-FLAG."
(interactive "*r\nP")
(let ((end-marker (save-excursion (goto-char to) (point-marker))))
(if (or (assoc (LaTeX-current-environment) LaTeX-indent-environment-list)
;; This could be generalized, if there are more cases where
;; a special string at the start of a region to fill should
;; inhibit filling.
(progn (save-excursion (goto-char from)
(looking-at (concat TeX-comment-start-regexp
"+[ \t]*"
"Local Variables:")))))
;; Filling disabled, only do indentation.
(indent-region from to nil)
(save-restriction
(goto-char from)
(while (< (point) end-marker)
(if (re-search-forward
(concat "\\("
;; Code comments.
"[^\r\n%\\]\\([ \t]\\|\\\\\\\\\\)*"
TeX-comment-start-regexp
"\\|"
;; Lines ending with `\par'.
"\\(\\=\\|[^" TeX-esc "\n]\\)\\("
(regexp-quote (concat TeX-esc TeX-esc))
"\\)*"
(regexp-quote TeX-esc) "par[ \t]*"
"\\({[ \t]*}\\)?[ \t]*$"
"\\)\\|\\("
;; Lines ending with `\\'.
(regexp-quote TeX-esc)
(regexp-quote TeX-esc)
"\\(\\s-*\\*\\)?"
"\\(\\s-*\\[[^]]*\\]\\)?"
"\\s-*$\\)")
end-marker t)
(progn
(goto-char (line-end-position))
(delete-horizontal-space)
;; I doubt very much if we want justify -
;; this is a line with \\
;; if you think otherwise - uncomment the next line
;; (and justify-flag (justify-current-line))
(forward-char)
;; keep our position in a buffer
(save-excursion
;; Code comments and lines ending with `\par' are
;; included in filling. Lines ending with `\\' are
;; skipped.
(if (match-string 1)
(LaTeX-fill-region-as-para-do from (point) justify-flag)
(LaTeX-fill-region-as-para-do
from (line-beginning-position 0) justify-flag)
;; At least indent the line ending with `\\'.
(indent-according-to-mode)))
(setq from (point)))
;; ELSE part follows - loop termination relies on a fact
;; that (LaTeX-fill-region-as-para-do) moves point past
;; the filled region
(LaTeX-fill-region-as-para-do from end-marker justify-flag)))))))
;; The content of `LaTeX-fill-region-as-para-do' was copied from the
;; function `fill-region-as-paragraph' in `fill.el' (CVS Emacs,
;; January 2004) and adapted to the needs of AUCTeX.
(defun LaTeX-fill-region-as-para-do (from to &optional justify
nosqueeze squeeze-after)
"Fill the region defined by FROM and TO as one paragraph.
It removes any paragraph breaks in the region and extra newlines at the end,
indents and fills lines between the margins given by the
`current-left-margin' and `current-fill-column' functions.
\(In most cases, the variable `fill-column' controls the width.)
It leaves point at the beginning of the line following the paragraph.
Normally performs justification according to the `current-justification'
function, but with a prefix arg, does full justification instead.
From a program, optional third arg JUSTIFY can specify any type of
justification. Fourth arg NOSQUEEZE non-nil means not to make spaces
between words canonical before filling. Fifth arg SQUEEZE-AFTER, if non-nil,
means don't canonicalize spaces before that position.
Return the `fill-prefix' used for filling.
If `sentence-end-double-space' is non-nil, then period followed by one
space does not end a sentence, so don't break a line there."
(interactive (progn
(barf-if-buffer-read-only)
(list (region-beginning) (region-end)
(if current-prefix-arg 'full))))
(unless (memq justify '(t nil none full center left right))
(setq justify 'full))
;; Make sure "to" is the endpoint.
(goto-char (min from to))
(setq to (max from to))
;; Ignore blank lines at beginning of region.
(skip-chars-forward " \t\n")
(let ((from-plus-indent (point))
(oneleft nil))
(beginning-of-line)
(setq from (point))
;; Delete all but one soft newline at end of region.
;; And leave TO before that one.
(goto-char to)
(while (and (> (point) from) (eq ?\n (char-after (1- (point)))))
(if (and oneleft
(not (and use-hard-newlines
(get-text-property (1- (point)) 'hard))))
(delete-char -1)
(backward-char 1)
(setq oneleft t)))
(setq to (copy-marker (point) t))
(goto-char from-plus-indent))
(if (not (> to (point)))
nil ;; There is no paragraph, only whitespace: exit now.
(or justify (setq justify (current-justification)))
;; Don't let Adaptive Fill mode alter the fill prefix permanently.
(let ((fill-prefix fill-prefix))
;; Figure out how this paragraph is indented, if desired.
(when (and adaptive-fill-mode
(or (null fill-prefix) (string= fill-prefix "")))
(setq fill-prefix (fill-context-prefix from to))
;; Ignore a white-space only fill-prefix
;; if we indent-according-to-mode.
(when (and fill-prefix fill-indent-according-to-mode
(string-match "\\`[ \t]*\\'" fill-prefix))
(setq fill-prefix nil)))
(goto-char from)
(beginning-of-line)
(if (not justify) ; filling disabled: just check indentation
(progn
(goto-char from)
(while (< (point) to)
(if (and (not (eolp))
(< (LaTeX-current-indentation) (current-left-margin)))
(fill-indent-to-left-margin))
(forward-line 1)))
(when use-hard-newlines
(remove-text-properties from to '(hard nil)))
;; Make sure first line is indented (at least) to left margin...
(indent-according-to-mode)
;; COMPATIBILITY for Emacs <= 21.1
(if (fboundp 'fill-delete-prefix)
;; Delete the fill-prefix from every line.
(fill-delete-prefix from to fill-prefix)
;; Delete the comment prefix and any whitespace from every
;; line of the region in concern except the first. (The
;; implementation is heuristic to a certain degree.)
(save-excursion
(goto-char from)
(forward-line 1)
(when (< (point) to)
(while (re-search-forward (concat "^[ \t]+\\|^[ \t]*"
TeX-comment-start-regexp
"+[ \t]*") to t)
(delete-region (match-beginning 0) (match-end 0))))))
(setq from (point))
;; FROM, and point, are now before the text to fill,
;; but after any fill prefix on the first line.
(LaTeX-fill-delete-newlines from to justify nosqueeze squeeze-after)
;; This is the actual FILLING LOOP.
(goto-char from)
(let* (linebeg
(code-comment-start (save-excursion
(LaTeX-back-to-indentation)
(TeX-search-forward-comment-start
(line-end-position))))
(end-marker (save-excursion
(goto-char (or code-comment-start to))
(point-marker)))
(LaTeX-current-environment (LaTeX-current-environment)))
;; Fill until point is greater than the end point. If there
;; is a code comment, use the code comment's start as a
;; limit.
(while (and (< (point) (marker-position end-marker))
(or (not code-comment-start)
(and code-comment-start
(> (- (marker-position end-marker)
(line-beginning-position))
fill-column))))
(setq linebeg (point))
(move-to-column (current-fill-column))
(if (when (< (point) (marker-position end-marker))
;; Find the position where we'll break the line.
(forward-char 1) ; Use an immediately following
; space, if any.
(LaTeX-fill-move-to-break-point linebeg)
;; Check again to see if we got to the end of
;; the paragraph.
(skip-chars-forward " \t")
(< (point) (marker-position end-marker)))
;; Found a place to cut.
(progn
(LaTeX-fill-newline)
(when justify
;; Justify the line just ended, if desired.
(save-excursion
(forward-line -1)
(justify-current-line justify nil t))))
(goto-char end-marker)
;; Justify this last line, if desired.
(if justify (justify-current-line justify t t))))
;; Fill a code comment if necessary. (Enable this code if
;; you want the comment part in lines with code comments to
;; be filled. Originally it was disabled because the
;; indentation code indented the lines following the line
;; with the code comment to the column of the comment
;; starters. That means, it would have looked like this:
;; | code code code % comment
;; | % comment
;; | code code code
;; This now (2005-07-29) is not the case anymore. But as
;; filling code comments like this would split a single
;; paragraph into two separate ones, we still leave it
;; disabled. I leave the code here in case it is useful for
;; somebody.
;; (when (and code-comment-start
;; (> (- (line-end-position) (line-beginning-position))
;; fill-column))
;; (LaTeX-fill-code-comment justify))
;; The following is an alternative strategy to minimize the
;; occurence of overfull lines with code comments. A line
;; will be broken before the last non-comment word if the
;; code comment does not fit into the line.
(when (and LaTeX-fill-break-before-code-comments
code-comment-start
(> (- (line-end-position) (line-beginning-position))
fill-column))
(beginning-of-line)
(goto-char end-marker)
(while (not (looking-at TeX-comment-start-regexp)) (forward-char))
(skip-chars-backward " \t")
(skip-chars-backward "^ \t\n")
(unless (or (bolp)
;; Comment starters and whitespace.
(TeX-looking-at-backward
(concat "^\\([ \t]*" TeX-comment-start-regexp "+\\)*"
"[ \t]*")
(line-beginning-position)))
(LaTeX-fill-newline)))))
;; Leave point after final newline.
(goto-char to)
(unless (eobp) (forward-char 1))
;; Return the fill-prefix we used
fill-prefix)))
;; Following lines are copied from `fill.el' (CVS Emacs, March 2005).
;; The `fill-space' property carries the string with which a newline should be
;; replaced when unbreaking a line (in fill-delete-newlines). It is added to
;; newline characters by fill-newline when the default behavior of
;; fill-delete-newlines is not what we want.
(unless (featurep 'xemacs)
;; COMPATIBILITY for Emacs < 22.1
(add-to-list 'text-property-default-nonsticky '(fill-space . t)))
(defun LaTeX-fill-delete-newlines (from to justify nosqueeze squeeze-after)
;; COMPATIBILITY for Emacs < 22.1 and XEmacs
(if (fboundp 'fill-delete-newlines)
(fill-delete-newlines from to justify nosqueeze squeeze-after)
(if (featurep 'xemacs)
(when (featurep 'mule)
(goto-char from)
(let ((unwished-newline (concat LaTeX-nospace-between-char-regexp "\n"
LaTeX-nospace-between-char-regexp)))
(while (re-search-forward unwished-newline to t)
(skip-chars-backward "^\n")
(delete-char -1))))
;; This else-sentence was copied from the function `fill-delete-newlines'
;; in `fill.el' (CVS Emacs, 2005-02-17) and adapted accordingly.
(while (search-forward "\n" to t)
(if (get-text-property (match-beginning 0) 'fill-space)
(replace-match (get-text-property (match-beginning 0) 'fill-space))
(let ((prev (char-before (match-beginning 0)))
(next (following-char)))
(when (or (aref (char-category-set next) ?|)
(aref (char-category-set prev) ?|))
(delete-char -1))))))
;; Make sure sentences ending at end of line get an extra space.
(if (or (not (boundp 'sentence-end-double-space))
sentence-end-double-space)