summaryrefslogtreecommitdiff
path: root/elpa/auctex-13.1.3/tex-fold.el
diff options
context:
space:
mode:
Diffstat (limited to 'elpa/auctex-13.1.3/tex-fold.el')
-rw-r--r--elpa/auctex-13.1.3/tex-fold.el948
1 files changed, 948 insertions, 0 deletions
diff --git a/elpa/auctex-13.1.3/tex-fold.el b/elpa/auctex-13.1.3/tex-fold.el
new file mode 100644
index 0000000..6d50f31
--- /dev/null
+++ b/elpa/auctex-13.1.3/tex-fold.el
@@ -0,0 +1,948 @@
+;;; tex-fold.el --- Fold TeX macros. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2004-2022 Free Software Foundation, Inc.
+
+;; Author: Ralf Angeli <angeli@caeruleus.net>
+;; Maintainer: auctex-devel@gnu.org
+;; Created: 2004-07-04
+;; Keywords: tex, wp
+
+;; 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 support for hiding and unhiding TeX, LaTeX,
+;; ConTeXt, Texinfo and similar macros and environments inside of
+;; AUCTeX.
+;;
+;; Caveats:
+;;
+;; The display string of content which should display part of itself
+;; is made by copying the text from the buffer together with its text
+;; properties. If fontification has not happened when this is done
+;; (e.g. because of lazy or just-in-time font locking) the intended
+;; fontification will not show up. Maybe this could be improved by
+;; using some sort of "lazy folding" or refreshing the window upon
+;; scrolling. As a workaround fontification of the whole buffer
+;; currently is forced before folding it.
+
+;;; Code:
+
+(eval-when-compile
+ (require 'cl-lib))
+
+(require 'tex)
+(autoload 'LaTeX-forward-paragraph "latex")
+(autoload 'LaTeX-backward-paragraph "latex")
+(autoload 'LaTeX-find-matching-begin "latex")
+(autoload 'LaTeX-find-matching-end "latex")
+(autoload 'ConTeXt-find-matching-start "context")
+(autoload 'ConTeXt-find-matching-stop "context")
+(autoload 'Texinfo-find-env-start "tex-info")
+(autoload 'Texinfo-find-env-end "tex-info")
+
+(defgroup TeX-fold nil
+ "Fold TeX macros."
+ :group 'AUCTeX)
+
+(defcustom TeX-fold-type-list '(env macro math)
+ "List of item types to consider when folding.
+Valid items are the symbols `env' for environments, `macro' for
+macros, `math' for math macros and `comment' for comments."
+ :type '(set (const :tag "Environments" env)
+ (const :tag "Macros" macro)
+ (const :tag "Math Macros" math)
+ (const :tag "Comments" comment)))
+
+(defcustom TeX-fold-macro-spec-list
+ '(("[f]" ("footnote" "marginpar"))
+ ("[c]" ("cite"))
+ ("[l]" ("label"))
+ ("[r]" ("ref" "pageref" "eqref" "footref"))
+ ("[i]" ("index" "glossary"))
+ ("[1]:||*" ("item"))
+ ("..." ("dots"))
+ ("(C)" ("copyright"))
+ ("(R)" ("textregistered"))
+ ("TM" ("texttrademark"))
+ (1 ("part" "chapter" "section" "subsection" "subsubsection"
+ "paragraph" "subparagraph"
+ "part*" "chapter*" "section*" "subsection*" "subsubsection*"
+ "paragraph*" "subparagraph*"
+ "emph" "textit" "textsl" "textmd" "textrm" "textsf" "texttt"
+ "textbf" "textsc" "textup")))
+ "List of replacement specifiers and macros to fold.
+
+The first element of each item can be a string, an integer or a
+function symbol. The second element is a list of macros to fold
+without the leading backslash.
+
+If the first element is a string, it will be used as a display
+replacement for the whole macro. Numbers in braces, brackets,
+parens or angle brackets will be replaced by the respective macro
+argument. For example \"{1}\" will be replaced by the first
+mandatory argument of the macro. One can also define
+alternatives within the specifier which are used if an argument
+is not found. Alternatives are separated by \"||\". They are
+most useful with optional arguments. As an example, the default
+specifier for \\item is \"[1]:||*\" which means that if there is
+an optional argument, its value is shown followed by a colon. If
+there is no optional argument, only an asterisk is used as the
+display string.
+
+If the first element is an integer, the macro will be replaced by
+the respective macro argument.
+
+If the first element is a function symbol, the function will be
+called with all mandatory arguments of the macro and the result
+of the function call will be used as a replacement for the macro.
+
+Setting this variable does not take effect immediately. Use
+Customize or reset the mode."
+ :type '(repeat (group (choice (string :tag "Display String")
+ (integer :tag "Number of argument" :value 1)
+ (function :tag "Function to execute"))
+ (repeat :tag "Macros" (string)))))
+
+(defvar TeX-fold-macro-spec-list-internal nil
+ "Internal list of display strings and macros to fold.
+Is updated when the TeX Fold mode is being activated and then
+contains all constructs to fold for the given buffer or mode
+respectively, that is, contents of both `TeX-fold-macro-spec-list'
+and <mode-prefix>-fold-macro-spec-list.")
+(make-variable-buffer-local 'TeX-fold-macro-spec-list-internal)
+
+(defcustom TeX-fold-env-spec-list
+ '(("[comment]" ("comment")))
+ "List of display strings and environments to fold."
+ :type '(repeat (group (choice (string :tag "Display String")
+ (integer :tag "Number of argument" :value 1))
+ (repeat :tag "Environments" (string)))))
+
+(defvar TeX-fold-env-spec-list-internal nil
+ "Internal list of display strings and environments to fold.
+Is updated when the TeX Fold mode is being activated and then
+contains all constructs to fold for the given buffer or mode
+respectively, that is, contents of both `TeX-fold-env-spec-list'
+and <mode-prefix>-fold-env-spec-list.")
+(make-variable-buffer-local 'TeX-fold-env-spec-list-internal)
+
+(defcustom TeX-fold-math-spec-list nil
+ "List of display strings and math macros to fold."
+ :type '(repeat (group (choice (string :tag "Display String")
+ (integer :tag "Number of argument" :value 1))
+ (repeat :tag "Math Macros" (string)))))
+
+(defvar TeX-fold-math-spec-list-internal nil
+ "Internal list of display strings and math macros to fold.
+Is updated when the TeX Fold mode is being activated and then
+contains all constructs to fold for the given buffer or mode
+respectively, that is, contents of both `TeX-fold-math-spec-list'
+and <mode-prefix>-fold-math-spec-list.")
+(make-variable-buffer-local 'TeX-fold-math-spec-list-internal)
+
+(defcustom TeX-fold-unspec-macro-display-string "[m]"
+ "Display string for unspecified macros.
+This string will be displayed if a single macro is being hidden
+which is not specified in `TeX-fold-macro-spec-list'."
+ :type '(string))
+
+(defcustom TeX-fold-unspec-env-display-string "[env]"
+ "Display string for unspecified environments.
+This string will be displayed if a single environment is being
+hidden which is not specified in `TeX-fold-env-spec-list'."
+ :type '(string))
+
+(defcustom TeX-fold-unspec-use-name t
+ "If non-nil use the name of an unspecified item as display string.
+Set it to nil if you want to use the values of the variables
+`TeX-fold-unspec-macro-display-string' or
+`TeX-fold-unspec-env-display-string' respectively as a display
+string for any unspecified macro or environment."
+ :type 'boolean)
+
+(defcustom TeX-fold-preserve-comments nil
+ "If non-nil do not fold in comments."
+ :type 'boolean)
+
+(defcustom TeX-fold-unfold-around-mark t
+ "Unfold text around the mark, if active."
+ :type 'boolean)
+
+(defcustom TeX-fold-help-echo-max-length 70
+ "Maximum length of help echo message for folded overlays.
+Set it to zero in order to disable help echos."
+ :type 'integer)
+
+(defcustom TeX-fold-force-fontify t
+ "Force the buffer to be fully fontified by folding it."
+ :type 'boolean)
+
+(defcustom TeX-fold-auto nil
+ "If non-nil, fold macros automatically after `TeX-insert-macro'."
+ :type 'boolean)
+
+(defface TeX-fold-folded-face
+ '((((class color) (background light))
+ (:foreground "SlateBlue"))
+ (((class color) (background dark))
+ (:foreground "SlateBlue1"))
+ (((class grayscale) (background light))
+ (:foreground "DimGray"))
+ (((class grayscale) (background dark))
+ (:foreground "LightGray"))
+ (t (:slant italic)))
+ "Face for the display string of folded content.")
+
+(defvar TeX-fold-folded-face 'TeX-fold-folded-face
+ "Face for the display string of folded content.")
+
+(defface TeX-fold-unfolded-face
+ '((((class color) (background light))
+ (:background "#f2f0fd"))
+ (((class color) (background dark))
+ (:background "#38405d"))
+ (((class grayscale) (background light))
+ (:background "LightGray"))
+ (((class grayscale) (background dark))
+ (:background "DimGray"))
+ (t (:inverse-video t)))
+ "Face for folded content when it is temporarily opened.")
+
+(defvar TeX-fold-unfolded-face 'TeX-fold-unfolded-face
+ "Face for folded content when it is temporarily opened.")
+
+(defvar TeX-fold-ellipsis "..."
+ "String used as display string for overlays instead of a zero-length string.")
+
+(defvar TeX-fold-open-spots nil)
+(make-variable-buffer-local 'TeX-fold-open-spots)
+
+(defcustom TeX-fold-command-prefix "\C-c\C-o"
+ "Prefix key to use for commands in TeX Fold mode.
+The value of this variable is checked as part of loading TeX Fold mode.
+After that, changing the prefix key requires manipulating keymaps."
+ :type 'string)
+
+(defvar TeX-fold-keymap
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\C-o" #'TeX-fold-dwim)
+ (define-key map "\C-b" #'TeX-fold-buffer)
+ (define-key map "\C-r" #'TeX-fold-region)
+ (define-key map "\C-p" #'TeX-fold-paragraph)
+ (define-key map "\C-m" #'TeX-fold-macro)
+ (define-key map "\C-e" #'TeX-fold-env)
+ (define-key map "\C-c" #'TeX-fold-comment)
+ (define-key map "b" #'TeX-fold-clearout-buffer)
+ (define-key map "r" #'TeX-fold-clearout-region)
+ (define-key map "p" #'TeX-fold-clearout-paragraph)
+ (define-key map "i" #'TeX-fold-clearout-item)
+ map))
+
+
+;;; Folding
+
+(defun TeX-fold-dwim ()
+ "Hide or show items according to the current context.
+If there is folded content, unfold it. If there is a marked
+region, fold all configured content in this region. If there is
+no folded content but a macro or environment, fold it."
+ (interactive)
+ (cond ((TeX-fold-clearout-item))
+ ((TeX-active-mark) (TeX-fold-region (mark) (point)))
+ ((TeX-fold-item 'macro))
+ ((TeX-fold-item 'math))
+ ((TeX-fold-item 'env))
+ ((TeX-fold-comment))))
+
+(defun TeX-fold-buffer ()
+ "Hide all configured macros and environments in the current buffer.
+The relevant macros are specified in the variable `TeX-fold-macro-spec-list'
+and `TeX-fold-math-spec-list', and environments in `TeX-fold-env-spec-list'."
+ (interactive)
+ (TeX-fold-clearout-region (point-min) (point-max))
+ (when (and TeX-fold-force-fontify
+ (boundp 'jit-lock-mode)
+ jit-lock-mode
+ (fboundp 'jit-lock-fontify-now))
+ ;; We force fontification here only because it should rarely be
+ ;; needed for the other folding commands.
+ (jit-lock-fontify-now))
+ (TeX-fold-region (point-min) (point-max)))
+
+(defun TeX-fold-paragraph ()
+ "Hide all configured macros and environments in the current paragraph.
+The relevant macros are specified in the variable `TeX-fold-macro-spec-list'
+and `TeX-fold-math-spec-list', and environments in `TeX-fold-env-spec-list'."
+ (interactive)
+ (save-excursion
+ (let ((end (progn (LaTeX-forward-paragraph) (point)))
+ (start (progn (LaTeX-backward-paragraph) (point))))
+ (TeX-fold-clearout-region start end)
+ (TeX-fold-region start end))))
+
+(defun TeX-fold-region (start end)
+ "Fold all items in region from START to END."
+ (interactive "r")
+ (when (and (memq 'env TeX-fold-type-list)
+ (not (eq major-mode 'plain-tex-mode)))
+ (TeX-fold-region-macro-or-env start end 'env))
+ (when (memq 'macro TeX-fold-type-list)
+ (TeX-fold-region-macro-or-env start end 'macro))
+ (when (memq 'math TeX-fold-type-list)
+ (TeX-fold-region-macro-or-env start end 'math))
+ (when (memq 'comment TeX-fold-type-list)
+ (TeX-fold-region-comment start end)))
+
+(defun TeX-fold-region-macro-or-env (start end type)
+ "Fold all items of type TYPE in region from START to END.
+TYPE can be one of the symbols 'env for environments, 'macro
+for macros and 'math for math macros."
+ (save-excursion
+ (let (fold-list item-list regexp)
+ (dolist (item (cond ((eq type 'env) TeX-fold-env-spec-list-internal)
+ ((eq type 'math) TeX-fold-math-spec-list-internal)
+ (t TeX-fold-macro-spec-list-internal)))
+ (dolist (i (cadr item))
+ (cl-pushnew (list i (car item)) fold-list :test #'equal)
+ (cl-pushnew i item-list :test #'equal)))
+ (when item-list
+ (setq regexp (cond ((and (eq type 'env)
+ (eq major-mode 'context-mode))
+ (concat (regexp-quote TeX-esc)
+ "start" (regexp-opt item-list t)))
+ ((and (eq type 'env)
+ (eq major-mode 'texinfo-mode))
+ (concat (regexp-quote TeX-esc)
+ (regexp-opt item-list t)))
+ ((eq type 'env)
+ (concat (regexp-quote TeX-esc)
+ "begin[ \t]*{"
+ (regexp-opt item-list t) "}"))
+ (t
+ (concat (regexp-quote TeX-esc)
+ (regexp-opt item-list t)))))
+ (save-restriction
+ (narrow-to-region start end)
+ ;; Start from the bottom so that it is easier to prioritize
+ ;; nested macros.
+ (goto-char (point-max))
+ (let ((case-fold-search nil)
+ item-name)
+ (while (re-search-backward regexp nil t)
+ (setq item-name (match-string 1))
+ (unless (or (and TeX-fold-preserve-comments
+ (TeX-in-commented-line))
+ ;; Make sure no partially matched macros are
+ ;; folded. For macros consisting of letters
+ ;; this means there should be none of the
+ ;; characters [A-Za-z@*] after the matched
+ ;; string. Single-char non-letter macros like
+ ;; \, don't have this requirement.
+ (and (memq type '(macro math))
+ (save-match-data
+ (string-match "[A-Za-z]" item-name))
+ (save-match-data
+ (string-match "[A-Za-z@*]"
+ (string (char-after
+ (match-end 0)))))))
+ (let* ((item-start (match-beginning 0))
+ (display-string-spec (cadr (assoc item-name
+ fold-list)))
+ (item-end (TeX-fold-item-end item-start type))
+ (ov (TeX-fold-make-overlay item-start item-end type
+ display-string-spec)))
+ (TeX-fold-hide-item ov))))))))))
+
+(defun TeX-fold-region-comment (start end)
+ "Fold all comments in region from START to END."
+ (save-excursion
+ (goto-char start)
+ (let (beg)
+ (while (setq beg (TeX-search-forward-comment-start end))
+ (goto-char beg)
+ ;; Determine the start of the region to be folded just behind
+ ;; the comment starter.
+ (looking-at TeX-comment-start-regexp)
+ (setq beg (match-end 0))
+ ;; Search for the end of the comment.
+ (while (TeX-comment-forward))
+ (end-of-line 0)
+ ;; Hide the whole region.
+ (TeX-fold-hide-item (TeX-fold-make-overlay beg (point) 'comment
+ TeX-fold-ellipsis))))))
+
+(defun TeX-fold-macro ()
+ "Hide the macro on which point currently is located."
+ (interactive)
+ (unless (TeX-fold-item 'macro)
+ (message "No macro found")))
+
+(defun TeX-fold-math ()
+ "Hide the math macro on which point currently is located."
+ (interactive)
+ (unless (TeX-fold-item 'math)
+ (message "No macro found")))
+
+(defun TeX-fold-env ()
+ "Hide the environment on which point currently is located."
+ (interactive)
+ (unless (TeX-fold-item 'env)
+ (message "No environment found")))
+
+(defun TeX-fold-comment ()
+ "Hide the comment on which point currently is located."
+ (interactive)
+ (unless (TeX-fold-comment-do)
+ (message "No comment found")))
+
+(defun TeX-fold-item (type)
+ "Hide the item on which point currently is located.
+TYPE specifies the type of item and can be one of the symbols
+`env' for environments, `macro' for macros or `math' for math
+macros.
+Return non-nil if an item was found and folded, nil otherwise."
+ (if (and (eq type 'env)
+ (eq major-mode 'plain-tex-mode))
+ (message
+ "Folding of environments is not supported in current mode")
+ (let ((item-start (cond ((and (eq type 'env)
+ (eq major-mode 'context-mode))
+ (save-excursion
+ (ConTeXt-find-matching-start) (point)))
+ ((and (eq type 'env)
+ (eq major-mode 'texinfo-mode))
+ (save-excursion
+ (Texinfo-find-env-start) (point)))
+ ((eq type 'env)
+ (condition-case nil
+ (save-excursion
+ (LaTeX-find-matching-begin) (point))
+ (error nil)))
+ (t
+ (TeX-find-macro-start)))))
+ (when item-start
+ (let* ((item-name (save-excursion
+ (goto-char item-start)
+ (looking-at
+ (cond ((and (eq type 'env)
+ (eq major-mode 'context-mode))
+ (concat (regexp-quote TeX-esc)
+ "start\\([A-Za-z]+\\)"))
+ ((and (eq type 'env)
+ (eq major-mode 'texinfo-mode))
+ (concat (regexp-quote TeX-esc)
+ "\\([A-Za-z]+\\)"))
+ ((eq type 'env)
+ (concat (regexp-quote TeX-esc)
+ "begin[ \t]*{"
+ "\\([A-Za-z*]+\\)}"))
+ (t
+ (concat (regexp-quote TeX-esc)
+ "\\([A-Za-z@*]+\\)"))))
+ (match-string-no-properties 1)))
+ (fold-list (cond ((eq type 'env) TeX-fold-env-spec-list-internal)
+ ((eq type 'math)
+ TeX-fold-math-spec-list-internal)
+ (t TeX-fold-macro-spec-list-internal)))
+ fold-item
+ (display-string-spec
+ (or (catch 'found
+ (while fold-list
+ (setq fold-item (car fold-list))
+ (setq fold-list (cdr fold-list))
+ (when (member item-name (cadr fold-item))
+ (throw 'found (car fold-item)))))
+ ;; Item is not specified.
+ (if TeX-fold-unspec-use-name
+ (concat "[" item-name "]")
+ (if (eq type 'env)
+ TeX-fold-unspec-env-display-string
+ TeX-fold-unspec-macro-display-string))))
+ (item-end (TeX-fold-item-end item-start type))
+ (ov (TeX-fold-make-overlay item-start item-end type
+ display-string-spec)))
+ (TeX-fold-hide-item ov))))))
+
+(defun TeX-fold-comment-do ()
+ "Hide the comment on which point currently is located.
+This is the function doing the work for `TeX-fold-comment'. It
+is an internal function communicating with return values rather
+than with messages for the user.
+Return non-nil if a comment was found and folded, nil otherwise."
+ (if (and (not (TeX-in-comment)) (not (TeX-in-line-comment)))
+ nil
+ (let (beg)
+ (save-excursion
+ (while (progn
+ (beginning-of-line 0)
+ (and (TeX-in-line-comment)
+ (not (bobp)))))
+ (goto-char (TeX-search-forward-comment-start (line-end-position 2)))
+ (looking-at TeX-comment-start-regexp)
+ (setq beg (match-end 0))
+ (while (TeX-comment-forward))
+ (end-of-line 0)
+ (when (> (point) beg)
+ (TeX-fold-hide-item (TeX-fold-make-overlay beg (point) 'comment
+ TeX-fold-ellipsis)))))))
+
+
+;;; Utilities
+
+(defun TeX-fold-make-overlay (ov-start ov-end type display-string-spec)
+ "Make a TeX-fold overlay extending from OV-START to OV-END.
+TYPE is a symbol which is used to describe the content to hide
+and may be `macro' for macros, `math' for math macro and `env' for
+environments.
+DISPLAY-STRING-SPEC is the original specification of the display
+string in the variables `TeX-fold-macro-spec-list' or
+`TeX-fold-env-spec-list' and may be a string or an integer."
+ ;; Calculate priority before the overlay is instantiated. We don't
+ ;; want `TeX-overlay-prioritize' to pick up a non-prioritized one.
+ (let ((priority (TeX-overlay-prioritize ov-start ov-end))
+ (ov (make-overlay ov-start ov-end (current-buffer) t nil)))
+ (overlay-put ov 'category 'TeX-fold)
+ (overlay-put ov 'priority priority)
+ (overlay-put ov 'evaporate t)
+ (overlay-put ov 'TeX-fold-type type)
+ (overlay-put ov 'TeX-fold-display-string-spec display-string-spec)
+ ov))
+
+(defun TeX-fold-item-end (start type)
+ "Return the end of an item of type TYPE starting at START.
+TYPE can be either `env' for environments, `macro' for macros or
+`math' for math macros."
+ (save-excursion
+ (cond ((and (eq type 'env)
+ (eq major-mode 'context-mode))
+ (goto-char start)
+ (ConTeXt-find-matching-stop)
+ (point))
+ ((and (eq type 'env)
+ (eq major-mode 'texinfo-mode))
+ (goto-char (1+ start))
+ (Texinfo-find-env-end)
+ (point))
+ ((eq type 'env)
+ (goto-char (1+ start))
+ (LaTeX-find-matching-end)
+ (point))
+ (t
+ (goto-char start)
+ (TeX-find-macro-end)))))
+
+(defun TeX-fold-overfull-p (ov-start ov-end display-string)
+ "Return t if an overfull line will result after adding an overlay.
+The overlay extends from OV-START to OV-END and will display the
+string DISPLAY-STRING."
+ (and
+ (save-excursion
+ (goto-char ov-end)
+ (search-backward "\n" ov-start t))
+ (not (string-match "\n" display-string))
+ (> (+ (- ov-start
+ (save-excursion
+ (goto-char ov-start)
+ (line-beginning-position)))
+ (length display-string)
+ (- (save-excursion
+ (goto-char ov-end)
+ (line-end-position))
+ ov-end))
+ (current-fill-column))))
+
+(defun TeX-fold-macro-nth-arg (n macro-start &optional macro-end delims)
+ "Return a property list of the argument number N of a macro.
+The start of the macro to examine is given by MACRO-START, its
+end optionally by MACRO-END. With DELIMS the type of delimiters
+can be specified as a cons cell containing the opening char as
+the car and the closing char as the cdr. The chars have to have
+opening and closing syntax as defined in
+`TeX-search-syntax-table'.
+
+The first item in the returned list is the string specified in
+the argument, with text properties. The second item is for
+backward compatibility and always nil."
+ (save-excursion
+ (let* ((macro-end (or macro-end
+ (save-excursion (goto-char macro-start)
+ (TeX-find-macro-end))))
+ (open-char (if delims (car delims) ?{))
+ (open-string (char-to-string open-char))
+ (close-char (if delims (cdr delims) ?}))
+ ;; (close-string (char-to-string close-char))
+ content-start content-end)
+ (goto-char macro-start)
+ (if (condition-case nil
+ (progn
+ (while (> n 0)
+ (skip-chars-forward (concat "^" open-string) macro-end)
+ (when (= (point) macro-end)
+ (error nil))
+ (setq content-start (progn
+ (skip-chars-forward
+ (concat open-string " \t"))
+ (point)))
+ (goto-char
+ (if delims
+ (with-syntax-table
+ (TeX-search-syntax-table open-char close-char)
+ (scan-lists (point) 1 1))
+ (TeX-find-closing-brace)))
+ (setq content-end (save-excursion
+ (backward-char)
+ (skip-chars-backward " \t")
+ (point)))
+ (setq n (1- n)))
+ t)
+ (error nil))
+ (list (TeX-fold-buffer-substring content-start content-end))
+ nil))))
+
+(defun TeX-fold-buffer-substring (start end)
+ "Return the contents of buffer from START to END as a string.
+Like `buffer-substring' but copy overlay display strings as well."
+ ;; Swap values of `start' and `end' if necessary.
+ (when (> start end) (let ((tmp start)) (setq start end end tmp)))
+ (let ((overlays (overlays-in start end))
+ result)
+ ;; Get rid of overlays not under our control or not completely
+ ;; inside the specified region.
+ (dolist (ov overlays)
+ (when (or (not (eq (overlay-get ov 'category) 'TeX-fold))
+ (< (overlay-start ov) start)
+ (> (overlay-end ov) end))
+ (setq overlays (remove ov overlays))))
+ (if (null overlays)
+ (buffer-substring start end)
+ ;; Sort list according to ascending starts.
+ (setq overlays (sort (copy-sequence overlays)
+ (lambda (a b)
+ (< (overlay-start a) (overlay-start b)))))
+ ;; Get the string from the start of the region up to the first overlay.
+ (setq result (buffer-substring start (overlay-start (car overlays))))
+ (let (ov)
+ (while overlays
+ (setq ov (car overlays)
+ overlays (cdr overlays))
+ ;; Add the display string of the overlay.
+ (setq result (concat result (overlay-get ov 'display)))
+ ;; Remove overlays contained in the current one.
+ (dolist (elt overlays)
+ (when (< (overlay-start elt) (overlay-end ov))
+ (setq overlays (remove elt overlays))))
+ ;; Add the string from the end of the current overlay up to
+ ;; the next overlay or the end of the specified region.
+ (setq result (concat result (buffer-substring (overlay-end ov)
+ (if overlays
+ (overlay-start
+ (car overlays))
+ end))))))
+ result)))
+
+(defun TeX-fold-make-help-echo (start end)
+ "Return a string to be used as the help echo of folded overlays.
+The text between START and END will be used for this but cropped
+to the length defined by `TeX-fold-help-echo-max-length'. Line
+breaks will be replaced by spaces."
+ (let* ((spill (+ start TeX-fold-help-echo-max-length))
+ (lines (split-string (buffer-substring start (min end spill)) "\n"))
+ (result (pop lines)))
+ (dolist (line lines)
+ ;; Strip leading whitespace
+ (when (string-match "^[ \t]+" line)
+ (setq line (replace-match "" nil nil line)))
+ ;; Strip trailing whitespace
+ (when (string-match "[ \t]+$" line)
+ (setq line (replace-match "" nil nil line)))
+ (setq result (concat result " " line)))
+ (when (> end spill) (setq result (concat result "...")))
+ result))
+
+(defun TeX-fold-update-at-point ()
+ "Update all TeX-fold overlays at point displaying computed content."
+ (let (overlays)
+ ;; Get all overlays at point under our control.
+ (dolist (ov (overlays-at (point)))
+ (when (and (eq (overlay-get ov 'category) 'TeX-fold)
+ (numberp (overlay-get ov 'TeX-fold-display-string-spec)))
+ (cl-pushnew ov overlays)))
+ (when overlays
+ ;; Sort list according to descending starts.
+ (setq overlays (sort (copy-sequence overlays)
+ (lambda (a b)
+ (> (overlay-start a) (overlay-start b)))))
+ (dolist (ov overlays)
+ (TeX-fold-hide-item ov)))))
+
+
+;;; Removal
+
+(defun TeX-fold-clearout-buffer ()
+ "Permanently show all macros in the buffer."
+ (interactive)
+ (TeX-fold-clearout-region (point-min) (point-max)))
+
+(defun TeX-fold-clearout-paragraph ()
+ "Permanently show all macros in the paragraph point is located in."
+ (interactive)
+ (save-excursion
+ (let ((end (progn (LaTeX-forward-paragraph) (point)))
+ (start (progn (LaTeX-backward-paragraph) (point))))
+ (TeX-fold-clearout-region start end))))
+
+(defun TeX-fold-clearout-region (start end)
+ "Permanently show all macros in region starting at START and ending at END."
+ (interactive "r")
+ (let ((overlays (overlays-in start end)))
+ (TeX-fold-remove-overlays overlays)))
+
+(defun TeX-fold-clearout-item ()
+ "Permanently show the macro on which point currently is located."
+ (interactive)
+ (let ((overlays (overlays-at (point))))
+ (TeX-fold-remove-overlays overlays)))
+
+(defun TeX-fold-remove-overlays (overlays)
+ "Remove all overlays set by TeX-fold in OVERLAYS.
+Return non-nil if a removal happened, nil otherwise."
+ (let (found)
+ (while overlays
+ (when (eq (overlay-get (car overlays) 'category) 'TeX-fold)
+ (delete-overlay (car overlays))
+ (setq found t))
+ (setq overlays (cdr overlays)))
+ found))
+
+
+;;; Toggling
+
+(defun TeX-fold-expand-spec (spec ov-start ov-end)
+ "Expand instances of {<num>}, [<num>], <<num>>, and (<num>).
+Replace them with the respective macro argument."
+ (let ((spec-list (split-string spec "||"))
+ (delims '((?\{ . ?\}) (?\[ . ?\]) (?< . ?>) (?\( . ?\))))
+ index success)
+ (catch 'success
+ ;; Iterate over alternatives.
+ (dolist (elt spec-list)
+ (setq spec elt
+ index nil)
+ ;; Find and expand every placeholder.
+ (while (and (string-match "\\([[{<]\\)\\([1-9]\\)\\([]}>]\\)" elt index)
+ ;; Does the closing delim match the opening one?
+ (string-equal
+ (match-string 3 elt)
+ (char-to-string
+ (cdr (assq (string-to-char (match-string 1 elt))
+ delims)))))
+ (setq index (match-end 0))
+ (let ((arg (car (save-match-data
+ ;; Get the argument.
+ (TeX-fold-macro-nth-arg
+ (string-to-number (match-string 2 elt))
+ ov-start ov-end
+ (assoc (string-to-char (match-string 1 elt))
+ delims))))))
+ (when arg (setq success t))
+ ;; Replace the placeholder in the string.
+ (setq elt (replace-match (or arg TeX-fold-ellipsis) nil t elt)
+ index (+ index (- (length elt) (length spec)))
+ spec elt)))
+ (when success (throw 'success nil))))
+ spec))
+
+(defun TeX-fold-hide-item (ov)
+ "Hide a single macro or environment.
+That means, put respective properties onto overlay OV."
+ (let* ((ov-start (overlay-start ov))
+ (ov-end (overlay-end ov))
+ (spec (overlay-get ov 'TeX-fold-display-string-spec))
+ (computed (cond
+ ((stringp spec)
+ (TeX-fold-expand-spec spec ov-start ov-end))
+ ((functionp spec)
+ (let (arg arg-list
+ (n 1))
+ (while (setq arg (TeX-fold-macro-nth-arg
+ n ov-start ov-end))
+ (unless (member (car arg) arg-list)
+ (setq arg-list (append arg-list (list (car arg)))))
+ (setq n (1+ n)))
+ (or (condition-case nil
+ (apply spec arg-list)
+ (error nil))
+ "[Error: No content or function found]")))
+ (t (or (TeX-fold-macro-nth-arg spec ov-start ov-end)
+ "[Error: No content found]"))))
+ (display-string (if (listp computed) (car computed) computed))
+ ;; (face (when (listp computed) (cadr computed)))
+ )
+ ;; Do nothing if the overlay is empty.
+ (when (and ov-start ov-end)
+ ;; Cater for zero-length display strings.
+ (when (string= display-string "") (setq display-string TeX-fold-ellipsis))
+ ;; Add a linebreak to the display string and adjust the overlay end
+ ;; in case of an overfull line.
+ (when (TeX-fold-overfull-p ov-start ov-end display-string)
+ (setq display-string (concat display-string "\n"))
+ (move-overlay ov ov-start (save-excursion
+ (goto-char ov-end)
+ (skip-chars-forward " \t")
+ (point))))
+ (overlay-put ov 'mouse-face 'highlight)
+ (when font-lock-mode
+ ;; Add raise adjustment for superscript and subscript.
+ ;; (bug#42209)
+ (setq display-string
+ (propertize display-string
+ 'display (get-text-property ov-start 'display))))
+ (overlay-put ov 'display display-string)
+ (when font-lock-mode
+ (overlay-put ov 'face TeX-fold-folded-face))
+ (unless (zerop TeX-fold-help-echo-max-length)
+ (overlay-put ov 'help-echo (TeX-fold-make-help-echo
+ (overlay-start ov) (overlay-end ov)))))))
+
+(defun TeX-fold-show-item (ov)
+ "Show a single LaTeX macro or environment.
+Remove the respective properties from the overlay OV."
+ (overlay-put ov 'mouse-face nil)
+ (overlay-put ov 'display nil)
+ (overlay-put ov 'help-echo nil)
+ (when font-lock-mode
+ (overlay-put ov 'face TeX-fold-unfolded-face)))
+
+;; Copy and adaption of `reveal-post-command' from reveal.el in GNU
+;; Emacs on 2004-07-04.
+(defun TeX-fold-post-command ()
+ ;; `with-local-quit' is not supported in XEmacs.
+ (condition-case nil
+ (let ((inhibit-quit nil))
+ (condition-case err
+ (let* ((spots (TeX-fold-partition-list
+ (lambda (x)
+ ;; We refresh any spot in the current
+ ;; window as well as any spots associated
+ ;; with a dead window or a window which
+ ;; does not show this buffer any more.
+ (or (eq (car x) (selected-window))
+ (not (window-live-p (car x)))
+ (not (eq (window-buffer (car x))
+ (current-buffer)))))
+ TeX-fold-open-spots))
+ (old-ols (mapcar #'cdr (car spots))))
+ (setq TeX-fold-open-spots (cdr spots))
+ (when (or disable-point-adjustment
+ global-disable-point-adjustment
+ ;; See preview.el on how to make this configurable.
+ (memq this-command
+ (list (key-binding [left]) (key-binding [right])
+ #'backward-char #'forward-char
+ #'mouse-set-point)))
+ ;; Open new overlays.
+ (dolist (ol (nconc (when (and TeX-fold-unfold-around-mark
+ mark-active)
+ (overlays-at (mark)))
+ (overlays-at (point))))
+ (when (eq (overlay-get ol 'category) 'TeX-fold)
+ (push (cons (selected-window) ol) TeX-fold-open-spots)
+ (setq old-ols (delq ol old-ols))
+ (TeX-fold-show-item ol))))
+ ;; Close old overlays.
+ (dolist (ol old-ols)
+ (when (and (eq (current-buffer) (overlay-buffer ol))
+ (not (rassq ol TeX-fold-open-spots)))
+ (if (and (>= (point) (overlay-start ol))
+ (<= (point) (overlay-end ol)))
+ ;; Still near the overlay: keep it open.
+ (push (cons (selected-window) ol) TeX-fold-open-spots)
+ ;; Really close it.
+ (TeX-fold-hide-item ol)))))
+ (error (message "TeX-fold: %s" err))))
+ (quit (setq quit-flag t))))
+
+
+;;; Misc
+
+;; Copy and adaption of `cvs-partition' from pcvs-util.el in GNU Emacs
+;; on 2004-07-05 to make tex-fold.el mainly self-contained.
+(defun TeX-fold-partition-list (p l)
+ "Partition a list L into two lists based on predicate P.
+The function returns a `cons' cell where the `car' contains
+elements of L for which P is true while the `cdr' contains
+the other elements. The ordering among elements is maintained."
+ (let (car cdr)
+ (dolist (x l)
+ (if (funcall p x) (push x car) (push x cdr)))
+ (cons (nreverse car) (nreverse cdr))))
+
+
+;;; The mode
+
+;;;###autoload
+(define-minor-mode TeX-fold-mode
+ "Minor mode for hiding and revealing macros and environments.
+
+Called interactively, with no prefix argument, toggle the mode.
+With universal prefix ARG (or if ARG is nil) turn mode on.
+With zero or negative ARG turn mode off."
+ :init-value nil
+ :lighter nil
+ :keymap (list (cons TeX-fold-command-prefix TeX-fold-keymap))
+ (if TeX-fold-mode
+ (progn
+ ;; The value t causes problem when body text is hidden in
+ ;; outline-minor-mode. (bug#36651)
+ ;; In addition, it's better not to override user preference
+ ;; without good reason.
+ ;; (set (make-local-variable 'search-invisible) t)
+ (add-hook 'post-command-hook #'TeX-fold-post-command nil t)
+ (add-hook 'LaTeX-fill-newline-hook #'TeX-fold-update-at-point nil t)
+ (add-hook 'TeX-after-insert-macro-hook
+ (lambda ()
+ (when (and TeX-fold-mode TeX-fold-auto)
+ (save-excursion
+ (backward-char)
+ (or (TeX-fold-item 'macro)
+ (TeX-fold-item 'math)
+ (TeX-fold-item 'env))))))
+ ;; Update the `TeX-fold-*-spec-list-internal' variables.
+ (dolist (elt '("macro" "env" "math"))
+ (set (intern (format "TeX-fold-%s-spec-list-internal" elt))
+ ;; Append the value of `TeX-fold-*-spec-list' to the
+ ;; mode-specific `<mode-prefix>-fold-*-spec-list' variable.
+ (append (symbol-value (intern (format "TeX-fold-%s-spec-list"
+ elt)))
+ (let ((symbol (intern (format "%s-fold-%s-spec-list"
+ (TeX-mode-prefix) elt))))
+ (when (boundp symbol)
+ (symbol-value symbol)))))))
+ ;; (kill-local-variable 'search-invisible)
+ (remove-hook 'post-command-hook #'TeX-fold-post-command t)
+ (remove-hook 'LaTeX-fill-newline-hook #'TeX-fold-update-at-point t)
+ (TeX-fold-clearout-buffer))
+ (TeX-set-mode-name))
+
+;;;###autoload
+(defalias 'tex-fold-mode #'TeX-fold-mode)
+
+(provide 'tex-fold)
+
+;;; tex-fold.el ends here