diff options
| author | Richard M. Stallman | 1999-08-03 17:50:44 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1999-08-03 17:50:44 +0000 |
| commit | 84482eb3014e0269828e12d4b05b53963de9d95a (patch) | |
| tree | 9d4f133f4c191918dfd3fbd53ab195ffa0f13a58 /lisp/replace.el | |
| parent | 42a19c2a181df9a6c3c0f9fd98c2362227d6340c (diff) | |
| download | emacs-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.el | 126 |
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. | ||
| 123 | As each match is found, the user must type a character saying | ||
| 124 | what to do with it. For directions, type \\[help-command] at that time. | ||
| 125 | |||
| 126 | TO-EXPR is a Lisp expression evaluated to compute each replacement. It may | ||
| 127 | reference `replace-count' to get the number of replacements already made. | ||
| 128 | If 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 | |||
| 131 | For convenience, when entering TO-EXPR interactively, you can use `\\&' or | ||
| 132 | `\\0'to stand for whatever matched the whole of REGEXP, and `\\=\\N' (where | ||
| 133 | N is a digit) stands for whatever what matched the Nth `\\(...\\)' in REGEXP. | ||
| 134 | Use `\\#&' or `\\#N' if you want a number instead of a string. | ||
| 135 | |||
| 136 | In Transient Mark mode, if the mark is active, operate on the contents | ||
| 137 | of the region. Otherwise, operate from point to the end of the buffer. | ||
| 138 | |||
| 139 | If `query-replace-interactive' is non-nil, the last incremental search | ||
| 140 | regexp is used as REGEXP--you don't have to specify it with the | ||
| 141 | minibuffer. | ||
| 142 | |||
| 143 | Preserves case in each replacement if `case-replace' and `case-fold-search' | ||
| 144 | are non-nil and REGEXP has no uppercase letters. | ||
| 145 | Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace | ||
| 146 | only 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. |
| 123 | The second argument TO-STRINGS contains the replacement strings, separated | 166 | The 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) |