aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/replace.el
diff options
context:
space:
mode:
authorRichard M. Stallman1999-08-03 17:50:44 +0000
committerRichard M. Stallman1999-08-03 17:50:44 +0000
commit84482eb3014e0269828e12d4b05b53963de9d95a (patch)
tree9d4f133f4c191918dfd3fbd53ab195ffa0f13a58 /lisp/replace.el
parent42a19c2a181df9a6c3c0f9fd98c2362227d6340c (diff)
downloademacs-84482eb3014e0269828e12d4b05b53963de9d95a.tar.gz
emacs-84482eb3014e0269828e12d4b05b53963de9d95a.zip
(query-replace-regexp-eval)
(replace-eval-replacement, replace-loop-through-replacements) (replace-match-string-symbols): New functions. (perform-replace): Allow REPLACEMENTS to be (FUNCTION . DATA). Use replace-loop-through-replacements.
Diffstat (limited to 'lisp/replace.el')
-rw-r--r--lisp/replace.el126
1 files changed, 113 insertions, 13 deletions
diff --git a/lisp/replace.el b/lisp/replace.el
index 4921fd1fd4f..76813d4e0bf 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -118,6 +118,49 @@ and `\\=\\N' (where N is a digit) stands for
118 (perform-replace regexp to-string t t arg)) 118 (perform-replace regexp to-string t t arg))
119(define-key esc-map [?\C-%] 'query-replace-regexp) 119(define-key esc-map [?\C-%] 'query-replace-regexp)
120 120
121(defun query-replace-regexp-eval (regexp to-expr &optional arg)
122 "Replace some things after point matching REGEXP with the result of TO-EXPR.
123As each match is found, the user must type a character saying
124what to do with it. For directions, type \\[help-command] at that time.
125
126TO-EXPR is a Lisp expression evaluated to compute each replacement. It may
127reference `replace-count' to get the number of replacements already made.
128If the result of TO-EXPR is not a string, it is converted to one using
129`prin1-to-string' with the NOESCAPE argument (which see).
130
131For convenience, when entering TO-EXPR interactively, you can use `\\&' or
132`\\0'to stand for whatever matched the whole of REGEXP, and `\\=\\N' (where
133N is a digit) stands for whatever what matched the Nth `\\(...\\)' in REGEXP.
134Use `\\#&' or `\\#N' if you want a number instead of a string.
135
136In Transient Mark mode, if the mark is active, operate on the contents
137of the region. Otherwise, operate from point to the end of the buffer.
138
139If `query-replace-interactive' is non-nil, the last incremental search
140regexp is used as REGEXP--you don't have to specify it with the
141minibuffer.
142
143Preserves case in each replacement if `case-replace' and `case-fold-search'
144are non-nil and REGEXP has no uppercase letters.
145Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
146only matches surrounded by word boundaries."
147 (interactive
148 (let (from to)
149 (if query-replace-interactive
150 (setq from (car regexp-search-ring))
151 (setq from (read-from-minibuffer "Query replace regexp: "
152 nil nil nil
153 query-replace-from-history-variable
154 nil t)))
155 (setq to (list (read-from-minibuffer
156 (format "Query replace regexp %s with eval: " from)
157 nil nil t query-replace-to-history-variable from t)))
158 ;; We make TO a list because replace-match-string-symbols requires one,
159 ;; and the user might enter a single token.
160 (replace-match-string-symbols to)
161 (list from (car to) current-prefix-arg)))
162 (perform-replace regexp (cons 'replace-eval-replacement to-expr) t t arg))
163
121(defun map-query-replace-regexp (regexp to-strings &optional arg) 164(defun map-query-replace-regexp (regexp to-strings &optional arg)
122 "Replace some matches for REGEXP with various strings, in rotation. 165 "Replace some matches for REGEXP with various strings, in rotation.
123The second argument TO-STRINGS contains the replacement strings, separated 166The second argument TO-STRINGS contains the replacement strings, separated
@@ -688,6 +731,54 @@ The valid answers include `act', `skip', `act-and-show',
688(define-key query-replace-map "\e" 'exit-prefix) 731(define-key query-replace-map "\e" 'exit-prefix)
689(define-key query-replace-map [escape] 'exit-prefix) 732(define-key query-replace-map [escape] 'exit-prefix)
690 733
734(defun replace-match-string-symbols (n)
735 ;; Process a list (and any sub-lists), expanding certain symbols:
736 ;; Symbol Expands To
737 ;; N (match-string N) (where N is a string of digits)
738 ;; #N (string-to-number (match-string N))
739 ;; & (match-string 0)
740 ;; #& (string-to-number (match-string 0))
741 ;;
742 ;; Note that these symbols must be preceeded by a backslash in order to
743 ;; type them.
744 (while n
745 (cond
746 ((consp (car n))
747 (replace-match-string-symbols (car n))) ;Process sub-list
748 ((symbolp (car n))
749 (let ((name (symbol-name (car n))))
750 (cond
751 ((string-match "^[0-9]+$" name)
752 (setcar n (list 'match-string (string-to-number name))))
753 ((string-match "^#[0-9]+$" name)
754 (setcar n (list 'string-to-number
755 (list 'match-string
756 (string-to-number (substring name 1))))))
757 ((string= "&" name)
758 (setcar n '(match-string 0)))
759 ((string= "#&" name)
760 (setcar n '(string-to-number (match-string 0))))))))
761 (setq n (cdr n))))
762
763(defun replace-eval-replacement (expression replace-count)
764 (let ((replacement (eval expression)))
765 (if (stringp replacement)
766 replacement
767 (prin1-to-string replacement t))))
768
769(defun replace-loop-through-replacements (data replace-count)
770 ;; DATA is a vector contaning the following values:
771 ;; 0 next-rotate-count
772 ;; 1 repeat-count
773 ;; 2 next-replacement
774 ;; 3 replacements
775 (if (= (aref data 0) replace-count)
776 (progn
777 (aset data 0 (+ replace-count (aref data 1)))
778 (let ((next (cdr (aref data 2))))
779 (aset data 2 (if (consp next) next (aref data 3))))))
780 (car (aref data 2)))
781
691(defun perform-replace (from-string replacements 782(defun perform-replace (from-string replacements
692 query-flag regexp-flag delimited-flag 783 query-flag regexp-flag delimited-flag
693 &optional repeat-count map) 784 &optional repeat-count map)
@@ -711,10 +802,8 @@ which will run faster and probably do exactly what you want."
711 (search-string from-string) 802 (search-string from-string)
712 (real-match-data nil) ; the match data for the current match 803 (real-match-data nil) ; the match data for the current match
713 (next-replacement nil) 804 (next-replacement nil)
714 (replacement-index 0)
715 (keep-going t) 805 (keep-going t)
716 (stack nil) 806 (stack nil)
717 (next-rotate-count 0)
718 (replace-count 0) 807 (replace-count 0)
719 (nonempty-match nil) 808 (nonempty-match nil)
720 809
@@ -736,9 +825,22 @@ which will run faster and probably do exactly what you want."
736 (setq limit (copy-marker (region-end))) 825 (setq limit (copy-marker (region-end)))
737 (goto-char (region-beginning)) 826 (goto-char (region-beginning))
738 (deactivate-mark))) 827 (deactivate-mark)))
739 (if (stringp replacements) 828
740 (setq next-replacement replacements) 829 ;; REPLACEMENTS is either a string, a list of strings, or a cons cell
741 (or repeat-count (setq repeat-count 1))) 830 ;; containing a function and its first argument. The function is
831 ;; called to generate each replacement like this:
832 ;; (funcall (car replacements) (cdr replacements) replace-count)
833 ;; It must return a string.
834 (cond
835 ((stringp replacements)
836 (setq next-replacement replacements
837 replacements nil))
838 ((stringp (car replacements)) ; If it isn't a string, it must be a cons
839 (or repeat-count (setq repeat-count 1))
840 (setq replacements (cons 'replace-loop-through-replacements
841 (vector repeat-count repeat-count
842 replacements replacements)))))
843
742 (if delimited-flag 844 (if delimited-flag
743 (setq search-function 're-search-forward 845 (setq search-function 're-search-forward
744 search-string (concat "\\b" 846 search-string (concat "\\b"
@@ -782,14 +884,12 @@ which will run faster and probably do exactly what you want."
782 (and (looking-at search-string) 884 (and (looking-at search-string)
783 (match-data))))) 885 (match-data)))))
784 886
785 ;; If time for a change, advance to next replacement string. 887 ;; Calculate the replacement string, if necessary.
786 (if (and (listp replacements) 888 (when replacements
787 (= next-rotate-count replace-count)) 889 (set-match-data real-match-data)
788 (progn 890 (setq next-replacement
789 (setq next-rotate-count 891 (funcall (car replacements) (cdr replacements)
790 (+ next-rotate-count repeat-count)) 892 replace-count)))
791 (setq next-replacement (nth replacement-index replacements))
792 (setq replacement-index (% (1+ replacement-index) (length replacements)))))
793 (if (not query-flag) 893 (if (not query-flag)
794 (progn 894 (progn
795 (set-match-data real-match-data) 895 (set-match-data real-match-data)