Subject: bug#78693: 14.0.9; Folding of math macros with a function spec is broken

From: Arash Esbati <[email-masked]>
Date: Thu, 18 Sep 2025 10:03:29 +0200

Hi Paul,

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

> Thanks Raghuzar.  Attaching an updated patch rebased to master.  Since
> it's a non-local change, I figure I'll wait for Arash or Ikumi to take a
> quick sniff, then we can push and close.

Thanks for this and sorry for my late response.  I have some minor
comments (see below).  I trust your patch works.

> diff --git a/doc/auctex.texi b/doc/auctex.texi
> index d0d2e41c..eb692f70 100644
> --- a/doc/auctex.texi
> +++ b/doc/auctex.texi
> @@ -2931,6 +2931,23 @@ as a replacement for the macro.  Such functions typically return a string,
>  but may also return the symbol @code{abort} to indicate that the macro
>  should not be folded.
>  
> +Each specifier may instead be a cons cell @code{(@var{spec} . @var{sig})},
> +where @var{spec} is as above and @var{sig} controls how many arguments are
> +considered part of the macro to fold:
> +@itemize @bullet
> +@item
> +@code{nil}: no limit (default).
> +@item
> +Integer @var{n}: stop after @var{n} total arguments.
> +@item
> +Cons @code{(@var{p} . @var{q})}: stop after @var{p} optional and
> +@var{q} required arguments.

I think the LaTeX parlance is "mandatory argument".

> +@item
> +Predicate function: called repeatedly with the list of argument blocks
> +encountered thus far.  Returns non-@code{nil} to terminate scanning early.
> +See the doc string of @code{TeX-find-macro-boundaries} for details.
> +@end itemize
> [...]
> +
>  (defcustom TeX-fold-macro-spec-list
> -  '(("[f]" ("footnote" "marginpar"))
> -    (TeX-fold-cite-display ("cite" "Cite"))
> -    (TeX-fold-textcite-display ("textcite" "Textcite"))
> -    (TeX-fold-parencite-display ("parencite" "Parencite"))
> -    (TeX-fold-footcite-display ("footcite" "footcitetext"))
> -    ("[l]" ("label"))
> -    ("[r]" ("ref" "pageref" "eqref" "footref"))
> -    ("[i]" ("index" "glossary"))
> -    ("[1]:||*" ("item"))
> -    ("..." ("dots"))
> -    ("(C)" ("copyright"))
> -    ("(R)" ("textregistered"))
> -    ("TM"  ("texttrademark"))
> -    (TeX-fold-alert-display ("alert"))
> -    (TeX-fold-textcolor-display ("textcolor"))
> +  '((("[f]" . (1 . 1)) ("footnote" "marginpar"))
> +    ((TeX-fold-cite-display . (2 . 1)) ("cite" "Cite"))
> +    ((TeX-fold-textcite-display . (2 . 1)) ("textcite" "Textcite"))
> +    ((TeX-fold-parencite-display . (2 . 1)) ("parencite" "Parencite"))
> +    ((TeX-fold-footcite-display . (2 . 1)) ("footcite" "footcitetext"))
> +    (("[l]" . TeX-fold-stop-after-first-required) ("label"))
> +    (("[r]" . 1) ("ref" "pageref" "eqref" "footref"))
> +    (("[i]" . (1 . 1)) ("index" "glossary"))
> +    (("[1]:||*" . (1 . 0)) ("item"))
> +    (("..." . 0) ("dots"))
> +    (("(C)" . 0) ("copyright"))
> +    (("(R)" . 0) ("textregistered"))
> +    (("TM" . 0)  ("texttrademark"))
> +    ((TeX-fold-alert-display . 1) ("alert"))
> +    ((TeX-fold-textcolor-display . (1 . 2)) ("textcolor"))
>      (TeX-fold-begin-display ("begin"))
> -    (TeX-fold-end-display ("end"))
> +    ((TeX-fold-end-display . 1) ("end"))
>      (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")))
> +        "paragraph*" "subparagraph*"))
> +    ((1 . (0 . 1)) ("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.
> -Such functions typically return a string, but may also return the
> -symbol `abort' to indicate that the macro should not be folded.
> -
> -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"))
> +The first element is of the form SPEC or (SPEC . SIG), where SPEC can be
> +a string, an integer or a function symbol and SIG is described below.
> +The second element is a list of macros to fold without the leading
> +backslash.
> +
> +If SPEC 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 SPEC is an integer, the macro will be replaced by the respective
> +macro argument.
> +
> +If SPEC 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.  Such functions typically
> +return a string, but may also return the symbol `abort' to indicate that
> +the macro should not be folded.
> +
> +SIG optionally restricts how many macro arguments are consumed.  It
> +should be of the form required by the SIGNATURE argument of
> +`TeX-find-macro-boundaries'.  For example, if SIGNATURE is an integer n,
> +then at most n total arguments are consumed, while if it is a cons
> +cell (p . q), then at most p optional and q required arguments are
                                               ^^^^^^^^

mandatory

> +allowed.
> +
> +Setting this variable does not take effect immediately.  Use Customize
> +or reset the mode."
> +  :type `(repeat (group ,TeX-fold--spec-type
>                          (repeat :tag "Macros" (string))))
> -  :package-version '(auctex . "14.0.8"))
> +  :package-version '(auctex . "14.0.9"))

:package-version '(auctex . "14.1.1"))

> [...]
> diff --git a/tex.el b/tex.el
> index 18438a81..cbd0bef1 100644
> --- a/tex.el
> +++ b/tex.el
> @@ -5790,11 +5790,23 @@ If LIMIT is non-nil, do not search further up than this position
>  in the buffer."
>    (TeX-find-balanced-brace -1 depth limit))
>  
> -(defun TeX-find-macro-boundaries (&optional lower-bound)
> +(defun TeX-find-macro-boundaries (&optional lower-bound signature)
>    "Return a cons containing the start and end of a macro.
>  If LOWER-BOUND is given, do not search backward further than this
>  point in buffer.  Arguments enclosed in brackets or braces are
> -considered part of the macro."
> +considered part of the macro.
> +
> +If SIGNATURE is given, restrict the total number of arguments.  If
> +SIGNATURE is an integer N, allow at most N total arguments.  If
> +SIGNATURE is a cons cell (P . Q), allow at most P optional and Q
> +required arguments.

mandatory

HTH.  Best, Arash