emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/cdlatex 7ce2c74171 07/49: Add texmathp.el


From: ELPA Syncer
Subject: [nongnu] elpa/cdlatex 7ce2c74171 07/49: Add texmathp.el
Date: Mon, 11 Jul 2022 02:58:31 -0400 (EDT)

branch: elpa/cdlatex
commit 7ce2c74171c6d1abd1e7f2325bab78e54aded29a
Author: Carsten Dominik <dominik@wcw-staff-145-18-168-40.wireless.uva.nl>
Commit: Carsten Dominik <dominik@wcw-staff-145-18-168-40.wireless.uva.nl>

    Add texmathp.el
---
 texmathp.el | 406 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 406 insertions(+)

diff --git a/texmathp.el b/texmathp.el
new file mode 100644
index 0000000000..b6b6f43128
--- /dev/null
+++ b/texmathp.el
@@ -0,0 +1,406 @@
+;;; texmathp.el -- Code to check if point is inside LaTeX math environment
+;; Copyright (c) 1998, 2005 Carsten Dominik
+
+;; Author: Carsten Dominik <dominik@science.uva.nl>
+;; Keywords: tex
+;; Version: 1.2
+;;
+;; New versions: http://www.astro.uva.nl/~dominik/Tools
+;;
+;; This file is not part of GNU Emacs
+;;
+;; COPYRIGHT NOTICE
+;;
+;; This program 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 2 of the License, or (at your option)
+;; any later version.
+;;
+;; This program 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 GNU Emacs.  If you did not, write to the Free Software Foundation,
+;; Inc., 675 Mass Ave., Cambridge, MA 02139, 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, for example:
+;;
+;;    \begin{equation}  ... \end{equation}
+;;    $ ... $
+;;    $$ ... $$
+;;    \[ ... \]
+;;    \ensuremath{...}
+;;    \mbox{...}
+;;
+;;  To install, put this file on your load-path and compile it.
+;;
+;;  To use this in your 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 LaTeX core as well as AMS-LaTeX (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,
+;;    e.g. something like this 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' we check several paragraphs,
+;;    backwards, by default 2.  Paragraph here means something limited
+;;    by an empty line.
+;;
+;;--------------------------------------------------------------------------
+;;  CHANGES
+;;
+;;  Version 1.2
+;;  - improved handling of commented lines
+;;
+;;--------------------------------------------------------------------------
+;;
+;;  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.
+;;--------------------------------------------------------------------------
+
+;;; Code:
+
+(provide 'texmathp)
+
+(defgroup texmathp nil
+  "Testing TeX and LaTeX documents for math mode."
+  :tag "Test For TeX and LaTeX Math Mode"
+  :prefix "texmathp-"
+  :group 'tex)
+
+(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"
+  :group 'texmathp
+  :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)))))
+
+(defconst texmathp-tex-commands-default
+  '(;; Standard LaTeX
+    ("equation"      env-on)
+    ("eqnarray"      env-on)      ("eqnarray*"     env-on)
+    ("displaymath"   env-on)
+    ("\\mbox"        arg-off)
+    ("\\("           sw-on)       ("\\)"           sw-off)
+    ("\\["           sw-on)       ("\\]"           sw-off)
+    ("$$"            sw-toggle)   ("$"             sw-toggle)
+    ;; 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)      ("xxalignat*"    env-on)
+    ("\\ensuremath"  arg-on)
+    ("\\text"        arg-off)     ("\\intertext"   arg-off))
+  "The default entries for `texmathp-tex-commands', which see.")
+
+(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.
+Therefore, the fastest method to test for math mode is 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."
+  :group 'texmathp
+  :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 considered as argument of \bb in the following
+construct:  \bbb [xxx] {aaa}
+The disadvantage is that any number of braces expressions will be considered
+arguments of the macro independent of its definition."
+  :group 'texmathp
+  :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', e.q.
+\"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.")
+
+(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)
+
+;; 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 (make-syntax-table)
+  "Syntax table used while texmathp is parsing.")
+(mapcar
+ (lambda (x) (modify-syntax-entry (car x) (cdr x) texmathp-syntax-table))
+ '((?\\ . "\\") (?\f .">") (?\n . ">") (?% . "<")
+   (?\[ . ".") (?\] . ".") (?\{ . "(}") (?\} . "){")
+   (?\( . ".") (?\) . ".") (?\" . ".") (?& . ".") (?_ . ".")
+   (?@ . "_") (?~ . " ") (?$ . "$") (?' . "w")))
+
+(defun texmathp-compile ()
+  "Compile the value of `texmathp-tex-commands' into the internal lists."
+
+  ;; 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))
+       var entry type switches togglers)
+    (while (setq entry (car list))
+      (setq type (nth 1 entry)
+           list (cdr list)
+           var (cond ((memq type '(env-on env-off)) 'texmathp-environments)
+                     ((memq type '(arg-on arg-off)) 'texmathp-macros)
+                     ((memq type '(sw-on sw-off))   'switches)
+                     ((memq type '(sw-toggle))      'togglers)))
+      (set var (cons (car entry) (symbol-value var))))
+    (setq texmathp-onoff-regexp
+         (concat "[^\\\\]\\(" 
+                 (mapconcat 'regexp-quote switches "\\|")
+                 "\\)")
+         texmathp-toggle-regexp
+         (concat "\\([^\\\\\\$]\\|\\`\\)\\("
+                 (mapconcat 'regexp-quote togglers "\\|")
+                 "\\)"))))
+
+(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)
+  (unless (and (eq (car texmathp-memory) texmathp-tex-commands)
+              (eq (cdr texmathp-memory) texmathp-tex-commands-default))
+    (texmathp-compile))
+  (let* ((pos (point)) math-on sw-match
+        (bound (save-excursion
+                 (if (re-search-backward "[\n\t][ \t]*[\n\r]"
+                                         nil 1 texmathp-search-n-paragraphs)
+                     (match-beginning 0)
+                   (point-min))))
+        (env-match (texmathp-match-environment bound))
+        (mac-match (texmathp-match-macro bound))
+        (match (cons nil bound)))
+
+    ;; Select the nearer match
+    (and env-match (setq match env-match))
+    (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))
+        (> (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)
+           (unless (texmathp-comment-p)
+             (if (setq math-on (not math-on))
+                 (setq sw-match (cons (match-string 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 (interactive-p)
+        (message "math-mode is %s: %s begins at buffer position %d"
+                 (if math-on "on" "off")
+                 (or (car match) "new paragraph") (cdr match))
+        (save-excursion (goto-char (cdr match)) (sit-for 2)))
+    (and math-on t)))
+
+(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 (progn
+                      (modify-syntax-entry ?\{ "(}")
+                      (modify-syntax-entry ?\} "){")
+                      (modify-syntax-entry ?\[ ".")
+                      (modify-syntax-entry ?\] ".")
+                      (condition-case nil 
+                          (progn (up-list -1) (not (texmathp-comment-p)))
+                        (error (progn nil))))
+               ;; Move back over 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))
+                    (progn
+                      (if (eq (preceding-char) ?\})
+                          (progn
+                            ;; skip {}
+                            (modify-syntax-entry ?\{ "(}")
+                            (modify-syntax-entry ?\} "){")
+                            (modify-syntax-entry ?\[ ".")
+                            (modify-syntax-entry ?\] "."))
+                        ;; skip []
+                        (modify-syntax-entry ?\{ ".")
+                        (modify-syntax-entry ?\} ".")
+                        (modify-syntax-entry ?\[ "(]")
+                        (modify-syntax-entry ?\] ")["))
+                      (condition-case nil 
+                          (progn (backward-sexp) t) (error 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)))))
+
+(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))
+      (let (end-list env)
+       (while (re-search-backward "\\\\\\(begin\\|end\\){\\([^}]+\\)}"
+                                  bound t)
+         (setq env (buffer-substring-no-properties
+                    (match-beginning 2) (match-end 2)))
+         (cond ((texmathp-comment-p))
+               ((string= (match-string 1) "end")
+                (setq end-list (cons env end-list)))
+;               (add-to-list 'end-list env))
+               ((equal env (car end-list))
+                (setq end-list (cdr end-list)))
+               ((member env texmathp-environments)
+                (throw 'exit (cons env (point))))))
+       nil))))
+
+(defun texmathp-match-switch (bound)
+  ;; Search backward for any of the math switches.
+  ;; Limit searched to BOUND.  The return value is like ("\\(" . (point)).
+  (let (match)
+    (save-excursion
+      (setq match (re-search-backward texmathp-onoff-regexp bound t))
+      (while (and (texmathp-comment-p)
+                 (or (backward-char 1) t)
+                 (setq match
+                       (re-search-backward texmathp-onoff-regexp bound t))))
+      (if match
+         (cons (buffer-substring-no-properties
+                (match-beginning 1) (match-end 1))
+               (match-beginning 1))
+       nil))))
+
+(defun texmathp-comment-p (&optional pos)
+  "Is position POS inside a comment?"
+  (let ((pos (or pos (point))))
+    (save-excursion
+      (goto-char pos)
+      (beginning-of-line 1)
+      (catch 'exit
+       (while (skip-chars-forward "^%"  pos)
+         (if (= pos (point)) (throw 'exit nil))
+         (if (not (equal (char-before) ?\\))
+             (throw 'exit t)
+           (forward-char 1)))
+       nil))))
+
+(defun texmathp-test-comment ()
+  (interactive)
+  (message "%s" (texmathp-comment-p (point))))
+  
+
+;;; texmathp.el end here
+



reply via email to

[Prev in Thread] Current Thread [Next in Thread]