summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <mail@nicolasgoaziou.fr>2014-07-03 20:10:47 (GMT)
committer Nicolas Goaziou <mail@nicolasgoaziou.fr>2014-07-05 08:54:09 (GMT)
commitdf9ccbd11918c8e7273b98520f335573f512aa05 (patch)
tree43daad01a96b6e7f748027a0fb6d80aeb7767b90
parentf1433d82aea7c48a3482feb4ed2e33ffef47a074 (diff)
downloadorg-mode-df9ccbd11918c8e7273b98520f335573f512aa05.zip
org-mode-df9ccbd11918c8e7273b98520f335573f512aa05.tar.gz
org-element: Reach orphaned elements during cache sync
* lisp/org-element.el (org-element--cache-sync-requests): Change pattern. (org-element--cache-sync, org-element--cache-submit-request): Update request pattern. (org-element--cache-process-request): Remove orphaned elements during first phase. An orphaned element is an element not directly altered by changes to buffer but with one of its parent removed.
-rw-r--r--lisp/org-element.el108
1 files changed, 61 insertions, 47 deletions
diff --git a/lisp/org-element.el b/lisp/org-element.el
index 0aaa991..1aa7fad 100644
--- a/lisp/org-element.el
+++ b/lisp/org-element.el
@@ -4703,7 +4703,7 @@ This cache is used in `org-element-context'.")
A request is a vector with the following pattern:
- \[NEXT BEG END OFFSET PARENT PHASE]
+ \[NEXT BEG END OFFSET OUTREACH PARENT PHASE]
Processing a synchronization request consists of three phases:
@@ -4713,9 +4713,9 @@ Processing a synchronization request consists of three phases:
During phase 0, NEXT is the key of the first element to be
removed, BEG and END is buffer position delimiting the
-modifications. Every element starting between them (inclusive)
-are removed. PARENT, when non-nil, is the parent of the first
-element to be removed.
+modifications. Elements starting between them (inclusive) are
+removed and so are those contained within OUTREACH. PARENT, when
+non-nil, is the parent of the first element to be removed.
During phase 1, NEXT is the key of the next known element in
cache and BEG its beginning position. Parse buffer between that
@@ -5047,7 +5047,7 @@ updated before current modification are actually submitted."
(when next
(incf (aref next 3) (aref request 3))
(aset next 2 (aref request 2))
- (aset next 5 (aref request 5)))
+ (aset next 6 (aref request 6)))
(setq org-element--cache-sync-requests
(cdr org-element--cache-sync-requests))))
;; If more requests are awaiting, set idle timer accordingly.
@@ -5077,7 +5077,7 @@ more information.
Throw `interrupt' if the process stops before completing the
request."
(catch 'quit
- (when (= (aref request 5) 0)
+ (when (= (aref request 6) 0)
;; Phase 1.
;;
;; Delete all elements starting after BEG, but not after buffer
@@ -5087,7 +5087,8 @@ request."
;; a deletion modifies structure of the balanced tree.
(catch 'end-phase
(let ((beg (aref request 0))
- (end (aref request 2)))
+ (end (aref request 2))
+ (outreach (aref request 4)))
(while t
(when (org-element--cache-interrupt-p time-limit)
(throw 'interrupt nil))
@@ -5108,18 +5109,22 @@ request."
node nil)))))
(if data
(let ((pos (org-element-property :begin data)))
- (if (and (<= pos end)
- (or (not next)
- (org-element--cache-key-less-p data-key next)))
+ (if (if (or (not next)
+ (org-element--cache-key-less-p data-key next))
+ (<= pos end)
+ (let ((up data))
+ (while (and up (not (eq up outreach)))
+ (setq up (org-element-property :parent up)))
+ up))
(org-element--cache-remove data)
(aset request 0 data-key)
(aset request 1 pos)
- (aset request 5 1)
+ (aset request 6 1)
(throw 'end-phase nil)))
;; No element starting after modifications left in
;; cache: further processing is futile.
(throw 'quit t)))))))
- (when (= (aref request 5) 1)
+ (when (= (aref request 6) 1)
;; Phase 2.
;;
;; Phase 1 left a hole in the parse tree. Some elements after
@@ -5158,8 +5163,8 @@ request."
(let ((limit (+ (aref request 1) (aref request 3) extra)))
(when (and threshold (< threshold limit)) (throw 'interrupt nil))
(let ((parent (org-element--parse-to limit t time-limit)))
- (aset request 4 parent)
- (aset request 5 2)
+ (aset request 5 parent)
+ (aset request 6 2)
(throw 'end-phase nil)))))
;; Phase 3.
;;
@@ -5174,7 +5179,7 @@ request."
;; request is updated.
(let ((start (aref request 0))
(offset (aref request 3))
- (parent (aref request 4))
+ (parent (aref request 5))
(node (org-element--cache-root))
(stack (list nil))
(leftp t)
@@ -5194,7 +5199,7 @@ request."
;; Handle interruption request. Update current request.
(when (or exit-flag (org-element--cache-interrupt-p time-limit))
(aset request 0 key)
- (aset request 4 parent)
+ (aset request 5 parent)
(throw 'interrupt nil))
;; Shift element.
(unless (zerop offset)
@@ -5474,7 +5479,7 @@ change, as an integer."
(let ((next (car org-element--cache-sync-requests))
delete-to delete-from)
(if (and next
- (zerop (aref next 5))
+ (zerop (aref next 6))
(> (setq delete-to (+ (aref next 2) (aref next 3))) end)
(<= (setq delete-from (aref next 1)) end))
;; Current changes can be merged with first sync request: we
@@ -5485,7 +5490,7 @@ change, as an integer."
;; boundaries of robust parents, if any. Otherwise, find
;; first element to remove and update request accordingly.
(if (> beg delete-from)
- (let ((up (aref next 4)))
+ (let ((up (aref next 5)))
(while up
(org-element--cache-shift-positions
up offset '(:contents-end :end))
@@ -5494,7 +5499,7 @@ change, as an integer."
(when first
(aset next 0 (org-element--cache-key first))
(aset next 1 (org-element-property :begin first))
- (aset next 4 (org-element-property :parent first))))))
+ (aset next 5 (org-element-property :parent first))))))
;; Ensure cache is correct up to END. Also make sure that NEXT,
;; if any, is no longer a 0-phase request, thus ensuring that
;; phases are properly ordered. We need to provide OFFSET as
@@ -5503,34 +5508,43 @@ change, as an integer."
;; the first request).
(when next (org-element--cache-sync (current-buffer) end offset))
(let ((first (org-element--cache-for-removal beg end offset)))
- (cond
- ;; Changes happened before the first known element. Shift
- ;; the rest of the cache.
- ((and first (> (org-element-property :begin first) end))
- (push (vector (org-element--cache-key first) nil nil offset nil 2)
- org-element--cache-sync-requests))
- ;; There is at least an element to remove. Find position
- ;; past every element containing END.
- (first
- (if (> (org-element-property :end first) end)
- (setq end (org-element-property :end first))
- (let ((element (org-element--cache-find end)))
- (setq end (org-element-property :end element))
- (let ((up element))
- (while (and (setq up (org-element-property :parent up))
- (>= (org-element-property :begin up) beg))
- (setq end (org-element-property :end up))))))
- (push (vector (org-element--cache-key first)
- (org-element-property :begin first)
- end
- offset
- (org-element-property :parent first)
- 0)
- org-element--cache-sync-requests))
- ;; No element to remove. No need to re-parent either.
- ;; Simply shift additional elements, if any, by OFFSET.
- (org-element--cache-sync-requests
- (incf (aref (car org-element--cache-sync-requests) 3) offset)))))))
+ (if first
+ (push (let ((beg (org-element-property :begin first))
+ (key (org-element--cache-key first)))
+ (cond
+ ;; When changes happen before the first known
+ ;; element, shift the rest of the cache.
+ ((> beg end)
+ (vector key nil nil offset nil nil 2))
+ ;; Otherwise, we find the first non robust
+ ;; element containing END. All elements between
+ ;; FIRST and this one are to be removed.
+ ;;
+ ;; Among them, some could be located outside the
+ ;; synchronized part of the cache, in which case
+ ;; comparing buffer positions to find them is
+ ;; useless. Instead, we store the element
+ ;; containing them in the request itself. All
+ ;; its children will be removed.
+ ((let ((first-end (org-element-property :end first)))
+ (and (> first-end end)
+ (vector key beg first-end offset first
+ (org-element-property :parent first) 0))))
+ (t
+ (let* ((element (org-element--cache-find end))
+ (end (org-element-property :end element))
+ (up element))
+ (while (and (setq up (org-element-property :parent up))
+ (>= (org-element-property :begin up) beg))
+ (setq end (org-element-property :end up)
+ element up))
+ (vector key beg end offset element
+ (org-element-property :parent first) 0)))))
+ org-element--cache-sync-requests)
+ ;; No element to remove. No need to re-parent either.
+ ;; Simply shift additional elements, if any, by OFFSET.
+ (when org-element--cache-sync-requests
+ (incf (aref (car org-element--cache-sync-requests) 3) offset)))))))
;;;; Public Functions