Subject: Re: bug#78586: TeX-make-inline

From: Ikumi Keita <[email-masked]>
Date: Wed, 04 Jun 2025 18:44:11 +0900

Hi Paul,

>>>>> "Paul D. Nelson" <[email-masked]> writes:
> Deleting whitespace is relevant when converting from display to inline.
> It seemed like the appropriate way to handle the variety of ways users
> might write display math, e.g., $$ x + y $$ with or without newlines.

I see, thanks for explanation.

+(defun LaTeX--modify-math-1 (open close inline new-open new-close new-inline pos)
+  "Helper function for `LaTeX-modify-math'.
+OPEN and CLOSE are the current delimiters, NEW-OPEN and NEW-CLOSE are
+the new delimiters.  INLINE and NEW-INLINE are booleans indicating
+whether the current and new delimiters are inline or display math.
+Assume point is at the start of the current OPEN delimiter.  POS is a
+marker that keeps track of cursor position."
+  (let ((converting-to-inline (and (not inline) new-inline)))
+    (when converting-to-inline
+      ;; Join with previous line if non-blank.
+      (when (save-excursion
+              (skip-chars-backward "[:blank:]")
+              (and
+               (bolp) (not (bobp))
+               (progn
+                 (forward-char -1)
+                 (skip-chars-backward "[:blank:]")
+                 (not (bolp)))))
+        (forward-char (length open))
+        (save-excursion (join-line))
+        (forward-char (- (length open)))))

Why do you go forth and back here? What's wrong with a bare `join-line'
without two `forward-char's?

+(defun LaTeX-modify-math (new-type)
+  "Modify the current math construct to NEW-TYPE.
+
+Interactively, prompt for NEW-TYPE from a list of inline math
+delimiters (\"$\", \"\\(\"), display math delimiters (\"$$\",
+\"\\=\\[\") and valid LaTeX environments (\"equation\", ...).
+
+Non-interactively, NEW-TYPE must be either
+- a string specifying the target delimiter or environment name, or
+- a cons cell ((OPEN . CLOSE) . INLINE), where OPEN and CLOSE are
+  delimiters and INLINE is non-nil if the math construct is to be
+  understood as inline.
+
+The function converts the math construct at point (inline, display, or
+environment) to the specified NEW-TYPE, preserving the content.  If
+point is not in a math construct, signal an error.  Clears any active
+previews at point before modification.
+
+Does not support modifying macro-based constructs such as \\ensuremath."
+  (interactive
+   (let* ((type (progn (texmathp) (car texmathp-why)))
+          (tbl (append '("$" "\\(" "$$" "\\[")
+                       (LaTeX--math-environment-list))))
+     (barf-if-buffer-read-only)
+     (unless type (user-error "Not inside math"))
+     (LaTeX--closing type) ;; Check for errors.
+     (list (completing-read
+            (format "Convert %s → " type) tbl nil t nil nil
+            type))))
+  (let ((new-open (if (stringp new-type)
+                      new-type
+                    (caar new-type)))
+        (new-close (if (stringp new-type)
+                       (LaTeX--closing new-type)
+                     (cdar new-type)))
+        (new-inline (if (stringp new-type)
+                        (member new-type '("$" "\\("))
+                      (cdr new-type))))
+    (when (fboundp 'preview-clearout-at-point)
+      (preview-clearout-at-point))
+    (unless (called-interactively-p 'any)
+      (unless (texmathp) (error "Not inside math")))
+    (let ((type (car texmathp-why))
+          (math-start (cdr texmathp-why))
+          (pos (point-marker)))
+      (set-marker-insertion-type pos
+                                 (not
+                                  (and
+                                   (< (point) (point-max))
+                                   (save-excursion
+                                     (forward-char)
+                                     (not (texmathp))))))
+      (goto-char math-start)
+      (let* ((open (if (member type '("\\(" "$" "\\[" "$$"))
+                       type
+                     (concat TeX-esc "begin" TeX-grop type TeX-grcl)))
+             (close (LaTeX--closing type)))
+        (if (or (not (stringp new-type))
+                (member new-open '("$" "\\(" "\\[" "$$")))
+            ;; Conversion to inline or non-environment display.
+            (let* ((inline (member type '("$" "\\("))))
+              (LaTeX--modify-math-1 open close inline new-open new-close new-inline pos))
+          ;; Conversion to an environment.
+          (delete-char (length open))
+          (push-mark (save-excursion
+                       (search-forward close)
+                       (delete-region (match-beginning 0) (match-end 0))
+                       (when (= (point) pos)
+                         (set-marker pos nil))

We have to keep
(setq pos nil)
after `set-marker', which doesn't change the value of `pos' itself.

+                       (when (member type '("$" "\\("))
+                         (skip-chars-forward ".,;:!?"))
+                       (point)))
+          (activate-mark)
+          (LaTeX-insert-environment new-type)))
+      (when pos
+        (goto-char pos)
+        (set-marker pos nil)))))
+
+(defun LaTeX-make-inline ()
+  "Convert LaTeX display math construct at point to inline math.
+Remove the enclosing math construct (such as \\=\\[...\\=\\] or
+\\begin{equation}...\\end{equation}) and replace it with inline math
+surrounded by `TeX-electric-math' if non-nil, or \"$...$\", fitting the
+result onto one line.  Finally, leave any trailing punctuation outside
+the math delimiters."
+  (interactive "*")
+  (LaTeX-modify-math
+   (if TeX-electric-math
+       (cons TeX-electric-math 'inline)
+     "$")))

As far as I can see, the proposed feature doesn't support docTeX mode. I
don't think that is a practical problem at all, but addition of FIXME
comment and breif mention about it in the documentation would be nice.

Regards,
Ikumi Keita
#StandWithUkraine #StopWarInUkraine
#Gaza #StopMassiveKilling #CeasefireNOW