Function: replace-preview-setup

replace-preview-setup is a byte-compiled function defined in replace.el.gz.

Signature

(replace-preview-setup FROM REGEXP-FLAG DELIMITED-FLAG &optional BACKWARD)

Documentation

Return a closure that previews the replacement of FROM.

Add it to minibuffer-setup-hook while reading the replacement text: on every change it shows, in the original window, how the visible matches of FROM would look after the replacement.

FROM nil means that the same minibuffer reads it too, as at the prompt of query-replace-read-from: then both halves come from the input, and nothing is previewed until it has both of them.

REGEXP-FLAG and DELIMITED-FLAG say how to search for FROM, as in replace-search. BACKWARD non-nil means that the replacement will go from point to the beginning of the buffer instead of to its end.

Source Code

;; Defined in /usr/src/emacs/lisp/replace.el.gz
(defun replace-preview-setup (from regexp-flag delimited-flag
			      &optional backward)
  "Return a closure that previews the replacement of FROM.
Add it to `minibuffer-setup-hook' while reading the replacement text:
on every change it shows, in the original window, how the visible
matches of FROM would look after the replacement.

FROM nil means that the same minibuffer reads it too, as at the prompt
of `query-replace-read-from': then both halves come from the input, and
nothing is previewed until it has both of them.

REGEXP-FLAG and DELIMITED-FLAG say how to search for FROM, as in
`replace-search'.  BACKWARD non-nil means that the replacement will go
from point to the beginning of the buffer instead of to its end."
  (if (or (not query-replace-show-preview) (minibufferp))
      #'ignore
    (let ((unwind (make-symbol "replace-preview--unwind"))
	  (after-change (make-symbol "replace-preview--after-change"))
	  (buffer (current-buffer))
	  ;; All of an active region is replaced, and only the
	  ;; filter below keeps the preview inside it.
	  (bounds (unless (use-region-p)
		    (if backward
			(cons (point-min) (point))
		      (cons (point) (point-max)))))
	  (region-filter (when (use-region-p)
			   (replace--region-filter
			    (funcall region-extract-function 'bounds)))))
      (fset unwind
	    (lambda ()
	      (remove-hook 'after-change-functions after-change t)
	      (remove-hook 'minibuffer-exit-hook unwind t)
	      (when (buffer-live-p buffer)
		(with-current-buffer buffer
		  (when region-filter
		    (remove-function (local 'isearch-filter-predicate)
				     region-filter))
		  (replace-preview-cleanup)))))
      (fset after-change
	    (lambda (_beg _end _len)
	      (let* ((input (replace-preview--input
			     from (minibuffer-contents)))
		     (search (car input))
		     (replacement (cdr input)))
		(with-minibuffer-selected-window
		  ;; The replacement text is typed one character at a
		  ;; time, so it's expected to be invalid meanwhile,
		  ;; e.g. when it ends with a backslash or refers to a
		  ;; group that the regexp doesn't have.
		  (condition-case nil
		      (if (or
			   (null input) (equal search "")
			   ;; Neither \, nor \# can be previewed, for
			   ;; different reasons.  \, is a Lisp expression
			   ;; that the user is still typing: evaluating it
			   ;; on each keystroke would run the side effects
			   ;; of a half-typed form as soon as it happens
			   ;; to be readable.  \# expands to the number of
			   ;; replacements made so far, and none has been
			   ;; made yet, so the preview would show 0 for
			   ;; every match where the replacement itself
			   ;; will show 0, 1, 2...
			   (and regexp-flag
				(string-match
				 query-replace-eval-replacement-regexp
				 replacement)))
			  (replace-preview-cleanup)
			(replace-preview-update
			 search replacement regexp-flag delimited-flag
			 (if (and case-fold-search search-upper-case)
			     (isearch-no-upper-case-p search regexp-flag)
			   case-fold-search)
			 (car bounds) (cdr bounds)))
		    (error (replace-preview-cleanup)))))))
      (lambda ()
	(add-hook 'minibuffer-exit-hook unwind nil t)
	(add-hook 'after-change-functions after-change nil t)
	(when region-filter
	  (with-current-buffer buffer
	    (add-function :after-while (local 'isearch-filter-predicate)
			  region-filter)))
	(funcall after-change nil nil nil)))))