Subject: bug#73302: TeX-find-closing-brace and verbatim macros

From: Arash Esbati <[email-masked]>
Date: Mon, 30 Sep 2024 20:52:44 +0200

Hi Paul,

Paul Nelson <[email-masked]> writes:

> That example motivated me to take a proper look at the verbatim
> functions in AUCTeX, which is indeed relevant.  The following modified
> code passes all tests mentioned thus far in this thread, although the
> way the verbatim argument is found might be a bit brittle

Does the code work on this example:

  \Verb{foo{b}ar}

> I guess you could have a commented "{" in the middle of a multi-line
> \Verb{...}, but multi-line \Verb{...} seems like illegal latex anyway,
> so maybe it's all OK?

I don't think you can have a commented "{" in the argument of
\Verb{...}, only balanced pair of braces like above.  Multi-line \verb
are illegal in vanilla LaTeX, yes, but with fvextra v1.8.0, you can have
them[1]:

  * By default, `\Verb` and `\SaveVerb` now take multi-line (but not
    multi-paragraph) verbatim arguments.  The old behavior of requiring
    verbatim arguments to be on a single line can be restored by setting
    the new option `vargsingleline` to `true`.

But within AUCTeX, we disallow multi-line verb args.

Overall, I think the following (100% untested) changes should make your
code more robust:

--8<---------------cut here---------------start------------->8---
(defun czm-tex-fold--verb-data (&rest _args)
  "Return data for a verbatim macro.
Returns a list of the form (START END CONTENT)."
  (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)))
    (goto-char (1- bound-end))
    (when (if (string= start-delim TeX-grop)
              (and (backward-sexp) (point))
            (search-backward start-delim bound-start t))
      (let* ((verb-arg-start (1+ (point)))
             (verb-arg-end (1- bound-end)))
        (list bound-start
              bound-end
              (buffer-substring-no-properties verb-arg-start
                                              verb-arg-end))))))

(defun czm-tex-fold-verbs (start end)
  "Fold verbatim macros between START and END."
  (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 (czm-tex-fold--verb-data))
                    (verb-start (nth 0 data))
                    (verb-end (nth 1 data))
                    (content (nth 2 data))
                    (spec (lambda (&rest _args)
                            (nth 2 (czm-tex-fold--verb-content)))))
          (czm-tex-fold--create-misc-overlay verb-start verb-end
                                             content spec))))))
--8<---------------cut here---------------end--------------->8---

Best, Arash

Footnotes:
[1]  https://ctan.net/macros/latex/contrib/fvextra/CHANGELOG.md