Subject: bug#78006: Improving `TeX-electric-math' behavior

From: "Paul D. Nelson" <[email-masked]>
Date: Fri, 25 Apr 2025 13:40:29 +0200

>> One counterintuitive edge case: if I mark x and hit $ repeatedly, then I
>> get $x$ -> \[x\] -> x -> etc.  On the other hand, if I mark $x$ and hit
>> $, then I get $$x$$ -> $x$ -> etc.
>
> I think this is by design.  In `TeX-insert-dollar-electric-region', we
> have this test:
>
>  ((and (eq last-command #'TeX-insert-dollar)
>          (re-search-forward ...))
>   ...
>

Right, I guess I was asking if it might make sense to eliminate the
"last-command" test, so that the command operates in a broader set of
scenarios.  I don't have strong feelings on this, since I haven't used
this cycling feature before.

>> Tangentially, I wonder whether this feature might be more useful if it
>> worked not just when operating on a region for the first time, but
>> more generally on any math region, as a way to cycle between inline
>> and displayed math.  I've had "make-inline" and "make-displayed"
>> functions in my config for a long time now that I've tried
>> unsuccessfully to think of an elegant way to package and contribute.
>
> Hmm, maybe we can add them to AUCTeX itself.  Do you want to show the
> code?

Sure.  There's a command for making a displayed equation inline, and
another command that, among other things, makes a displayed equation
inline.  I bind these to "C-c i" and "C-c e".  The "among other things"
should probably be stripped out before sending to AUCTeX, but OK,
resisting the urge to polish for now:

(defcustom czm-tex-edit-punctuation-string
  "[\\.|,|;|!|?]"
  "Regexp for matching punctuation characters."
  :group 'czm-tex-edit
  :type 'regexp)

;;;###autoload
(defun czm-tex-edit-make-equation-inline ()
  "Convert LaTeX equation environment at point to inlined math.
Format LaTeX environment at point by surrounding the math
environment with dollar signs, removing any leading or trailing
text."
  (interactive)
  (when (texmathp)
    (preview-clearout-at-point)
    (let ((cur (point-marker)) beg end)
      (save-excursion
        (LaTeX-find-matching-end)
        (setq end (line-beginning-position 2))
        (goto-char cur)
        (LaTeX-find-matching-begin)
        (setq beg (point)))
      (save-restriction
        (narrow-to-region beg end)
        (goto-char (point-min))
        (kill-line 1)
        (beginning-of-line-text)
        (delete-region (point-min) (point))
        (goto-char (point-max))
        (forward-line -2)
        (end-of-line)
        (delete-region (point) (point-max))
        (whitespace-cleanup)
        (goto-char (point-min))
        (insert "$")
        (goto-char (point-max))
        (insert "\n")
        (backward-char)
        (while (looking-back czm-tex-edit-punctuation-string 5)
          (backward-char))
        (insert "$")
        (while (> (count-lines (point-min) (point-max)) 1)
          (join-line))
        (current-buffer))
      (join-line)
      (goto-char cur))))

(defun czm-tex-edit-add-label ()
  "Add LaTeX label to matching \\begin{} at environment beginning.
Also, save label to kill ring as an \\eqref{} command."
  (interactive)
  (save-excursion
    (LaTeX-find-matching-begin)
    (end-of-line)
    (funcall czm-tex-edit-label-function)
    (let ((end (point)))
      (search-backward "{")
      (let ((beg (point)))
        (kill-new (concat "\\eqref" (buffer-substring beg end)))))))

(defun czm-tex-edit--handle-env (env pos num-chars search-str numbered)
  "Helper function for `czm-tex-edit-make-equation-numbered'.

Remove part of the environment string and insert a numbered or
unnumbered LaTeX equation environment at POS.  ENV specifies the
name of the environment to match, NUM-CHARS specifies the number
of characters to delete, SEARCH-STR specifies the string to
search for and NUMBERED determines if the equation environment
should be numbered."
  (goto-char pos)
  (delete-char num-chars)
  (when (or (equal env "equation") (equal env "equation*"))
    (kill-line))
  (push-mark (save-excursion
               (search-forward search-str)
               (delete-region (match-beginning 0) (match-end 0))
               (when (equal env "$")
                 (while (looking-at-p czm-tex-edit-punctuation-string)
                   (forward-char)))
               (point)))
  (activate-mark)
  (LaTeX-insert-environment (if numbered "equation" "equation*"))
  (when numbered
    (czm-tex-edit-add-label)))

(defun czm-tex-edit-make-equation-numbered ()
  "Toggle whether an equation is numbered."
  (interactive)
  (save-excursion
    (when (texmathp)
      (preview-clearout-at-point)
      (let ((env (car texmathp-why))
            (pos (cdr texmathp-why)))
        (cond
         ((or
           (equal env '"\\[") (equal env '"$$"))
          (czm-tex-edit--handle-env env pos 2 (if (equal env "$$") "$$" "\\]") nil))
         ((equal env "$")
          (czm-tex-edit--handle-env env pos 1 "$" nil))
         ((equal env "equation*")
          (czm-tex-edit--handle-env env pos 0 "\\end{equation*}" t))
         ((equal env "equation")
          (czm-tex-edit--handle-env env pos 0 "\\end{equation}" nil)))))))

[This last function is poorly named and documented -- apologies.]

These are part of https://github.com/ultronozm/czm-tex-edit.el.

One thought: AUCTeX has "C-u C-c C-e" for switching the type of an
environment.  Perhaps the same command could be made to work in
top-level $...$ regions, using something like the above
"make-equation-numbered" as the implementation.  Conversely, perhaps
$...$ could be a hard-coded option for environment type after "C-u C-c
C-e", with something like the above "make-inline" as implementation.
The point of this suggestion is just to get around the scarcity of
keybinds and integrate with existing commands.

Any thoughts welcome!