;;; replace.el --- replace commands for Emacs
-;; Copyright (C) 1985, 86, 87, 92, 94, 96, 1997, 2000, 2001, 2002,
-;; 2003, 2004 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1987, 1992, 1994, 1996, 1997, 2000, 2001, 2002,
+;; 2003, 2004 Free Software Foundation, Inc.
;; Maintainer: FSF
(defvar query-replace-history nil)
-(defcustom query-replace-interactive nil
+(defvar query-replace-interactive nil
"Non-nil means `query-replace' uses the last search string.
-That becomes the \"string to replace\".
-If value is `initial', the last search string is inserted into
-the minibuffer as an initial value for \"string to replace\"."
- :type '(choice (const :tag "Off" nil)
- (const :tag "Initial content" initial)
- (other :tag "Use default value" t))
- :group 'matching)
+That becomes the \"string to replace\".")
(defcustom query-replace-from-history-variable 'query-replace-history
"History list to use for the FROM argument of `query-replace' commands.
:group 'matching
:version "21.4")
-(defun query-replace-read-args (string regexp-flag &optional noerror)
- (unless noerror
- (barf-if-buffer-read-only))
- (let (from to)
- (if (and query-replace-interactive
- (not (eq query-replace-interactive 'initial)))
- (setq from (car (if regexp-flag regexp-search-ring search-ring)))
- ;; The save-excursion here is in case the user marks and copies
- ;; a region in order to specify the minibuffer input.
- ;; That should not clobber the region for the query-replace itself.
- (save-excursion
- (setq from (read-from-minibuffer
- (format "%s: " string)
- (if (eq query-replace-interactive 'initial)
- (car (if regexp-flag regexp-search-ring search-ring)))
- nil nil
- query-replace-from-history-variable
- nil t)))
- ;; Warn if user types \n or \t, but don't reject the input.
- (and regexp-flag
- (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\(\\\\[nt]\\)" from)
- (let ((match (match-string 3 from)))
- (cond
- ((string= match "\\n")
- (message "Note: `\\n' here doesn't match a newline; to do that, type C-q C-j instead"))
- ((string= match "\\t")
- (message "Note: `\\t' here doesn't match a tab; to do that, just type TAB")))
- (sit-for 2))))
-
- (save-excursion
- (setq to (read-from-minibuffer
- (format "%s %s with: " string from)
- nil nil nil
- query-replace-to-history-variable from t)))
- (when (and regexp-flag
- (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" to))
+(defun query-replace-descr (string)
+ (mapconcat 'isearch-text-char-description string ""))
+
+(defun query-replace-read-from (string regexp-flag)
+ "Query and return the `from' argument of a query-replace operation.
+The return value can also be a pair (FROM . TO) indicating that the user
+wants to replace FROM with TO."
+ (if query-replace-interactive
+ (car (if regexp-flag regexp-search-ring search-ring))
+ (let* ((lastfrom (car (symbol-value query-replace-from-history-variable)))
+ (lastto (car (symbol-value query-replace-to-history-variable)))
+ (from
+ ;; The save-excursion here is in case the user marks and copies
+ ;; a region in order to specify the minibuffer input.
+ ;; That should not clobber the region for the query-replace itself.
+ (save-excursion
+ (when (equal lastfrom lastto)
+ ;; Typically, this is because the two histlists are shared.
+ (setq lastfrom (cadr (symbol-value
+ query-replace-from-history-variable))))
+ (read-from-minibuffer
+ (if (and lastto lastfrom)
+ (format "%s (default %s -> %s): " string
+ (query-replace-descr lastfrom)
+ (query-replace-descr lastto))
+ (format "%s: " string))
+ nil nil nil
+ query-replace-from-history-variable
+ nil t t))))
+ (if (and (zerop (length from)) lastto lastfrom)
+ (cons lastfrom
+ (query-replace-compile-replacement lastto regexp-flag))
+ ;; Warn if user types \n or \t, but don't reject the input.
+ (and regexp-flag
+ (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\(\\\\[nt]\\)" from)
+ (let ((match (match-string 3 from)))
+ (cond
+ ((string= match "\\n")
+ (message "Note: `\\n' here doesn't match a newline; to do that, type C-q C-j instead"))
+ ((string= match "\\t")
+ (message "Note: `\\t' here doesn't match a tab; to do that, just type TAB")))
+ (sit-for 2)))
+ from))))
+
+(defun query-replace-compile-replacement (to regexp-flag)
+ "Maybe convert a regexp replacement TO to Lisp.
+Returns a list suitable for `perform-replace' if necessary,
+the original string if not."
+ (if (and regexp-flag
+ (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" to))
(let (pos list char)
(while
(progn
;; Swallow a space after 'foo
;; but not after (quote foo).
(and (eq (car-safe (car pos)) 'quote)
- (= ?\( (aref to 0))))
- (string-match " " to (cdr pos)))
+ (not (= ?\( (aref to 0)))))
+ (eq (string-match " " to (cdr pos))
+ (cdr pos)))
(1+ (cdr pos))
(cdr pos))))
(setq to (substring to end)))))
(string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#]" to)))
- (setq to (nreverse (delete "" (cons to list)))))
- (replace-match-string-symbols to)
- (setq to (cons 'replace-eval-replacement
- (if (> (length to) 1)
- (cons 'concat to)
- (car to)))))
+ (setq to (nreverse (delete "" (cons to list))))
+ (replace-match-string-symbols to)
+ (cons 'replace-eval-replacement
+ (if (cdr to)
+ (cons 'concat to)
+ (car to))))
+ to))
+
+
+(defun query-replace-read-to (from string regexp-flag)
+ "Query and return the `to' argument of a query-replace operation."
+ (query-replace-compile-replacement
+ (save-excursion
+ (read-from-minibuffer
+ (format "%s %s with: " string (query-replace-descr from))
+ nil nil nil
+ query-replace-to-history-variable from t t))
+ regexp-flag))
+
+(defun query-replace-read-args (string regexp-flag &optional noerror)
+ (unless noerror
+ (barf-if-buffer-read-only))
+ (let* ((from (query-replace-read-from string regexp-flag))
+ (to (if (consp from) (prog1 (cdr from) (setq from (car from)))
+ (query-replace-read-to from string regexp-flag))))
(list from to current-prefix-arg)))
(defun query-replace (from-string to-string &optional delimited start end)
followed by a Lisp expression. Each
replacement evaluates that expression to compute the replacement
string. Inside of that expression, `\\&' is a string denoting the
-whole match as a sting, `\\N' for a partial match, `\\#&' and `\\#N'
+whole match as a string, `\\N' for a partial match, `\\#&' and `\\#N'
for the whole or a partial match converted to a number with
`string-to-number', and `\\#' itself for the number of replacements
done so far (starting with zero).
only matches that are surrounded by word boundaries.
Fourth and fifth arg START and END specify the region to operate on."
(interactive
- (let (from to)
- (if query-replace-interactive
- (setq from (car regexp-search-ring))
- (setq from (read-from-minibuffer "Query replace regexp: "
- nil nil nil
- query-replace-from-history-variable
- nil t)))
- (setq to (list (read-from-minibuffer
- (format "Query replace regexp %s with eval: " from)
- nil nil t query-replace-to-history-variable from t)))
+ (progn
+ (barf-if-buffer-read-only)
+ (let* ((from
+ ;; Let-bind the history var to disable the "foo -> bar" default.
+ ;; Maybe we shouldn't disable this default, but for now I'll
+ ;; leave it off. --Stef
+ (let ((query-replace-to-history-variable nil))
+ (query-replace-read-from "Query replace regexp" t)))
+ (to (list (read-from-minibuffer
+ (format "Query replace regexp %s with eval: "
+ (query-replace-descr from))
+ nil nil t query-replace-to-history-variable from t))))
;; We make TO a list because replace-match-string-symbols requires one,
;; and the user might enter a single token.
(replace-match-string-symbols to)
(if (and transient-mark-mode mark-active)
(region-beginning))
(if (and transient-mark-mode mark-active)
- (region-end)))))
+ (region-end))))))
(perform-replace regexp (cons 'replace-eval-replacement to-expr)
t 'literal delimited nil nil start end))
before rotating to the next.
Fourth and fifth arg START and END specify the region to operate on."
(interactive
- (let (from to)
- (setq from (if query-replace-interactive
+ (let* ((from (if query-replace-interactive
(car regexp-search-ring)
(read-from-minibuffer "Map query replace (regexp): "
nil nil nil
'query-replace-history nil t)))
- (setq to (read-from-minibuffer
+ (to (read-from-minibuffer
(format "Query replace %s with (space-separated strings): "
- from)
+ (query-replace-descr from))
nil nil nil
- 'query-replace-history from t))
+ 'query-replace-history from t)))
(list from to
(and current-prefix-arg
(prefix-numeric-value current-prefix-arg))
(define-key map "g" 'revert-buffer)
(define-key map "q" 'quit-window)
(define-key map "z" 'kill-this-buffer)
+ (define-key map "\C-c\C-f" 'next-error-follow-minor-mode)
map)
"Keymap for `occur-mode'.")
#'previous-single-property-change
#'next-single-property-change)
"No more matches")
+ ;; In case the *Occur* buffer is visible in a nonselected window.
+ (set-window-point (get-buffer-window (current-buffer)) (point))
(occur-mode-goto-occurrence))
\f
(read-from-minibuffer
(if default
(format "List lines matching regexp (default `%s'): "
- default)
+ (query-replace-descr default))
"List lines matching regexp: ")
nil
nil
nil
- 'regexp-history)))
+ 'regexp-history
+ default)))
(if (equal input "")
default
input))
(let ((matches 0) ;; count of matched lines
(lines 1) ;; line count
(matchbeg 0)
- (matchend 0)
(origpt nil)
(begpt nil)
(endpt nil)
(setq origpt (point))
(when (setq endpt (re-search-forward regexp nil t))
(setq matches (1+ matches)) ;; increment match count
- (setq matchbeg (match-beginning 0)
- matchend (match-end 0))
+ (setq matchbeg (match-beginning 0))
(setq begpt (save-excursion
(goto-char matchbeg)
(line-beginning-position)))
;; concatenate them all together.
(apply #'concat
(nconc
- (occur-engine-add-prefix (nreverse (cdr (occur-accumulate-lines (- (1+ nlines)) keep-props))))
+ (occur-engine-add-prefix (nreverse (cdr (occur-accumulate-lines (- (1+ (abs nlines))) keep-props))))
(list out-line)
- (occur-engine-add-prefix (cdr (occur-accumulate-lines (1+ nlines) keep-props))))))))
+ (if (> nlines 0)
+ (occur-engine-add-prefix
+ (cdr (occur-accumulate-lines (1+ nlines) keep-props)))))))))
;; Actually insert the match display data
(with-current-buffer out-buf
(let ((beg (point))
;; Bind message-log-max so we don't fill up the message log
;; with a bunch of identical messages.
(let ((message-log-max nil))
- (message message from-string next-replacement))
+ (message message
+ (query-replace-descr from-string)
+ (query-replace-descr next-replacement)))
(setq key (read-event))
;; Necessary in case something happens during read-event
;; that clobbers the match data.
(if (facep 'query-replace)
'query-replace 'region)))))
-;;; arch-tag: 16b4cd61-fd40-497b-b86f-b667c4cf88e4
+;; arch-tag: 16b4cd61-fd40-497b-b86f-b667c4cf88e4
;;; replace.el ends here