Although this question is a few years old, I think I might be able to contribute with one more answer. Below is the code for a function called math-hilite
which hides normal text and highlights everything in math style. Moreover it sets a read-only
property on hidden text and tells isearch-filter-predicate
to ignore hidden text so that any further search or replacement is done only within math text.
With prefix argument reverse
, math is hidden instead.
After you are done searching and replacing, call math-hilite
once more to bring your buffer back to its normal state.
By redefining the variable envir-bdry
, all sorts of other non-TeX applications are possible.
(require 'cl-lib)
(defun next-math-environment (start)
"Assuming start is NOT inside a math environment, we return a
list (b1 a1 a2 b2) with information regarding the next math
environment after start: (buffer-substring a1 a2) is the
environment itself, and (buffer-substring b1 b2) is the
environment including the tokens marking the environment.
If a math environment is malformed, that is, it
extends beyond the end of the paragraph, then we report the end
of the paragraph in both a2 and b2. This function could be
defined with texmathp, but it becomes much slower."
(unless (boundp 'envir-bdry)
(setq envir-bdry
`(
(,(regexp-quote "$$") . ,(regexp-quote "$$"))
(,(regexp-quote "$") . ,(regexp-quote "$"))
(,(regexp-quote "\\[") . ,(regexp-quote "\\]"))
(,(regexp-quote "\\(") . ,(regexp-quote "\\)"))
("\\\\begin *{math}" . "\\\\end *{math}")
("\\\\begin *{align\\*?}" . "\\\\end *{align\\*?}")
("\\\\begin *{gather\\*?}" . "\\\\end *{gather\\*?}")
("\\\\begin *{equation}" . "\\\\end *{equation}")
))
(setq bdry-regexp (mapconcat (lambda (x) (format "\\(%s\\)" (car x))) envir-bdry "\\|")))
(save-excursion (let (s paragraph-end
(paragraph-start "\n[[:space:]]*\n"))
(goto-char start)
(when (search-forward-regexp bdry-regexp nil t) ;; Search for the opening of a math environment
(setq
s (cl-loop for i from 1 if (match-string i) return (cdr (nth (1- i) envir-bdry))) ;; s is the corresponding closing string
paragraph-end (save-match-data (save-excursion (forward-paragraph) (point)))) ;; paragraph-end will bound the search for the closing string
(append
(list (match-beginning 0) (match-end 0)) ;; First part of the output
(if (search-forward-regexp s paragraph-end t) ;; Search for the closing string
(list (match-beginning 0) (match-end 0)) ;; Last part of the output if closing string is found
(list paragraph-end paragraph-end))))))) ;; Malformed math environment. Cannot find end of environment whithin paragraph.
;; so return paragraph-end in last 2 slots
(defun math-hilite (&optional reverse)
"Hide non-math TeX for purpose of searching and replacing,
putting a 'read-only property on hiddent text. If reverse is
non-nil then hide math instead. Call it a second time to cancel its effect"
(interactive "P")
(unless (boundp 'math-hid) (setq-local math-hid nil)) ;; This variable informs the state of the buffer
(with-silent-modifications ;; Don't consider changing text properties as modifications
(if (null math-hid) ;; Buffer state is not altered. Hide what must be hidden
(let (nme
text-state math-state
(start (point-min))
(hid (list 'face (cons 'foreground-color "grey20") 'read-only t)) ;; Properties for hidden stuff
(div (list 'face (cons 'foreground-color "salmon") 'read-only t)) ;; Properties for separators
)
(setq-local
math-hid t ;; Set buffer as altered
isearch-filter-predicate (lambda (x y) (null (get-text-property x 'read-only)))) ;; Set predicate for later search operations
(if (null reverse )
(setq text-state hid math-state nil) ;; Hide normal text and show math (default)
(setq text-state nil math-state hid) ;; Hide math and show normal text
)
(font-lock-mode -1)
(set-text-properties (point-min) (point-max) text-state) ;; Set whole buffer with text-state
(while (setq nme (next-math-environment start))
(set-text-properties (nth 0 nme) (nth 1 nme) div) ;; Set opening boundary with div properties
(set-text-properties (nth 1 nme) (nth 2 nme) math-state) ;; Set math environment with math-state
(set-text-properties (nth 2 nme) (nth 3 nme) div) ;; Set closing boundary with div properties
(let ((stk (nth (if reverse 3 1) nme)))
(put-text-property (1- stk) stk 'rear-nonsticky t)) ;; Fix sticky issue
(setq start (nth 3 nme))) ;; Get ready for seraching next math environment
(save-excursion
(goto-char (point-min))
(while (search-forward-regexp "%" nil t)
(set-text-properties (match-beginning 0) (line-end-position) hid)))) ;; Hide comments
(set-text-properties (point-min) (point-max) nil) ;; ELSE, when math-hid is t just reset everything
(font-lock-mode 1)
(setq-local isearch-filter-predicate 'isearch-filter-visible)
(setq-local math-hid nil)
)))