summaryrefslogtreecommitdiff
path: root/elpa/auctex-13.1.3/texmathp.el
diff options
context:
space:
mode:
Diffstat (limited to 'elpa/auctex-13.1.3/texmathp.el')
-rw-r--r--elpa/auctex-13.1.3/texmathp.el438
1 files changed, 438 insertions, 0 deletions
diff --git a/elpa/auctex-13.1.3/texmathp.el b/elpa/auctex-13.1.3/texmathp.el
new file mode 100644
index 0000000..f02824c
--- /dev/null
+++ b/elpa/auctex-13.1.3/texmathp.el
@@ -0,0 +1,438 @@
+;;; texmathp.el -- Code to check if point is inside LaTeX math environment -*- lexical-binding: t; -*-
+
+;; Copyright (C) 1998-2021 Free Software Foundation, Inc.
+
+;; Author: Carsten Dominik <dominik@strw.LeidenUniv.nl>
+;; 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 code provides a function to determine if point in a buffer is
+;; inside a (La)TeX math environment. This is not trivial since many
+;; different ways are used to switch between the two. Examples:
+;;
+;; \begin{equation} ... \end{equation}
+;; $ ... $
+;; $$ ... $$
+;; \[ ... \]
+;; \ensuremath{...}
+;; \mbox{...}
+;;
+;; To install, put this file on your load-path and compile it.
+;;
+;; To use this in a Lisp program, do
+;;
+;; (require 'texmathp)
+;;
+;; You can then write code like this:
+;;
+;; (if (texmathp) ...)
+;;
+;; The call to `texmathp' leaves some extra information in the
+;; variable `texmathp-why'. It's value is a cons cell (MATCH . POSITION),
+;; specifying which command at what position is responsible for math
+;; mode being on or off.
+;;
+;; To configure which macros and environments influence LaTeX math
+;; mode, customize the variable `texmathp-tex-commands'. By default
+;; it recognizes the plain TeX and LaTeX core as well as AMS-LaTeX
+;; and packages mathtools, empheq and breqn (see the variable
+;; `texmathp-tex-commands-default', also as an example).
+;;
+;; To try out the code interactively, use `M-x texmathp RET'.
+;;
+;; Of course, in order to work this function has to assume that the
+;; LaTeX above point is syntactically correct. In particular:
+;;
+;; o The different math delimiters are paired correctly. Thus if
+;; you do things like "\begin{equation} $" or "\[ ... \)"
+;; the result of (texmathp) is undefined. It is in fact possible
+;; in LaTeX to pair \[ with $$ and \( with $, but this will confuse
+;; texmathp (and human readers as well).
+;;
+;; o However, texmathp will correctly work with nested delimiters.
+;; Something like the following will be parsed correctly at any point:
+;;
+;; \begin{equation}
+;; x = y \mbox{abc \ensuremath{\alpha} cba $2^3$}
+;; \end{equation}
+;;
+;; o texmathp is somewhat forgiving if you have an empty line inside
+;; the current math environment, which is not legal in TeX but may
+;; easily happen during editing. Depending upon the variable
+;; `texmathp-search-n-paragraphs' several paragraphs are checked
+;; backwards, by default 2. Paragraph here means something limited
+;; by an empty line.
+;;--------------------------------------------------------------------------
+;;
+;; BUGS:
+;;
+;; If any of the the special macros like \mbox or \ensuremath has optional
+;; arguments, math mode inside these optional arguments is *not* influenced
+;; by the macro.
+;;
+;; Nested \(\) and \[\] can confuse texmathp. It returns nil at AAA
+;; in the following examples:
+;; \[ x=y \mbox{abc \(\alpha\) cba} AAA \]
+;; \[ x=y \begin{minipage}{3cm} abc \[\alpha\] cba \end{minipage} AAA \]
+;;--------------------------------------------------------------------------
+
+;;; Code:
+
+(defgroup texmathp nil
+ "Testing TeX and LaTeX documents for math mode."
+ :tag "Test For TeX and LaTeX Math Mode"
+ :prefix "texmathp-"
+ :group 'tex)
+
+;; Some internal variables which are computed from `texmathp-tex-commands'
+;; and `texmathp-tex-commands-default'.
+(defvar texmathp-environments nil)
+(defvar texmathp-macros nil)
+(defvar texmathp-onoff-regexp nil)
+(defvar texmathp-toggle-regexp nil)
+(defvar texmathp-tex-commands1 nil)
+(defvar texmathp-memory nil)
+
+(defvar texmathp-tex-commands) ; silence the compiler
+
+(defvar texmathp-tex-commands-default
+ '(;; Plain TeX
+ ("$$" sw-toggle) ("$" sw-toggle)
+ ("\\hbox" arg-off)
+ ("\\vbox" arg-off)
+ ("\\vtop" arg-off)
+ ("\\vcenter" arg-off)
+
+ ;; Standard LaTeX
+ ("equation" env-on)
+ ("eqnarray" env-on) ("eqnarray*" env-on)
+ ("math" env-on)
+ ("displaymath" env-on)
+ ("minipage" env-off)
+ ("\\fbox" arg-off)
+ ("\\mbox" arg-off)
+ ("\\framebox" arg-off)
+ ("\\label" arg-off)
+ ("\\textrm" arg-off)
+ ("\\(" sw-on) ("\\)" sw-off)
+ ("\\[" sw-on) ("\\]" sw-off)
+ ("\\ensuremath" arg-on)
+
+ ;; AMS-LaTeX
+ ("equation*" env-on)
+ ("align" env-on) ("align*" env-on)
+ ("gather" env-on) ("gather*" env-on)
+ ("multline" env-on) ("multline*" env-on)
+ ("flalign" env-on) ("flalign*" env-on)
+ ("alignat" env-on) ("alignat*" env-on)
+ ("xalignat" env-on) ("xalignat*" env-on)
+ ("xxalignat" env-on) ("\\boxed" arg-on)
+ ("\\text" arg-off) ("\\intertext" arg-off)
+ ("\\tag" arg-off) ("\\tag*" arg-off)
+
+ ;; mathtools
+ ("\\shortintertext" arg-off)
+
+ ;; empheq
+ ("empheq" env-on)
+ ("AmSequation" env-on) ("AmSequation*" env-on)
+ ("AmSalign" env-on) ("AmSalign*" env-on)
+ ("AmSgather" env-on) ("AmSgather*" env-on)
+ ("AmSmultline" env-on) ("AmSmultline*" env-on)
+ ("AmSflalign" env-on) ("AmSflalign*" env-on)
+ ("AmSalignat" env-on) ("AmSalignat*" env-on)
+
+ ;; breqn
+ ("dmath" env-on) ("dmath*" env-on)
+ ("dseries" env-on) ("dseries*" env-on)
+ ("dgroup" env-on) ("dgroup*" env-on)
+ ("darray" env-on) ("darray*" env-on)
+ ("dsuspend" env-off))
+ "The default entries for `texmathp-tex-commands', which see.")
+
+(defun texmathp-compile ()
+ "Compile the value of `texmathp-tex-commands' into the internal lists.
+Call this when you have changed the value of that variable without using
+customize (customize calls it when setting the variable)."
+ (interactive)
+ ;; Extract lists and regexp.
+ (setq texmathp-macros nil texmathp-environments nil)
+ (setq texmathp-memory
+ (cons texmathp-tex-commands texmathp-tex-commands-default))
+ (setq texmathp-tex-commands1 (append texmathp-tex-commands
+ texmathp-tex-commands-default))
+ (let ((list (reverse texmathp-tex-commands1))
+ entry type switches togglers)
+ (while (setq entry (car list))
+ (setq type (nth 1 entry)
+ list (cdr list))
+ (cond ((memq type '(env-on env-off)) (push (car entry) texmathp-environments))
+ ((memq type '(arg-on arg-off)) (push (car entry) texmathp-macros))
+ ((memq type '(sw-on sw-off)) (push (car entry) switches))
+ ((memq type '(sw-toggle)) (push (car entry) togglers))))
+ (setq texmathp-onoff-regexp
+ (concat "\\(?:[^\\]\\|\\`\\)"
+ (regexp-opt switches t))
+ texmathp-toggle-regexp
+ (concat "\\([^\\$]\\|\\`\\)"
+ (regexp-opt togglers t)))))
+
+(defcustom texmathp-tex-commands nil
+ "List of environments and macros influencing (La)TeX math mode.
+This user-defined list is used in addition to LaTeX and AMSLaTeX defaults.
+The structure of each entry is (NAME TYPE)
+
+- The first item in each entry is the name of an environment or macro.
+ If it's a macro, include the backslash.
+
+- The second item is a symbol indicating how the command works:
+ `env-on' Environment: turns math mode for its body on
+ `env-off' Environment: turns math mode for its body off
+ `arg-on' Command: turns math mode for its arguments on
+ `arg-off' Command: turns math mode for its arguments off
+ `sw-on' Switch: turns math-mode of following text on
+ `sw-off' Switch: turns math-mode of following text off
+ `sw-toggle' Switch: toggles math mode of following text"
+ :set (lambda (symbol value) (set-default symbol value) (texmathp-compile))
+ :type
+ '(repeat
+ (list :value ("" env-on)
+ (string :tag "Name")
+ (choice :tag "Type"
+ (const :tag "Environment: turns math mode for its body on" env-on)
+ (const :tag "Environment: turns math mode for its body off" env-off)
+ (const :tag "Command: turns math mode for its argument on" arg-on)
+ (const :tag "Command: turns math-mode for its argument off" arg-off)
+ (const :tag "Switch: turns math-mode of following text on" sw-on)
+ (const :tag "Switch: turns math-mode of following text off" sw-off)
+ (const :tag "Switch: toggles math mode of following text" sw-toggle)))))
+
+(defcustom texmathp-search-n-paragraphs 2
+ "Number of paragraphs to check before point.
+Normally, you cannot have an empty line in a math environment in (La)TeX.
+The fastest method to test for math mode is then limiting the search
+backward to the nearest empty line.
+However, during editing it happens that such lines exist temporarily.
+Therefore we look a little further. This variable determines how many
+empty lines we go back to fix the search limit."
+ :type 'number)
+
+(defcustom texmathp-allow-detached-args nil
+ "Non-nil means, allow arguments of macros to be detached by whitespace.
+When this is t, `aaa' will be interpreted as an argument of \\bbb in the
+following construct: \\bbb [xxx] {aaa}
+This is legal in TeX. The disadvantage is that any number of braces expressions
+will be considered arguments of the macro independent of its definition."
+ :type 'boolean)
+
+(defvar texmathp-why nil
+ "After a call to `texmathp' this variable shows why math-mode is on or off.
+The value is a cons cell (MATCH . POSITION).
+MATCH is a string like a car of an entry in `texmathp-tex-commands', for
+example \"equation\" or \"\\ensuremath\" or \"\\=\\[\" or \"$\".
+POSITION is the buffer position of the match. If there was no match,
+it points to the limit used for searches, usually two paragraphs up.")
+
+;; We need our own syntax table to play with the syntax of () [] and {}
+;; For speed reasons we define it statically instead of copying it each time.
+(defvar texmathp-syntax-table
+ (let ((table (make-syntax-table)))
+ (mapc (lambda (x) (modify-syntax-entry (car x) (cdr x) table))
+ '((?\\ . "\\") (?\f .">") (?\n . ">") (?% . "<")
+ (?\[ . ".") (?\] . ".") (?\{ . "(}") (?\} . "){")
+ (?\( . ".") (?\) . ".") (?\" . ".") (?& . ".") (?_ . ".")
+ (?@ . "_") (?~ . " ") (?$ . "$") (?' . "w")))
+ table)
+ "Syntax table used while texmathp is parsing.")
+
+;;;###autoload
+(defun texmathp ()
+ "Determine if point is inside (La)TeX math mode.
+Returns t or nil. Additional info is placed into `texmathp-why'.
+The functions assumes that you have (almost) syntactically correct (La)TeX in
+the buffer.
+See the variable `texmathp-tex-commands' about which commands are checked."
+ (interactive)
+ (let* ((pos (point)) math-on sw-match
+ (bound (save-excursion
+ (if (re-search-backward
+ (if (eq major-mode 'doctex-mode)
+ "[\n\r]%*[ \t]*[\n\r]"
+ "[\n\r][ \t]*[\n\r]")
+ nil 1 texmathp-search-n-paragraphs)
+ (match-beginning 0)
+ (point-min))))
+ (mac-match (texmathp-match-macro bound))
+ (env-match (texmathp-match-environment
+ (if (and mac-match (> (cdr mac-match) bound))
+ (cdr mac-match)
+ bound)))
+ (match (cons nil bound)))
+
+ ;; Select the nearer match
+ (and env-match (setq match env-match))
+ ;; Use `>=' instead of `>' in case called inside \ensuremath{..}
+ ;; beginning just at (point-min).
+ (and mac-match (>= (cdr mac-match) (cdr match)) (setq match mac-match))
+ (setq math-on (memq (nth 1 (assoc (car match) texmathp-tex-commands1))
+ '(env-on arg-on)))
+
+ ;; Check for switches
+ (and (not math-on)
+ (setq sw-match (texmathp-match-switch bound))
+ ;; Use `>=' instead of `>' by similar reason as above. (bug#41559)
+ (>= (cdr sw-match) (cdr match))
+ (eq (nth 1 (assoc (car sw-match) texmathp-tex-commands1)) 'sw-on)
+ (setq match sw-match math-on t))
+
+ ;; Check for togglers
+ (if (not math-on)
+ (save-excursion
+ (goto-char (cdr match))
+ (while (re-search-forward texmathp-toggle-regexp pos t)
+ (if (setq math-on (not math-on))
+ (setq sw-match (cons (match-string-no-properties 2) (match-beginning 2)))
+ (setq sw-match nil)))
+ (and math-on sw-match (setq match sw-match))))
+
+ ;; Store info, show as message when interactive, and return
+ (setq texmathp-why match)
+ (and (called-interactively-p 'any)
+ (message "math-mode is %s: %s begins at buffer position %d"
+ (if math-on "on" "off")
+ (or (car match) "new paragraph")
+ (cdr match)))
+ (and math-on t)))
+
+(defun texmathp-match-environment (bound)
+ "Find out if point is inside any of the math environments.
+Limit searched to BOUND. The return value is like (\"equation\" . (point))."
+ (catch 'exit
+ (save-excursion
+ (and (null texmathp-environments) (throw 'exit nil))
+ ;; Check if the line we are starting with is a commented one.
+ (let ((orig-comment-flag
+ ;; Could be replaced by `TeX-in-commented-line'.
+ (progn
+ (save-excursion
+ (beginning-of-line)
+ (skip-chars-forward " \t")
+ (string= (buffer-substring-no-properties
+ (point) (min (point-max)
+ (+ (point) (length comment-start))))
+ comment-start))))
+ end-list env)
+ (while (re-search-backward "\\\\\\(begin\\|end\\)[ \t]*{\\([^}]+\\)}"
+ bound t)
+ ;; Check if the match found is inside of a comment.
+ (let ((current-comment-flag
+ ;; Could be replaced by `TeX-in-comment'.
+ (when (save-match-data
+ (re-search-backward comment-start-skip
+ (line-beginning-position) t))
+ ;; We need a t for comparison with `orig-comment-flag',
+ ;; not a number.
+ t)))
+ ;; Only consider matching alternatives with respect to
+ ;; "in-commentness", i.e. if we started with a comment
+ ;; only consider matches which are in comments as well and
+ ;; vice versa.
+ (when (eq orig-comment-flag current-comment-flag)
+ (setq env (buffer-substring-no-properties
+ (match-beginning 2) (match-end 2)))
+ (cond ((string= (match-string-no-properties 1) "end")
+ (setq end-list (cons env end-list)))
+ ((equal env (car end-list))
+ (setq end-list (cdr end-list)))
+ ((member env texmathp-environments)
+ (throw 'exit (cons env (point))))))))
+ nil))))
+
+(defun texmathp-match-macro (bound)
+ "Find out if point is within the arguments of any of the Math macros.
+Limit searches to BOUND. The return value is like (\"\\macro\" . (point))."
+ (catch 'exit
+ (and (null texmathp-macros) (throw 'exit nil))
+ (let (pos cmd (syntax-table (syntax-table)))
+ (unwind-protect
+ (save-restriction
+ (save-excursion
+ (set-syntax-table texmathp-syntax-table)
+ (narrow-to-region (max 1 bound) (point))
+ ;; Move back out of the current parenthesis
+ (while (condition-case nil (progn (up-list -1) t) (error nil))
+ ;; Move back over any touching sexps (in fact also non-touching)
+ (while
+ (and
+ (cond
+ ((memq (preceding-char) '(?\] ?\})))
+ ((and
+ texmathp-allow-detached-args
+ (re-search-backward
+ "[]}][ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*\\="
+ bound t))
+ (goto-char (1+ (match-beginning 0))) t))
+ (if (eq (preceding-char) ?\})
+ ;; Jump back over {}
+ (condition-case nil
+ (progn (backward-sexp) t)
+ (error nil))
+ ;; Jump back over []. Modify syntax temporarily for this.
+ (unwind-protect
+ (progn
+ (modify-syntax-entry ?\{ ".")
+ (modify-syntax-entry ?\} ".")
+ (modify-syntax-entry ?\[ "(]")
+ (modify-syntax-entry ?\] ")[")
+ (condition-case nil
+ (progn (backward-sexp) t)
+ (error nil)))
+ (modify-syntax-entry ?\{ "(}")
+ (modify-syntax-entry ?\} "){")
+ (modify-syntax-entry ?\[ ".")
+ (modify-syntax-entry ?\] ".")
+ nil))))
+ (setq pos (point))
+ (and (memq (following-char) '(?\[ ?\{))
+ (re-search-backward "\\\\[*a-zA-Z]+\\=" nil t)
+ (setq cmd (buffer-substring-no-properties
+ (match-beginning 0) (match-end 0)))
+ (member cmd texmathp-macros)
+ (throw 'exit (cons cmd (point))))
+ (goto-char pos))
+ (throw 'exit nil)))
+ (set-syntax-table syntax-table)))))
+
+;;;###autoload
+(defun texmathp-match-switch (bound)
+ "Search backward for any of the math switches.
+Limit searched to BOUND."
+ ;; The return value is like ("\\(" . (point)).
+ (save-excursion
+ (if (re-search-backward texmathp-onoff-regexp bound t)
+ (cons (buffer-substring-no-properties (match-beginning 1) (match-end 1))
+ (match-beginning 1))
+ nil)))
+
+(provide 'texmathp)
+
+;;; texmathp.el ends here