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)))))

Reply via email to