--- replace.el 10 Jun 2004 09:36:09 +0200 1.172 +++ replace.el 17 Jun 2004 02:16:46 +0200 @@ -81,14 +81,15 @@ query-replace-from-history-variable nil t))) ;; Warn if user types \n or \t, but don't reject the input. - (if (string-match "\\\\[nt]" from) - (let ((match (match-string 0 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)))) + (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) @@ -165,18 +166,65 @@ (interactive (let ((common (query-replace-read-args "Query replace regexp" t))) - (list (nth 0 common) (nth 1 common) (nth 2 common) - ;; These are done separately here - ;; so that command-history will record these expressions - ;; rather than the values they had this time. - (if (and transient-mark-mode mark-active) - (region-beginning)) - (if (and transient-mark-mode mark-active) - (region-end))))) - + (list + (nth 0 common) + (if (string-match "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#?]" + (nth 1 common)) + (let ((to-string (nth 1 common)) pos to-expr char prompt) + (while (string-match + "\\(\\`\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\[,#?]" + to-string) + (setq pos (match-end 0)) + (push (substring to-string 0 (- pos 2)) to-expr) + (setq char (aref to-string (1- pos)) + to-string (substring to-string pos)) + (cond ((eq char ?\#) + (push '(number-to-string replace-count) to-expr)) + ((eq char ?\,) + (setq pos (read-from-string to-string)) + (push `(replace-quote ,(pop pos)) to-expr) + (setq to-string + (substring to-string + (if (and (< pos (length to-string)) + (eq (aref to-string pos) ?\ )) + (1+ pos) + pos)))) + ((eq char ?\?) + (push `(replace-quote + (replace-read-replacement + ,(if prompt + (progn + (setq prompt (1+ prompt)) + (format "Replacement %d: " prompt)) + (setq prompt 1) + "Replacement: "))) + to-expr)))) + (setq to-expr (delete "" (nreverse (cons to-string to-expr)))) + (replace-match-string-symbols to-expr) + (cons 'replace-eval-replacement + (if (> (length to-expr) 1) + (cons 'concat to-expr) + (car to-expr)))) + (nth 1 common)) + (nth 2 common) + ;; These are done separately here + ;; so that command-history will record these expressions + ;; rather than the values they had this time. + (if (and transient-mark-mode mark-active) + (region-beginning)) + (if (and transient-mark-mode mark-active) + (region-end))))) (perform-replace regexp to-string t t delimited nil nil start end)) + (define-key esc-map [?\C-%] 'query-replace-regexp) +(defun replace-read-replacement (prompt) + "Read a replacement string with PROMPT." + (read-from-minibuffer + prompt + nil nil t query-replace-to-history-variable + nil t)) + (defun query-replace-regexp-eval (regexp to-expr &optional delimited start end) "Replace some things after point matching REGEXP with the result of TO-EXPR. As each match is found, the user must type a character saying @@ -1012,6 +1060,7 @@ #N (string-to-number (match-string N)) & (match-string 0) #& (string-to-number (match-string 0)) +# replace-count Note that these symbols must be preceeded by a backslash in order to type them." @@ -1031,7 +1080,9 @@ ((string= "&" name) (setcar n '(match-string 0))) ((string= "#&" name) - (setcar n '(string-to-number (match-string 0)))))))) + (setcar n '(string-to-number (match-string 0)))) + ((string= "#" name) + (setcar n 'replace-count)))))) (setq n (cdr n)))) (defun replace-eval-replacement (expression replace-count) @@ -1040,6 +1091,21 @@ replacement (prin1-to-string replacement t)))) +(defun replace-quote (replacement) + "Quote a replacement string. +This just doubles all backslashes in REPLACEMENT and +returns the resulting string. If REPLACEMENT is not +a string, it is first passed through `prin1-to-string' +with the `noescape' argument set. + +`match-data' is preserved across the call." + (save-match-data + (replace-regexp-in-string "\\\\" "\\\\" + (if (stringp replacement) + replacement + (prin1-to-string replacement t)) + t t))) + (defun replace-loop-through-replacements (data replace-count) ;; DATA is a vector contaning the following values: ;; 0 next-rotate-count