diff --git a/iedit-lib.el b/iedit-lib.el index 6fa586b..8bd30d3 100644 --- a/iedit-lib.el +++ b/iedit-lib.el @@ -1,7 +1,7 @@ ;;; iedit-lib.el --- APIs for editing multiple regions in the same way ;;; simultaneously. -;; Copyright (C) 2010 - 2019, 2020, 2021 Victor Ren +;; Copyright (C) 2010 - 2022 Victor Ren ;; Time-stamp: <2022-01-14 12:33:36 Victor Ren> ;; Author: Victor Ren @@ -854,6 +854,24 @@ value of `iedit-occurrence-context-lines' is used for this time." (dolist (occurrence iedit-occurrences-overlays) (apply function (overlay-start occurrence) (overlay-end occurrence) args))))) +(defun iedit-apply-on-occurrences-in-seq (function &rest args) + "Call function for each occurrence in sequence." + (let ((iedit-updating t)) + (save-excursion + (goto-char (iedit-first-occurrence)) + (cl-loop for counter from 0 + for ov = (iedit-find-current-occurrence-overlay) + while (/= (point) (point-max)) + do (progn + (apply function ov counter args) + (iedit-move-conjoined-overlays ov) + ;; goto the beginning of the next occurrence overlay + (if (iedit-find-overlay-at-point (overlay-end ov) 'iedit-occurrence-overlay-name) + (goto-char (overlay-end ov)) ; conjoined overlay + (when (< (point) (overlay-end ov)) + (goto-char (next-single-char-property-change (point) 'iedit-occurrence-overlay-name))) + (goto-char (next-single-char-property-change (point) 'iedit-occurrence-overlay-name)))))))) + (defun iedit-upcase-occurrences () "Convert occurrences to upper case." (interactive "*") @@ -883,47 +901,47 @@ FORMAT." nil nil iedit-increment-format-string))) (list 1 iedit-increment-format-string))) (iedit-barf-if-buffering) - (let ((number start-at) - (iedit-updating t)) - (save-excursion - (goto-char (iedit-first-occurrence)) - (cl-loop for counter from number - for ov = (iedit-find-current-occurrence-overlay) - while (/= (point) (point-max)) - do (progn - (if (re-search-forward "\\\\#" (overlay-end ov) t) - (replace-match (format format-string counter) t) - (insert (format format-string counter))) - (iedit-move-conjoined-overlays ov) - ;; goto the beginning of the next occurrence overlay - (if (iedit-find-overlay-at-point (overlay-end ov) 'iedit-occurrence-overlay-name) - (goto-char (overlay-end ov)) ; conjoined overlay - (when (< (point) (overlay-end ov)) - (goto-char (next-single-char-property-change (point) 'iedit-occurrence-overlay-name))) - (goto-char (next-single-char-property-change (point) 'iedit-occurrence-overlay-name)))))))) + (iedit-apply-on-occurrences-in-seq + (lambda (ov count start-at) + (let ((counter (+ count start-at))) + (goto-char (overlay-start ov)) + (if (re-search-forward "\\\\#" (overlay-end ov) t) + (replace-match (format format-string counter) t) + (insert (format format-string counter))))) + start-at)) ;;; Don't downcase from-string to allow case freedom! (defun iedit-replace-occurrences(&optional to-string) - "Replace occurrences with STRING." + "Replace occurrences with TO-STRING. + +With a prefix arguement, TO-STRING needs not to be constant. The +things like `\\,' `\\&' `\\#' can be used in TO-STRING, the same +way as `replace-regexp'. Refer to the document of +`replace-string' and `replace-regexp' for the details about +TO-STRING." (interactive "*") (iedit-barf-if-buffering) (let* ((ov (iedit-find-current-occurrence-overlay)) (offset (- (point) (overlay-start ov))) - (from-string (buffer-substring-no-properties - (overlay-start ov) - (overlay-end ov))) + (literal (not current-prefix-arg)) (to-string (if (not to-string) - (read-string "Replace with: " - nil nil - from-string - nil) - to-string))) - (iedit-apply-on-occurrences - (lambda (beg end from-string to-string) - (goto-char beg) - (search-forward from-string end) - (replace-match to-string (not (and (not iedit-case-sensitive) case-replace)))) - from-string to-string) + (query-replace-read-to "occurrences" + "Replace" + (not literal)) + to-string))) + (iedit-apply-on-occurrences-in-seq + (lambda (ov count to-string literal) + (goto-char (overlay-start ov)) + (search-forward (buffer-substring-no-properties + (overlay-start ov) + (overlay-end ov)) + (overlay-end ov)) + (replace-match (if literal + to-string + (funcall (car to-string) (cdr to-string) count)) + (not (and (not iedit-case-sensitive) case-replace)) + literal)) + to-string literal) (goto-char (+ (overlay-start ov) offset)))) (defun iedit-blank-occurrences() diff --git a/iedit-tests.el b/iedit-tests.el index f23832d..a2a3fa1 100644 --- a/iedit-tests.el +++ b/iedit-tests.el @@ -1,6 +1,6 @@ ;;; iedit-tests.el --- iedit's automatic-tests -;; Copyright (C) 2010 - 2019, 2020 Victor Ren +;; Copyright (C) 2010 - 2022 Victor Ren ;; Time-stamp: <2022-01-14 12:33:56 Victor Ren> ;; Author: Victor Ren @@ -30,10 +30,12 @@ ;; This file is part of iedit. ;;; Code: + (require 'ert) (require 'iedit) (require 'iedit-rect) (require 'elp) +(require 'sgml-mode) (ert-deftest iedit-batch-compile-test () (with-temp-buffer @@ -74,12 +76,14 @@ Iedit-rect default key binding is <;> (defun with-iedit-test-fixture (input-buffer-string body) "iedit test fixture" (let ((old-transient-mark-mode transient-mark-mode) - (old-iedit-transient-sensitive iedit-transient-mark-sensitive)) + (old-iedit-transient-sensitive iedit-transient-mark-sensitive) + (old-iedit-auto-buffering iedit-auto-buffering)) (unwind-protect (progn (with-iedit-test-buffer "* iedit transient mark *" (transient-mark-mode t) (setq iedit-transient-mark-sensitive t) + (setq iedit-auto-buffering nil) (setq iedit-case-sensitive t) (insert input-buffer-string) (goto-char 1) @@ -87,6 +91,7 @@ Iedit-rect default key binding is <;> (funcall body)) (with-iedit-test-buffer "* iedit NO transient mark *" (setq iedit-transient-mark-sensitive nil) + (setq iedit-auto-buffering nil) (setq iedit-case-sensitive t) (transient-mark-mode -1) (insert input-buffer-string) @@ -94,7 +99,8 @@ Iedit-rect default key binding is <;> (iedit-mode) (funcall body))) (transient-mark-mode old-transient-mark-mode) - (setq iedit-transient-mark-sensitive old-transient-mark-mode)))) + (setq iedit-transient-mark-sensitive old-transient-mark-mode) + (setq iedit-auto-buffering old-iedit-auto-buffering)))) (ert-deftest iedit-mode-base-test () (with-iedit-test-fixture @@ -524,12 +530,19 @@ foo bar barfoo bar")) + (let ((current-prefix-arg 4)) + (iedit-replace-occurrences (query-replace-compile-replacement "\\,(format \"%s %d\" \\& \\#)" t ))) + (should (string= (buffer-string) +"bar 0 + bar 1 + barfoo + bar 2")) (iedit-number-occurrences 1 "%d ") (should (string= (buffer-string) -"1 bar - 2 bar +"1 bar 0 + 2 bar 1 barfoo - 3 bar"))))) + 3 bar 2"))))) (ert-deftest iedit-blank-occurrences-test () "Test functions deal with the whole occurrences"