;;; 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
(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)
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