Subject: bug#78585: [PATCH] TeX-fold-verbs: improve macro recognition

From: "Paul D. Nelson" <[email-masked]>
Date: Sun, 25 May 2025 14:52:58 +0200

Hi all,

This patch adds a couple "boundary checks" to the verbatim folding code
I contributed earlier.

Here's a sample document illustrating what could go wrong:

--8<---------------cut here---------------start------------->8---
\documentclass{article}
\usepackage{pythontex}
\NewDocumentCommand{\pyvm}{ m }{\mbox{\pyv{#1}}}

\begin{document}

$\pyvm{42}$

\end{document}
--8<---------------cut here---------------end--------------->8---

With the previous code, folding would trigger on \pyvm{42} as if it were
\pyv with delimiter m.  The fix is to require a word boundary in the
macro-matching regexp.

The other change is a bounds check.  I made this change locally a few
months ago, and think it was motivated by a parsing error, but
unfortunately forgot to save a minimal reproduction.

Any feedback welcome.

Thanks, best,

Paul

>From f84918335e0ae99921f68458c4bc6b91bd243bad Mon Sep 17 00:00:00 2001
From: Paul Nelson <[email-masked]>
Date: Sun, 25 May 2025 14:51:33 +0200
Subject: [PATCH] TeX-fold-verbs: improve delimiter and macro handling

* tex-fold.el (TeX-fold--verb-data): Add check to ensure
backward-sexp doesn't jump before macro boundaries when matching
braces.
(TeX-fold-verbs): Require word boundary after macro name in
regexp to prevent folding partial macro matches (e.g., \pyv in
\pyvm).
---
 tex-fold.el | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/tex-fold.el b/tex-fold.el
index 2c10cc27..766270ef 100644
--- a/tex-fold.el
+++ b/tex-fold.el
@@ -1362,13 +1362,17 @@ only in LaTeX modes."
                                     ?\{
                                   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)))))
+              (start-delim-pos
+               (save-excursion
+                 (goto-char bound-end)
+                 (if (string= start-delim TeX-grop) ; "{"
+                     (when-let* ((matching-brace (save-excursion (backward-sexp)
+                                                                 (point))))
+                       (and (>= matching-brace bound-start) matching-brace))
+                   ;; delimiter is, e.g., "|"
+                   (goto-char (1- bound-end))
+                   (search-backward start-delim bound-start t))))
+              (verb-arg-start (1+ start-delim-pos))
               (verb-arg-end (1- bound-end)))
     (list bound-start
           bound-end
@@ -1384,7 +1388,8 @@ Replaces the verbatim content with its own text."
                         (regexp-opt
                          (append
                           (LaTeX-verbatim-macros-with-braces)
-                          (LaTeX-verbatim-macros-with-delims))))))
+                          (LaTeX-verbatim-macros-with-delims)))
+                        "\\_>")))
         (while (let ((case-fold-search nil))
                  (re-search-forward re end t))
           (when-let* ((data (TeX-fold--verb-data))
-- 
2.39.3 (Apple Git-145)