Subject: bug#78741: [PATCH] LaTeX-repeat-recent-math

From: "Paul D. Nelson" <[email-masked]>
Date: Tue, 10 Jun 2025 08:47:47 +0200

Hi again,

I would like to propose a command that inserts a copy of the Nth most
recent display math (N=1 by default, strips labels).  I documented it at
the end of the "Entering Mathematics" part of the manual.  Any feedback
or suggestions would be welcome.

Paul

>From 04edbf84cb39b85803c39866384f6c94f84641ee Mon Sep 17 00:00:00 2001
From: Paul Nelson <[email-masked]>
Date: Sat, 31 May 2025 20:45:57 +0200
Subject: [PATCH] Add command LaTeX-repeat-recent-math-environment

* latex.el (LaTeX-repeat-recent-math): New command.

* doc/auctex.texi (Mathematics): Document it.
---
 doc/auctex.texi | 29 +++++++++++++++++++++++++++
 latex.el        | 53 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+)

diff --git a/doc/auctex.texi b/doc/auctex.texi
index 5629a693..90a8cf21 100644
--- a/doc/auctex.texi
+++ b/doc/auctex.texi
@@ -1404,6 +1404,35 @@ e.g.@: by adding the following to your init file:
 @xref{Quotes,,LaTeX-make-inline}, for a built-in convenience wrapper that
 converts display constructs to inline math.
 
+@subheading Repeating recent math
+
+@cindex LaTeX-repeat-recent-math
+@cindex Math, repeating
+@cindex Environments, repeating
+
+Sometimes you want the next equation to be a slight modification of a
+previous one.  The command @code{LaTeX-repeat-recent-math} looks backward
+for a recent top-level display math construct and inserts a copy.
+
+@deffn Command LaTeX-repeat-recent-math @var{n}
+Search backward for the @var{n}th most recent outer-level math construct
+(@samp{\[...\]}, @samp{$$...$$}, or any math environment recognized by
+@code{texmathp}, such as @code{equation}, @code{align*}, @dots{}).  Copy
+that construct to the current line, indent it, and strip any labels.
+
+With no prefix argument, @var{n} defaults to @code{1} (the most recent
+construct).
+@end deffn
+
+We can bind this command to a key, as follows:
+
+@lisp
+(keymap-set LaTeX-mode-map "C-c r" #'LaTeX-repeat-recent-math)
+@end lisp
+
+Then @kbd{C-c r} duplicates the last equation, @kbd{C-2 C-c r} duplicates
+the second-to-last equation, and so on.
+
 @node Completion
 @section Completion
 @cindex Completion
diff --git a/latex.el b/latex.el
index f4c206fa..5bff638b 100644
--- a/latex.el
+++ b/latex.el
@@ -9761,6 +9761,59 @@ trailing punctuation outside the math delimiters."
        (cons TeX-electric-math 'inline)
      "$")))
 
+(defun LaTeX-repeat-recent-math (&optional n)
+  "Insert a copy of the Nth most recent top-level math construct.
+N should be a positive integer.  The recognized constructs are
+\"\\=\\[ ... \\]\", \"$$ ... $$\" and \"\\begin{ENV} ... \\end{ENV}\"
+with ENV a math environment detected by `texmathp'.  Any
+\"\\label{...}\" macros inside the copied region are stripped."
+  (interactive "*p")
+  (setq n (or n 1))
+  (unless (> n 0) (user-error "N must be positive"))
+  (let* ((env-re (concat (regexp-quote TeX-esc) "begin"
+                         TeX-grop
+                         "\\(" (regexp-opt (LaTeX--math-environment-list)) "\\)"
+                         TeX-grcl))
+         (search-re (concat env-re "\\|"
+                            "\\(" (regexp-quote "$$") "\\|"
+                            (regexp-quote (concat TeX-esc "[")) "\\)"))
+         beg end)
+    (save-excursion
+      (catch 'found
+        (while (re-search-backward search-re nil t)
+          (unless (nth 4 (syntax-ppss))
+            (let ((open (match-string-no-properties 0)))
+              (when (save-excursion
+                      (goto-char (match-end 0))
+                      (texmathp))
+                (cl-decf n)
+                (when (zerop n)
+                  (setq beg (point))
+                  (goto-char (match-end 0))
+                  (let ((end-re
+                         (let ((type (if (string-match env-re open)
+                                         (match-string-no-properties 1 open)
+                                       open)))
+                           (regexp-quote (LaTeX--closing type)))))
+                    (re-search-forward end-re))
+                  (setq end (point))
+                  (throw 'found t))))))))
+    (unless (and beg end)
+      (user-error "Nth most recent top-level math construct not found"))
+    (let ((contents (buffer-substring-no-properties beg end)))
+      (beginning-of-line)
+      (if (looking-at-p "[[:blank:]]*$")
+          (delete-region (point) (line-end-position))
+        (end-of-line)
+        (delete-horizontal-space)
+        (insert "\n"))
+      (save-excursion (insert contents))
+      (save-restriction
+        (narrow-to-region (point) (+ (point) (length contents)))
+        (indent-region (point-min) (point-max))
+        (save-excursion (LaTeX--strip-labels))
+        (forward-line)))))
+
 (provide 'latex)
 
 ;;; latex.el ends here
-- 
2.39.3 (Apple Git-145)