Skip to content

Commit

Permalink
Update occurrences in `post-command-hook'
Browse files Browse the repository at this point in the history
Before the occurrences are updated in `modification-hooks' directly.  Some
commands adjust the current point after `modification-hooks' based on the saved
position, e.g. yank, replace-match. Then the point might end up to a wrong
place.

In this commit, a hook is added into `post-command-hook' when iedit-mode is
acitve.  The change in `modification-hooks' are collected into a
`iedit-after-change-list'.  In the hook, the list are accumlated into one change
and then applied to all the other occurrences.
  • Loading branch information
victorhge committed Aug 5, 2020
1 parent 77eb0a1 commit be44da7
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 61 deletions.
137 changes: 84 additions & 53 deletions iedit-lib.el
Original file line number Diff line number Diff line change
Expand Up @@ -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 <victorhge@gmail.com>
;; Keywords: occurrence region simultaneous rectangle refactoring
;; Version: 0.9.9.9
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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'.
Expand Down
5 changes: 3 additions & 2 deletions iedit-rect.el
Original file line number Diff line number Diff line change
Expand Up @@ -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 <victorhge@gmail.com>
;; Keywords: occurrence region simultaneous rectangle refactoring
;; Version: 0.9.9.9
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
15 changes: 13 additions & 2 deletions iedit-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -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 <victorhge@gmail.com>
;; Version: 0.9.9.9
;; X-URL: https://www.emacswiki.org/emacs/Iedit
Expand Down Expand Up @@ -167,14 +167,16 @@ 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
123foo123foo
123foo"))
(forward-char 3)
(insert "456")
(run-hooks 'post-command-hook)
(should (string= (buffer-string)
"123foo456bar
123foo456123foo456123foo456
Expand All @@ -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")))))
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -393,6 +401,7 @@ fob")))))
foo"))
(goto-char 7)
(insert "1")
(run-hooks 'post-command-hook)
(should (string= (buffer-string)
"foo
1foo
Expand Down Expand Up @@ -500,6 +509,7 @@ fob")))))
(lambda ()
(iedit-toggle-buffering)
(insert "bar")
(run-hooks 'post-command-hook)
(should (string= (buffer-string)
"barfoo
foo
Expand Down Expand Up @@ -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
Expand Down
9 changes: 5 additions & 4 deletions iedit.el
Original file line number Diff line number Diff line change
Expand Up @@ -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 <victorhge@gmail.com>
;; Keywords: occurrence region simultaneous refactoring
;; Version: 0.9.9.9
Expand Down Expand Up @@ -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))))
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)))
Expand Down

0 comments on commit be44da7

Please sign in to comment.