branch: externals/phpinspect commit 5fab07b426d8f2b54621a2d7b989f8b76239d5b3 Author: Hugo Thunnissen <de...@hugot.nl> Commit: Hugo Thunnissen <de...@hugot.nl>
Keep track of multi-call edits of the same region --- phpinspect-edtrack.el | 70 ++++++++++++++++++++++++++++++++++----------------- test/test-edtrack.el | 23 +++++++++++++++++ 2 files changed, 70 insertions(+), 23 deletions(-) diff --git a/phpinspect-edtrack.el b/phpinspect-edtrack.el index ae28dfc546..b7b899c949 100644 --- a/phpinspect-edtrack.el +++ b/phpinspect-edtrack.el @@ -27,7 +27,13 @@ (edits nil :type list) (taint-pool nil - :type list)) + :type list) + (last-edit nil + :type cons + :documentation "Last registered edit") + (last-edit-start -1 + :type integer + :documentation "Last registered edit start position")) (defsubst phpinspect-edtrack-make-taint-iterator (track) (cons (car (phpinspect-edtrack-taint-pool track)) @@ -105,34 +111,52 @@ "Edtrack registered change: [start: %d, end: %d, pre-change-length: %d]" start end pre-change-length) - (phpinspect-edtrack-register-taint - track - (phpinspect-edtrack-original-position-at-point track start) - (phpinspect-edtrack-original-position-at-point track (+ start pre-change-length))) + (let ((original-start (phpinspect-edtrack-original-position-at-point track start))) + (phpinspect-edtrack-register-taint + track original-start (+ original-start pre-change-length))) (let ((edit-before (phpinspect-edtrack-edits track))) (while (and edit-before (< end (phpinspect-edit-end edit-before))) (setq edit-before (cdr edit-before))) - (let* ((new-edit (cons - ;; The end location of the edited region, before being - ;; edited, with the delta edits that happened at preceding - ;; points in the buffer subtratted. This corresponds with - ;; the original position of the region end before the - ;; buffer was ever edited. - (phpinspect-edtrack-original-position-at-point - track (+ start pre-change-length)) - - - ;; The delta of this edit. - (- (- end start) pre-change-length)))) - (if edit-before + (let ((delta ;; The delta of this edit. + (- (- end start) pre-change-length)) + new-edit) + (if (= (phpinspect-edtrack-last-edit-start track) start) + ;; `after-change-functions' can be called in succession with the same + ;; start point for a continuously growing edited region. For example, + ;; when typing without interruptions, subsequent calls can be: + ;; [start: 1243, end: 1244, pre-change-length: 0] + ;; [start: 1243, end: 1245, pre-change-length: 0] + ;; [start: 1243, end: 1246, pre-change-length: 0] + ;; [start: 1243, end: 1247, pre-change-length: 0] + ;; + ;; The code below accounts for this scenario by altering the last + ;; registered edit when subsequent calls have the same start point. (progn - (setcdr edit-before (cons (car edit-before) (cdr edit-before))) - (setcar edit-before new-edit)) - (if (phpinspect-edtrack-edits track) - (push new-edit (cdr (last (phpinspect-edtrack-edits track)))) - (push new-edit (phpinspect-edtrack-edits track))))))) + (setq new-edit (phpinspect-edtrack-last-edit track)) + (phpinspect--log "Edtrack: updating growing edit: [%s]" new-edit) + (setcdr new-edit delta)) + ;; Else + (setq new-edit (cons + ;; The end location of the edited region, before being + ;; edited, with the delta edits that happened at preceding + ;; points in the buffer subtratted. This corresponds with + ;; the original position of the region end before the + ;; buffer was ever edited. + (phpinspect-edtrack-original-position-at-point + track (+ start pre-change-length)) + delta)) + (if edit-before + (progn + (setcdr edit-before (cons (car edit-before) (cdr edit-before))) + (setcar edit-before new-edit)) + (if (phpinspect-edtrack-edits track) + (push new-edit (cdr (last (phpinspect-edtrack-edits track)))) + (push new-edit (phpinspect-edtrack-edits track))))) + + (setf (phpinspect-edtrack-last-edit track) new-edit) + (setf (phpinspect-edtrack-last-edit-start track) start)))) (defsubst phpinspect-taint-start (taint) (car taint)) diff --git a/test/test-edtrack.el b/test/test-edtrack.el index 4391598f33..e4e9e03613 100644 --- a/test/test-edtrack.el +++ b/test/test-edtrack.el @@ -88,3 +88,26 @@ (should (phpinspect-taint-iterator-token-is-tainted-p iterator (phpinspect-make-meta nil 100 130 nil nil))))) + +(ert-deftest phpinspect-edtrack-edit-derived-taint-iterator () + (let ((track (phpinspect-make-edtrack)) + iterator) + (phpinspect-edtrack-register-edit track 10 20 5) + (phpinspect-edtrack-register-edit track 15 30 0) + (phpinspect-edtrack-register-edit track 20 25 10) + + (setq iterator (phpinspect-edtrack-make-taint-iterator track)) + + (should (phpinspect-taint-iterator-region-is-tainted-p iterator 15 20)) + (should (phpinspect-taint-iterator-region-is-tainted-p iterator 25 30)) + (should-not (phpinspect-taint-iterator-region-is-tainted-p iterator 30 35)))) + +(ert-deftest phpinspect-edtrack-taint-overlapping-edits () + (let ((track (phpinspect-make-edtrack)) + iterator) + (phpinspect-edtrack-register-edit track 10 20 5) + + (should (equal (list (cons 10 15)) (phpinspect-edtrack-taint-pool track))) + + (phpinspect-edtrack-register-edit track 15 0 1) + (should (equal (list (cons 10 16)) (phpinspect-edtrack-taint-pool track)))))