diff --git a/iedit-lib.el b/iedit-lib.el index d788875..a367101 100644 --- a/iedit-lib.el +++ b/iedit-lib.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2010, 2011, 2012 Victor Ren -;; Time-stamp: <2020-07-16 12:17:46 Victor Ren> +;; Time-stamp: <2020-07-21 11:54:31 Victor Ren> ;; Author: Victor Ren ;; Keywords: occurrence region simultaneous rectangle refactoring ;; Version: 0.9.9.9 @@ -176,6 +176,10 @@ is not applied to other occurrences when it is true.") Used in mode-line to indicate the position of the current occurrence.") +(defvar iedit-after-change-list nil + "Used to store the modifications in the command being run.") + +(make-variable-buffer-local 'iedit-after-change-list) (make-variable-buffer-local 'iedit-occurrences-overlays) (make-variable-buffer-local 'iedit-read-only-occurrences-overlays) (make-variable-buffer-local 'iedit-hiding) @@ -393,8 +397,14 @@ there are." (iedit-update-index) )) ;; todo test this function -(defun iedit-cleanup () +(defun iedit-lib-start () + "Initialize the hooks." + (add-hook 'post-command-hook 'iedit-update-occurrences-2 nil t) + (setq iedit-after-change-list nil)) + +(defun iedit-lib-cleanup () "Clean up occurrence overlay, invisible overlay and local variables." + (remove-hook 'post-command-hook 'iedit-update-occurrences-2 t) (remove-overlays nil nil iedit-occurrence-overlay-name t) (iedit-show-all) (setq iedit-occurrences-overlays nil) @@ -475,68 +485,89 @@ occurrence, it will abort Iedit mode." (add-hook 'post-command-hook 'iedit-post-undo nil t) (setq iedit-post-undo-hook-installed t)) (when (not iedit-aborting) - ;; before modification - (if (null after) - (if (or (< beg (overlay-start occurrence)) - (> end (overlay-end occurrence))) - (progn (setq iedit-aborting t) ; abort iedit-mode - (add-hook 'post-command-hook 'iedit-reset-aborting nil t)) - (setq iedit-before-modification-string - (buffer-substring-no-properties beg end)) - ;; Check if this is called twice before modification. When inserting - ;; into zero-width occurrence or between two conjoined occurrences, - ;; both insert-in-front-hooks and insert-behind-hooks will be - ;; called. Two calls will make `iedit-skip-modification-once' true. - (setq iedit-skip-modification-once (not iedit-skip-modification-once))) - ;; after modification - (when (not iedit-buffering) - (if iedit-skip-modification-once - ;; Skip the first hook - (setq iedit-skip-modification-once nil) - (setq iedit-skip-modification-once t) - (when (or (eq 0 change) ;; insertion - (eq beg end) ;; deletion - (not (string= iedit-before-modification-string ;; replacement - (buffer-substring-no-properties beg end)))) - (iedit-update-occurrences-2 occurrence after beg end change)))))))) - -(defun iedit-update-occurrences-2 (occurrence after beg end &optional change) - "" + ;; before modification + (if (null after) + (if (or (< beg (overlay-start occurrence)) + (> end (overlay-end occurrence))) + (progn (setq iedit-aborting t) ; abort iedit-mode + (add-hook 'post-command-hook 'iedit-reset-aborting nil t)) + (setq iedit-before-modification-string + (buffer-substring-no-properties beg end)) + ;; Check if this is called twice before modification. When inserting + ;; into zero-width occurrence or between two conjoined occurrences, + ;; both insert-in-front-hooks and insert-behind-hooks will be + ;; called. Two calls will make `iedit-skip-modification-once' true. + (setq iedit-skip-modification-once (not iedit-skip-modification-once))) + ;; after modification + (when (not iedit-buffering) + (if iedit-skip-modification-once + ;; Skip the first hook + (setq iedit-skip-modification-once nil) + (setq iedit-skip-modification-once t) + (when (or (eq 0 change) ;; insertion + (eq beg end) ;; deletion + (not (string= iedit-before-modification-string ;; replacement + (buffer-substring-no-properties beg end)))) + (let* ((inslen (- end beg)) + (dellen change)) + (push (list occurrence + (- beg 1) ; From 1 to beg + (- (point-max) end) ; From end to point-max + (- inslen dellen)) ; changed number + iedit-after-change-list))))))))) + +(defun iedit-update-occurrences-2 () + "The second part of updating other occurrences. + +This part is running in `post-command-hook'. It combines +`iedit-after-change-list' into one change and then call the third +part to apply it to all the other occurrences." + (when iedit-after-change-list + (let ((beg (buffer-size)) + (end (buffer-size)) + (change 0)) + (dolist (mod iedit-after-change-list) + (setq beg (min beg (nth 1 mod))) + (setq end (min end (nth 2 mod))) + (setq change (+ change (nth 3 mod)))) + (let* ((begpos (1+ beg)) + (endpos (- (point-max) end)) + (inslen (- endpos begpos)) + (dellen (- inslen change)) + (endpos (+ begpos inslen))) + (iedit-update-occurrences-3 + (caar iedit-after-change-list) + begpos + endpos + dellen) + (setq iedit-after-change-list nil))))) + +(defun iedit-update-occurrences-3 (occurrence beg end &optional change) + "The third part of updateing occurrences. +Apply the change to all the other occurrences. " (let ((inhibit-modification-hooks t) (offset (- beg (overlay-start occurrence))) (value (buffer-substring-no-properties beg end))) (save-excursion - ;; insertion or yank - (if (= 0 change) - (dolist (another-occurrence iedit-occurrences-overlays) + (dolist (another-occurrence iedit-occurrences-overlays) (let* ((beginning (+ (overlay-start another-occurrence) offset)) (ending (+ beginning (- end beg)))) (when (not (eq another-occurrence occurrence)) - (goto-char beginning) - (insert-and-inherit value) - ;; todo: reconsider this change Quick fix for - ;; multi-occur occur-edit-mode: multi-occur depend on - ;; after-change-functions to update original - ;; buffer. Since inhibit-modification-hooks is set to - ;; non-nil, after-change-functions hooks are not going - ;; to be called for the changes of other occurrences. - ;; So run the hook here. + (when change (delete-region beginning (+ beginning change))) ;; delete + (when (/= beg end) ;; insert + (goto-char beginning) + (insert-and-inherit value)) + ;; todo: reconsider this change Quick fix for multi-occur + ;; occur-edit-mode: multi-occur depend on after-change-functions + ;; to update original buffer. Since inhibit-modification-hooks + ;; is set to non-nil, after-change-functions hooks are not going + ;; to be called for the changes of other occurrences. So run + ;; the hook here. (run-hook-with-args 'after-change-functions beginning ending change)) - (iedit-move-conjoined-overlays another-occurrence))) - ;; deletion - (dolist (another-occurrence (remove occurrence iedit-occurrences-overlays)) - (let ((beginning (+ (overlay-start another-occurrence) offset))) - (delete-region beginning (+ beginning change)) - (unless (eq beg end) ;; replacement - (goto-char beginning) - (insert-and-inherit value)) - (run-hook-with-args 'after-change-functions - beginning - (+ beginning (- beg end)) - change))))))) + (iedit-move-conjoined-overlays another-occurrence)))))) (defun iedit-next-occurrence () "Move forward to the next occurrence in the `iedit'. diff --git a/iedit-rect.el b/iedit-rect.el index be80924..7accdad 100644 --- a/iedit-rect.el +++ b/iedit-rect.el @@ -2,7 +2,7 @@ ;; Copyright (C) 2010, 2011, 2012 Victor Ren -;; Time-stamp: <2020-04-12 14:56:20 Victor Ren> +;; Time-stamp: <2020-07-21 11:35:39 Victor Ren> ;; Author: Victor Ren ;; Keywords: occurrence region simultaneous rectangle refactoring ;; Version: 0.9.9.9 @@ -147,6 +147,7 @@ Commands: (number-to-string (length iedit-occurrences-overlays))) 'face 'font-lock-warning-face)) + (iedit-lib-start) (force-mode-line-update) (add-hook 'before-revert-hook 'iedit-rectangle-done nil t) (add-hook 'kbd-macro-termination-hook 'iedit-rectangle-done nil t) @@ -159,7 +160,7 @@ Save the current occurrence string locally and globally. Save the initial string globally." (when iedit-buffering (iedit-stop-buffering)) - (iedit-cleanup) + (iedit-lib-cleanup) (setq iedit-rectangle-mode nil) (force-mode-line-update) (remove-hook 'before-revert-hook 'iedit-rectangle-done t) diff --git a/iedit-tests.el b/iedit-tests.el index 133cd28..e9a6655 100644 --- a/iedit-tests.el +++ b/iedit-tests.el @@ -2,7 +2,7 @@ ;; Copyright (C) 2010, 2011, 2012 Victor Ren -;; Time-stamp: <2020-07-16 22:32:42 Victor Ren> +;; Time-stamp: <2020-07-21 01:58:10 Victor Ren> ;; Author: Victor Ren ;; Version: 0.9.9.9 ;; X-URL: https://www.emacswiki.org/emacs/Iedit @@ -167,7 +167,8 @@ foo" (should (string= iedit-initial-string-local "foo")) (should (eq 'selection iedit-occurrence-type-local)) (goto-char 1) - (insert "123") + (insert "123") + (run-hooks 'post-command-hook) (should (string= (buffer-string) "123foobar 123foo123foo123foo @@ -175,6 +176,7 @@ foo" 123foo")) (forward-char 3) (insert "456") + (run-hooks 'post-command-hook) (should (string= (buffer-string) "123foo456bar 123foo456123foo456123foo456 @@ -191,10 +193,12 @@ foo" (goto-char (point-at-eol)) (iedit-mode) (delete-region (point) (1- (point))) + (run-hooks 'post-command-hook) (should (string= (buffer-string) "fo fo")) (insert "b") + (run-hooks 'post-command-hook) (should (string= (buffer-string) "fob fob"))))) @@ -348,18 +352,21 @@ fob"))))) foo" (lambda () (insert "1") + (run-hooks 'post-command-hook) (should (string= (buffer-string) "1foo 1foo barfoo 1foo")) (backward-delete-char 1) + (run-hooks 'post-command-hook) (should (string= (buffer-string) "foo foo barfoo foo")) (capitalize-word 1) + (run-hooks 'post-command-hook) (should (string= (buffer-string) "Foo Foo @@ -368,6 +375,7 @@ fob"))))) ;; test insert from empty (iedit-delete-occurrences) (insert "1") + (run-hooks 'post-command-hook) (should (string= (buffer-string) "1 1 @@ -393,6 +401,7 @@ fob"))))) foo")) (goto-char 7) (insert "1") + (run-hooks 'post-command-hook) (should (string= (buffer-string) "foo 1foo @@ -500,6 +509,7 @@ fob"))))) (lambda () (iedit-toggle-buffering) (insert "bar") + (run-hooks 'post-command-hook) (should (string= (buffer-string) "barfoo foo @@ -540,6 +550,7 @@ fob"))))) (push nil buffer-undo-list) (call-interactively 'iedit-mode) (insert "bar") + (run-hooks 'post-command-hook) (should (string= (buffer-string) "barfoo foo diff --git a/iedit.el b/iedit.el index 84e09b5..bdb7885 100644 --- a/iedit.el +++ b/iedit.el @@ -2,7 +2,7 @@ ;; Copyright (C) 2010, 2011, 2012 Victor Ren -;; Time-stamp: <2020-07-16 13:14:05 Victor Ren> +;; Time-stamp: <2020-07-21 13:52:42 Victor Ren> ;; Author: Victor Ren ;; Keywords: occurrence region simultaneous refactoring ;; Version: 0.9.9.9 @@ -447,7 +447,7 @@ Keymap used within overlays: (setq mark-active nil) (run-hooks 'deactivate-mark-hook) (when iedit-mode - (iedit-cleanup)) + (iedit-lib-cleanup)) (setq result (catch 'not-same-length (iedit-start regexp (point-min) (point-max)))) @@ -478,6 +478,7 @@ Keymap used within overlays: (setq iedit-mode t)) (when iedit-auto-buffering (iedit-start-buffering)) + (iedit-lib-start) (run-hooks 'iedit-mode-hook) (add-hook 'before-revert-hook 'iedit-done nil t) (add-hook 'kbd-macro-termination-hook 'iedit-done nil t) @@ -578,7 +579,7 @@ the initial string globally." (setq iedit-num-lines-to-expand-up 0) (setq iedit-num-lines-to-expand-down 0) - (iedit-cleanup) + (iedit-lib-cleanup) (when iedit-is-narrowed (widen) @@ -691,7 +692,7 @@ controlled with `where' ('top to act on the top, anything else for the bottom). If amount is negative, collapses the top or bottom of the search region by `-amount' lines." (let ((occurrence (iedit-current-occurrence-string))) - (iedit-cleanup) + (iedit-lib-cleanup) (if (eq where 'top) (setq iedit-num-lines-to-expand-up (max 0 (+ amount iedit-num-lines-to-expand-up)))