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

From: Arash Esbati <[email-masked]>
Date: Mon, 26 May 2025 14:23:37 +0200

Hi Paul,

"Paul D. Nelson" <[email-masked]> writes:

> 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:
>
> \documentclass{article}
> \usepackage{pythontex}
> \NewDocumentCommand{\pyvm}{ m }{\mbox{\pyv{#1}}}
>
> \begin{document}
>
> $\pyvm{42}$
>
> \end{document}

Yes, I see what you mean.

> 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.

See below.

> 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)))
> +                        "\\_>")))

Why do you use the "\\_>" boundary?  I would have expected "\\b" or
"\\>"?  Am I missing something?

Best, Arash