Subject: bug#61400: Different filling for verbatim macros

From: Arash Esbati <[email-masked]>
Date: Mon, 13 Feb 2023 12:07:59 +0100

Ikumi Keita <[email-masked]> writes:

> Looking at the current code closely, I think we can take a more drastic
> route. :-)

That's always highly welcome :-)

> Thus it's safe to modify `LaTeX-verbatim-p' to return nil at just before
> "\verb|...|" etc. by the following reasons:
> o In `LaTeX-search-forward-comment-start', `LaTeX-verbatim-p' is always
>   called just before % sign.
> o In `TeX-in-comment', `LaTeX-verbatim-p' is always called in a comment.

Do we really want this?  My gut feeling is to have `LaTeX-verbatim-p'
returns t just before the "\verb|...|" etc., i.e., when cursor is over
the backslash.

> (3) I began to feel unsatisfied that `LaTeX-verbatim-p' needs the check
> for `LaTeX-verbatim-macros-with-braces' in addition to
> `LaTeX-current-verbatim-macro':
> ----------------------------------------------------------------------
> (defun LaTeX-verbatim-p (&optional pos)
> [...]
>         (member (LaTeX-current-verbatim-macro)
>                 (LaTeX-verbatim-macros-with-delims))
>         (member (TeX-current-macro) (LaTeX-verbatim-macros-with-braces)) <--- Here
>         (member (LaTeX-current-environment) (LaTeX-verbatim-environments)))))
> ----------------------------------------------------------------------
> Why can't `LaTeX-current-verbatim-macro' check both *-delims and
> *-braces at the same time? Its name suggests it _should_ be able to
> handle either type.

This was also my takeaway after reading the code.

> In addition, we don't have to keep the symmetric behavior of
> `LaTeX-current-verbatim-macro' and `TeX-current-macro', given what I
> wrote in (1). So we can modify `LaTeX-verbatim-macro-boundaries' so that
> it returns nil at just before "\verb..." etc.

See above, my thinking is if it will be more future proof the other way
around.

> Summing up the considerations above, I arrvied at the attached
> tentative fix. I confirmed that it passes the regression tests.
>
> What do you think about it?

Thanks, LGTM.  One other complication we have to deal with is that \Verb
from fancyvrb or \lstinline from listings can have an optional argument,
e.g.:

  \Verb[fontsize=\scriptsize]|foo bar|

The following change to your suggestion should work:

--8<---------------cut here---------------start------------->8---
(defun LaTeX-verbatim-macro-boundaries ()
  "Return boundaries of verbatim macro.
Boundaries are returned as a cons cell where the car is the macro
start and the cdr the macro end.

It doesn't regard the point just before \\verb... etc. belongs to
the verbatim macro.  This isn't symmetric with
`TeX-find-macro-boundaries'."
  (save-excursion
    (let ((orig (point))
          (verbatim-regexp (regexp-opt
                            (append (LaTeX-verbatim-macros-with-delims)
                                    (LaTeX-verbatim-macros-with-braces))
                            t)))
      (catch 'found
        (while (progn
                 (skip-chars-backward (concat "^" (regexp-quote TeX-esc))
                                      (line-beginning-position))
                 (when (looking-at verbatim-regexp) (throw 'found nil))
                 ;; XXX: Why do we go back to the preceding lines?
                 (or (bobp) (forward-char -1))
                 (not (bolp)))))
      ;; Search forward for the macro end, unless we failed to find a start
      (unless (bolp)
        (let* ((beg (1- (point)))
               (macro-end (match-end 0))
               ;; -- NEW
               opt-end
               ;; -- CHANGED
               ;; XXX: Here we assume we are dealing with \verb which
               ;; expects the delimiter right behind the command.
               ;; However, \lstinline can also cope with whitespace as
               ;; well as an optional argument after the command.
               ;; Besides, \lstinline or \Verb (from fancyvrb) also
               ;; accept an optional argument which we have to
               ;; encounter.  We assume that users don't write
               ;; something like this '\Verb[foo[' and again the
               ;; delimiter is directly after the ] closing the
               ;; optional argument:
               ;; -- CHANGED
               (delimiter (if (= (char-after macro-end) ?\[)
                              (save-excursion (goto-char macro-end)
                                              (forward-list)
                                              (setq opt-end (point))
                                              (string (following-char)))
                            (buffer-substring-no-properties
                             macro-end (1+ macro-end)))))
          ;; Heuristic: If an opening brace is encountered, search for
          ;; both the opening and the closing brace as an end marker.
          ;; Like that the function should work for \verb|...| as well
          ;; as for \url{...}.
          (when (string= delimiter TeX-grop)
            (setq delimiter (concat delimiter TeX-grcl)))
          ;; -- CHANGED
          (if opt-end
              (goto-char (1+ opt-end))
            (goto-char (1+ macro-end)))
          (skip-chars-forward (concat "^" delimiter))
          (when (<= orig (point))
            (cons beg (1+ (point)))))))))
--8<---------------cut here---------------end--------------->8---

And while we're at it: The docstring isn't correct any more, right?  I
mean this part:

    It doesn't regard the point just before \\verb... etc. belongs to
    the verbatim macro.  This isn't symmetric with
    `TeX-find-macro-boundaries'.

> (By the way, as written in the comment of the patch, I don't understand
> the reason why the while loop in `LaTeX-verbatim-macro-boundaries' goes
> back to the previous line. Is there any \verb variant, say in fancyverb
> or fvextra, which allows newline in its argument?)

No, not that I'm aware of; linebreak in verb arg is a no-no.

> +;; (defun LaTeX-current-verbatim-macro ()
> +;;   "Return name of verbatim macro containing point, nil if none is present."
> +;;   (let ((macro-boundaries (LaTeX-verbatim-macro-boundaries)))
> +;;     (when macro-boundaries
> +;;       (save-excursion
> +;;         (goto-char (car macro-boundaries))
> +;;         (forward-char (length TeX-esc))
> +;;         (buffer-substring-no-properties
> +;;          (point) (progn (skip-chars-forward "@A-Za-z*") (point)))))))

Would it make sense to keep the above as a utility function?

Best, Arash