From d5c0540e28d5a350689854e4d461819f986dfac2 Mon Sep 17 00:00:00 2001
From: Paul Nelson <ultrono@gmail.com>
Date: Mon, 30 Sep 2024 21:29:04 +0100
Subject: [PATCH] Improved verbatim folding

* tex-fold.el (TeX-fold-region-functions): Add TeX-fold-verbs to
the default.
(TeX-fold--verb-data):
(TeX-fold-verbs):
(TeX-fold--make-misc-overlay): New functions.
(TeX-fold-macro-nth-arg): Fix a minor issue concerning how
verbatim environments are detected while narrowed.
---
 tex-fold.el | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 73 insertions(+), 2 deletions(-)

diff --git a/tex-fold.el b/tex-fold.el
index a875cbb8..2e7285ec 100644
--- a/tex-fold.el
+++ b/tex-fold.el
@@ -353,12 +353,56 @@ and `TeX-fold-math-spec-list', and environments in `TeX-fold-env-spec-list'."
       (TeX-fold-clearout-region start end)
       (TeX-fold-region start end))))
 
-(defcustom TeX-fold-region-functions nil
+(defcustom TeX-fold-region-functions '(TeX-fold-verbs)
   "List of additional functions to call when folding a region.
 Each function is called with two arguments, the start and end positions
 of the region to fold."
   :type '(repeat function))
 
+(defun TeX-fold--verb-data (&rest _args)
+  "Return data describing verbatim macro at point.
+Returns list of the form (START END CONTENT).
+This should be called only in LaTeX modes."
+  (declare-function LaTeX-verbatim-macro-boundaries "latex")
+  (when-let* ((boundaries (LaTeX-verbatim-macro-boundaries))
+              (bound-start (car boundaries))
+              (bound-end (cdr boundaries))
+              (end-delim-char (char-before bound-end))
+              (start-delim-char (if (= end-delim-char ?\})
+                                    ?\{
+                                  end-delim-char))
+              (start-delim (char-to-string start-delim-char))
+              (verb-arg-start
+               (1+ (progn
+                     (goto-char bound-end)
+                     (if (string= start-delim TeX-grop)
+                         (progn (backward-sexp) (point))
+                       (forward-char -1)
+                       (search-backward start-delim bound-start t)))))
+              (verb-arg-end (1- bound-end)))
+    (list bound-start
+          bound-end
+          (buffer-substring-no-properties verb-arg-start
+                                          verb-arg-end))))
+
+(defun TeX-fold-verbs (start end)
+  "In LaTeX modes, fold verbatim macros between START and END."
+  (when (derived-mode-p 'LaTeX-mode)
+    (declare-function LaTeX-verbatim-macros-with-braces "latex")
+    (declare-function LaTeX-verbatim-macros-with-delims "latex")
+    (save-excursion
+      (goto-char start)
+      (let ((re (concat "\\\\" (regexp-opt
+                                (append
+                                 (LaTeX-verbatim-macros-with-braces)
+                                 (LaTeX-verbatim-macros-with-delims))))))
+        (while (let ((case-fold-search nil))
+                 (re-search-forward re end t))
+          (when-let* ((data (TeX-fold--verb-data))
+                      (spec (lambda (&rest _args)
+                              (nth 2 (TeX-fold--verb-data)))))
+            (apply #'TeX-fold--make-misc-overlay (append data (list spec)))))))))
+
 (defun TeX-fold-region (start end)
   "Fold all items in region from START to END."
   (interactive "r")
@@ -588,6 +632,25 @@ See its doc string for detail."
     (overlay-put ov 'TeX-fold-display-string-spec display-string-spec)
     ov))
 
+(defun TeX-fold--make-misc-overlay (start end display-string display-string-spec)
+  "Create a miscellaneous overlay between START and END.
+DISPLAY-STRING is the display string, while DISPLAY-STRING-SPEC is as in
+`TeX-fold-make-overlay'.
+
+This function is intended to be used with verbatim environments and
+other miscellaneous folding constructs.  By contrast, the function
+`TeX-fold-make-overlay' is used in the implementation of
+`TeX-fold-hide-item', which applies to typical macros, environments and
+math."
+  (let ((priority (TeX-overlay-prioritize start end))
+        (ov (make-overlay start end)))
+    (overlay-put ov 'category 'TeX-fold)
+    (overlay-put ov 'priority priority)
+    (overlay-put ov 'evaporate t)
+    (overlay-put ov 'display display-string)
+    (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
@@ -664,8 +727,16 @@ backward compatibility and always nil."
                                          (concat open-string " \t"))
                                         (point)))
                   (goto-char
-                   (if (TeX-verbatim-p)
+                   (if (save-restriction
+                         (widen)
+                         ;; `widen' accomodates the following issue:
+                         ;; with point on the `v' in `\end{verbatim}',
+                         ;; LaTeX-verbatim-p returns nil normally, but t
+                         ;; with region narrowed to avoid the
+                         ;; corresponding `\begin{verbatim}'.
+                         (TeX-verbatim-p))
                        (cond ((derived-mode-p 'LaTeX-mode)
+                              (declare-function LaTeX-verbatim-macro-boundaries "latex")
                               (cdr (LaTeX-verbatim-macro-boundaries)))
                              ;; FIXME: When other modes implement a
                              ;; nontrivial `TeX-verbatim-p-function', we
-- 
2.39.3 (Apple Git-145)

