The command my-replace-over-with-frac
defined in the following Elisp code assumes that \over
arguments are always delimited by braces.
There are more constructs that limit the arguments of \over
like $ a \over b $ $ c \over d $
or $\matrix{ a \over b & c \over d }$
. In each of those cases a \over b
and c \over d
are rendered as separate fractions.
If one ignores that it may lead to an invalid LaTeX document.
For that reason the default application of my-replace-over-with-frac
is interactive by default. For each match of \over
you are asked whether you want to accept the replacement or not. The text modifications are marked with yellow color.
If you skip some replacements you can afterwards search for \over
to find those cases and edit them.
If you are venturesome you can call my-replace-over-with-frac
with prefix-arg. In that case all replacements are done without user-interaction.
(defun my-next-over (&rest args)
"Search for the next \\over in a math environment.
ARGS are the arguments starting at the 2nd one of `search-forward'."
(cl-loop while (apply #'search-forward "\\over" args)
when (and (save-match-data (texmathp))
(null (nth 8 (syntax-ppss (point)))))
return (point)
finally return nil))
(defun my-replace-over-with-frac (&optional b e force)
"Replace {a \\over b} with {\frac{a}{b}} in region from B to E.
Make replacements without questions if FORCE is non-nil.
Thereby, a and b can be terms that can contain fractions themselves."
(interactive (append
(if (use-region-p)
(list (region-beginning) (region-end))
(list nil nil))
(list prefix-arg)))
(save-point
(unless b (setq b (point-min)))
(unless e (setq e (point-max)))
(goto-char b)
(let ((ol-over (make-overlay 1 1))
(ol-frac (make-overlay 1 1))
(ol-brace (make-overlay 1 1)))
(unwind-protect
(progn
(overlay-put ol-over 'face 'match)
(overlay-put ol-frac 'face 'match)
(while (my-next-over e t)
(move-overlay ol-over (match-beginning 0) (match-end 0))
(replace-match "}{")
(goto-char (match-beginning 0))
(backward-up-list)
(let ((b-frac (point)))
(insert "{\\frac")
(move-overlay ol-frac b-frac (point)))
(forward-sexp 2)
(insert "}")
(move-overlay ol-brace (1- (point)) (point))
(if (or force
(y-or-n-p "Apply? "))
(goto-char (overlay-end ol-over)) ;; consider other occurences of \over in the second operand
(delete-region (overlay-start ol-over) (overlay-end ol-over))
(goto-char (overlay-start ol-over))
(insert "\\over")
(save-point
(delete-region (overlay-start ol-frac) (overlay-end ol-frac))
(delete-region (overlay-start ol-brace) (overlay-end ol-brace))))
)
)
(delete-overlay ol-over)
(delete-overlay ol-frac)
(delete-overlay ol-brace)))))
(delete-overlay ol-frac)))))
The interaction stuff hides a bit the simplicity of the method.
The structure of the method is:
(while (search-forward "\\over")
(save-point
(replace-match "}{")
(backward-up-list)
(insert "\\frac")))