[lice @ dont load the .asd file]
[lice.git] / intervals.lisp
blobb82b7c422e9269582cc3418fe3b97854ee8736cc
1 ;;; implentation of an interval tree
3 (in-package "LICE")
5 (defvar *text-property-default-nonsticky* nil
6 "Alist of properties vs the corresponding non-stickinesses.
7 Each element has the form (PROPERTY . NONSTICKINESS).
9 If a character in a buffer has PROPERTY, new text inserted adjacent to
10 the character doesn't inherit PROPERTY if NONSTICKINESS is non-nil,
11 inherits it if NONSTICKINESS is nil. The front-sticky and
12 rear-nonsticky properties of the character overrides NONSTICKINESS.")
14 (defvar *char-property-alias-alist* nil
15 "Alist of alternative properties for properties without a value.
16 Each element should look like (PROPERTY ALTERNATIVE1 ALTERNATIVE2...).
17 If a piece of text has no direct value for a particular property, then
18 this alist is consulted. If that property appears in the alist, then
19 the first non-nil value from the associated alternative properties is
20 returned.")
22 (defvar *default-text-properties* nil
23 "Property-list used as default values.
24 The value of a property in this list is seen as the value for every
25 character that does not have its own value for that property.")
27 (defmacro doplist ((sym val plist &optional ret) &body body)
28 "Loop through each symbol value pair in PLIST executing BODY."
29 (let ((csym (gensym)))
30 `(do* ((,csym ,plist (cddr ,csym)))
31 ((endp ,csym) ,ret)
32 (let ((,sym (car ,csym))
33 (,val (cadr ,csym)))
34 ,@body))))
36 (defun interval-has-object (interval)
37 (and (interval-parent interval)
38 (not (typep (interval-parent interval) 'interval))))
40 (defun interval-has-parent (interval)
41 (and (interval-parent interval)
42 (typep (interval-parent interval) 'interval)))
44 (defun check-total-length (interval)
45 (when (< (interval-length interval) 0)
46 (error "Interval length < 0 ~a" interval)))
48 (defun create-root-interval (object)
49 "Return a fresh interval for OBJECT."
50 (let ((i (make-interval :pt 0 :length 0 :parent object
51 :left nil :right nil :plist nil)))
52 (cond
53 ((typep object 'buffer)
54 (setf (intervals object) i
55 ;; XXX: are buffer-max buffer-min the right functions to use?
56 (interval-length i) (- (buffer-max object) (buffer-min object))
57 (interval-pt i) (buffer-min object)))
58 ((typep object 'pstring)
59 (setf (intervals object) i
60 (interval-length i) (pstring-length object))))
61 i))
63 (defun plists-equal (p1 p2)
64 "Return 1 if the two properties lists are equal, 0 otherwise."
65 (when (= (length p1)
66 (length p2))
67 (doplist (sym val p1 t)
68 (unless (eql val (getf p2 sym))
69 (return-from plists-equal nil)))))
71 (defun intervals-equal (i1 i2)
72 "Return T if the two intervals have the same properties, NIL otherwise."
73 (plists-equal (interval-plist i1) (interval-plist i2)))
75 (defun lookup-char-property (plist prop textprop)
76 (let* ((val (getf plist prop))
77 (cat (getf plist 'category)))
78 (when val
79 (return-from lookup-char-property val))
80 ;; This is what GNU emacs does...
81 (when (and (symbolp cat)
82 (get cat prop))
83 (return-from lookup-char-property (get cat prop)))
84 ;; Check for alternative properties
85 (let ((tail (assoc prop *char-property-alias-alist*)))
86 (when tail
87 (or (find-if (lambda (p)
88 (getf plist p))
89 (cdr tail))
90 (and textprop
91 (consp *default-text-properties*)
92 (getf *default-text-properties* prop)))))))
94 (defun textget (plist sym)
95 "Get the value of property PROP from PLIST,
96 which is the plist of an interval.
97 We check for direct properties, for categories with property PROP,
98 and for PROP appearing on the default-text-properties list."
99 (lookup-char-property plist sym t))
101 (defun total-length (root)
102 "TOTAL_LENGTH"
103 (if root
104 (interval-length root)
107 (defun left-total-length (root)
108 (if (interval-left root)
109 (interval-length (interval-left root))
112 (defun right-total-length (root)
113 (if (interval-right root)
114 (interval-length (interval-right root))
117 (defun interval-text-length (root)
118 "The size of text represented by this interval alone. LENGTH."
119 (if root
120 (- (total-length root)
121 (total-length (interval-right root))
122 (total-length (interval-left root)))
125 (defun right-child-p (root)
126 (eq root (interval-right (interval-parent root))))
128 (defun left-child-p (root)
129 (eq root (interval-left (interval-parent root))))
131 (defun interval-past-top-p (interval)
132 "Return t if INTERVAL is not an interval. Used to check when we've
133 climbed past the root interval."
134 (not (typep (interval-parent interval) 'interval)))
136 (defun root-interval-p (i)
137 "Return true if i is the root interval node."
138 (or (null (interval-parent i))
139 (not (typep (interval-parent i) 'interval))))
141 (defun root-interval (interval)
142 "Return the root of interval."
143 (do ((i interval (interval-parent i)))
144 ((root-interval-p i) i)))
146 (defun leaf-interval-p (i)
147 "Return T if this interval has no children."
148 (and (null (interval-left i))
149 (null (interval-right i))))
151 (defun only-interval-p (i)
152 "Return T if this interval is the only interval in the interval tree."
153 (and (root-interval-p i)
154 (leaf-interval-p i)))
156 (defun default-interval-p (i)
157 (or (null i)
158 (null (interval-plist i))))
160 (defun rotate-left (interval)
161 "Assuming that a right child exists, perform the following operation:
164 / \ / \
165 B => A
166 / \ / \
169 (let ((old-total (interval-length interval))
170 (b (interval-right interval))
172 ;; Change interval's parent to point b.
173 (unless (root-interval-p interval)
174 (if (left-child-p interval)
175 (setf (interval-left (interval-parent interval)) b)
176 (setf (interval-right (interval-parent interval)) b)))
177 (setf (interval-parent b) (interval-parent interval))
178 ;; Make b the parent of a
179 (setf i (interval-left b)
180 (interval-left b) interval
181 (interval-parent interval) b)
182 ;; make a point to c
183 (setf (interval-right interval) i)
184 (when i
185 (setf (interval-parent i) interval))
186 ;; A's total length is decreased by the length of B and its left child.
187 (decf (interval-length interval) (- (interval-length b)
188 (right-total-length interval)))
189 (check-total-length interval)
190 ;; B must have the same total length of A.
191 (setf (interval-length b) old-total)
192 (check-total-length b)
195 (defun rotate-right (interval)
196 "Assuming that a left child exists, perform the following operation:
199 / \ / \
200 B => A
201 / \ / \
204 (let ((old-total (interval-length interval))
205 (b (interval-left interval))
207 ;; Change interval's parent to point b.
208 (unless (root-interval-p interval)
209 (if (left-child-p interval)
210 (setf (interval-left (interval-parent interval)) b)
211 (setf (interval-right (interval-parent interval)) b)))
212 (setf (interval-parent b) (interval-parent interval))
213 ;; Make b the parent of a
214 (setf i (interval-right b)
215 (interval-right b) interval
216 (interval-parent interval) b)
217 ;; make a point to c
218 (setf (interval-left interval) i)
219 (when i
220 (setf (interval-parent i) interval))
221 ;; A's total length is decreased by the length of B and its left child.
222 (decf (interval-length interval) (- (interval-length b)
223 (left-total-length interval)))
224 (check-total-length interval)
225 ;; B must have the same total length of A.
226 (setf (interval-length b) old-total)
227 (check-total-length b)
230 (defun balance-an-interval (i)
231 (let (old-diff
232 new-diff)
233 (loop
234 (setf old-diff (- (left-total-length i) (right-total-length i)))
235 (cond ((> old-diff 0)
236 ;; Since the left child is longer, there must be one.
237 (setf new-diff (+ (- (interval-length i)
238 (interval-length (interval-left i)))
239 (- (right-total-length (interval-left i))
240 (left-total-length (interval-left i)))))
241 (when (>= (abs new-diff) old-diff)
242 (return-from balance-an-interval i))
243 (setf i (rotate-right i))
244 (balance-an-interval (interval-right i)))
245 ((< old-diff 0)
246 (setf new-diff (+ (- (interval-length i)
247 (interval-length (interval-right i)))
248 (- (left-total-length (interval-right i))
249 (right-total-length (interval-right i)))))
250 (when (>= (abs new-diff) (- old-diff))
251 (return-from balance-an-interval i))
252 (setf i (rotate-left i))
253 (balance-an-interval (interval-left i)))
254 (t (return-from balance-an-interval i))))))
256 (defun balance-intervals (tree)
257 "Balance the interval tree TREE. Balancing is by weight: the amount
258 of text."
259 (labels ((balance (tree)
260 (when (interval-left tree)
261 (balance (interval-left tree)))
262 (when (interval-right tree)
263 (balance (interval-right tree)))
264 (balance-an-interval tree)))
265 (when tree
266 (balance tree))))
268 (defun balance-possible-root-interval (interval)
269 (let ((has-parent nil)
270 parent)
271 (when (null (interval-parent interval))
272 (return-from balance-possible-root-interval interval))
273 (when (interval-has-object interval)
274 (setf parent (interval-parent interval)
275 has-parent t))
276 (setf interval (balance-intervals interval))
277 (when has-parent
278 (setf (intervals parent) interval))
279 interval))
281 (defun split-interval-left (interval offset)
282 (let* ((new-length offset)
283 (new (make-interval :pt (interval-pt interval)
284 :length offset
285 :parent interval)))
286 (incf (interval-pt interval) offset)
287 (if (interval-left interval)
288 (progn
289 (setf (interval-left new) (interval-left interval)
290 (interval-parent (interval-left new)) new
291 (interval-left interval) new
292 (interval-length new) (+ new-length (interval-length (interval-left new))))
293 (check-total-length new)
294 (balance-an-interval new))
295 (progn
296 (setf (interval-left interval) new
297 (interval-length new) new-length)
298 (check-total-length new)))
299 (balance-possible-root-interval interval)
300 new))
302 (defun split-interval-right (interval offset)
303 (let* ((position (interval-pt interval))
304 (new-length (- (interval-text-length interval) offset))
305 (new (make-interval :pt (+ position offset)
306 :length 0
307 :parent interval)))
308 (setf (interval-parent new) interval)
309 (if (interval-right interval)
310 (progn
311 (setf (interval-right new) (interval-right interval)
312 (interval-parent (interval-right interval)) new
313 (interval-right interval) new
314 (interval-length new) (+ new-length (interval-length (interval-right new))))
315 (check-total-length new)
316 (balance-an-interval new))
317 (progn
318 (setf (interval-right interval) new
319 (interval-length new) new-length)
320 (check-total-length new)))
321 (balance-possible-root-interval interval)
322 new))
324 (defun find-interval (tree position)
325 (let ((relative-position position))
326 (when (null tree)
327 (return-from find-interval nil))
328 (assert (<= relative-position (total-length tree)))
329 (balance-possible-root-interval tree)
330 (loop
331 (cond ((< relative-position (left-total-length tree))
332 (setf tree (interval-left tree)))
333 ((and (interval-right tree)
334 (>= relative-position (- (total-length tree)
335 (right-total-length tree))))
336 (decf relative-position (- (total-length tree)
337 (right-total-length tree)))
338 (setf tree (interval-right tree)))
340 (setf (interval-pt tree) (+ (- position relative-position)
341 (left-total-length tree)))
342 (return-from find-interval tree))))))
344 (defun next-interval (interval)
345 (unless (null interval)
346 (let ((i interval)
347 (next-position (+ (interval-pt interval)
348 (interval-text-length interval))))
349 (when (interval-right interval)
350 (setf i (interval-right i))
351 (while (interval-left i)
352 (setf i (interval-left i)))
353 (setf (interval-pt i) next-position)
354 (return-from next-interval i))
355 (loop until (interval-past-top-p i)
356 if (left-child-p i)
357 do (progn
358 (setf i (interval-parent i)
359 (interval-pt i) next-position)
360 (return-from next-interval i))
361 do (setf i (interval-parent i))))))
363 (defun previous-interval (interval)
364 (unless (null interval)
365 (let ((i interval))
366 (when (interval-left interval)
367 (setf i (interval-left i))
368 (while (interval-right i)
369 (setf i (interval-right i)))
370 (setf (interval-pt i) (- (interval-pt interval)
371 (interval-text-length i)))
372 (return-from previous-interval i))
373 (loop until (interval-past-top-p i)
374 if (right-child-p i)
375 do (progn
376 (setf i (interval-parent i)
377 (interval-pt i) (- (interval-pt interval)
378 (interval-text-length i)))
379 (return-from previous-interval i))
380 do (setf i (interval-parent i))))))
382 (defun delete-node (i)
383 ;; Trivial cases
384 (when (null (interval-left i))
385 (return-from delete-node (interval-right i)))
386 (when (null (interval-right i))
387 (return-from delete-node (interval-left i)))
388 ;; Meat
389 (let ((migrate (interval-left i))
390 (this (interval-right i))
391 (migrate-amt (interval-length (interval-left i))))
392 (while (interval-left this)
393 (setf this (interval-left this))
394 (incf (interval-length this) migrate-amt))
395 (check-total-length this)
396 (setf (interval-left this) migrate)
397 (setf (interval-parent migrate) this)
398 (interval-right i)))
400 (defun delete-interval (i)
401 (let ((amt (interval-text-length i))
402 parent)
403 (and (> amt 0)
404 (error "only used on zero length intervals."))
405 (when (root-interval-p i)
406 (let ((owner (interval-parent i)))
407 (setf parent (delete-node i))
408 (when (interval-parent parent)
409 (setf (interval-parent parent) owner))
410 (setf (intervals owner) parent)
411 (return-from delete-interval)))
412 (setf parent (interval-parent i))
413 (if (left-child-p i)
414 (progn
415 (setf (interval-left parent) (delete-node i))
416 (when (interval-left parent)
417 (setf (interval-parent (interval-left parent)) parent)))
418 (progn
419 (setf (interval-right parent) (delete-node i))
420 (when (interval-right parent)
421 (setf (interval-parent (interval-right parent)) parent))))))
423 (defun merge-interval-right (i)
424 (let ((absorb (interval-text-length i))
425 successor)
426 (decf (interval-length i) absorb)
427 (check-total-length i)
428 (when (interval-right i)
429 (setf successor (interval-right i))
430 (while (interval-left successor)
431 (incf (interval-length successor) absorb)
432 (check-total-length successor)
433 (setf successor (interval-left successor)))
434 (incf (interval-length successor) absorb)
435 (check-total-length successor)
436 (delete-interval i)
437 (return-from merge-interval-right successor))
438 (setf successor i)
439 (while (interval-parent successor)
440 (if (left-child-p successor)
441 (progn
442 (setf successor (interval-parent successor))
443 (delete-interval i)
444 (return-from merge-interval-right successor))
445 (progn
446 (setf successor (interval-parent successor))
447 (decf (interval-length successor) absorb)
448 (check-total-length successor))))
449 (error "merge-interval-right: gak")))
451 (defun merge-interval-left (i)
452 (let ((absorb (interval-text-length i))
453 predecessor)
454 (decf (interval-length i) absorb)
455 (check-total-length i)
456 (when (interval-left i)
457 (setf predecessor (interval-left i))
458 (while (interval-right predecessor)
459 (incf (interval-length predecessor) absorb)
460 (check-total-length predecessor)
461 (setf predecessor (interval-right predecessor)))
462 (incf (interval-length predecessor) absorb)
463 (check-total-length predecessor)
464 (delete-interval i)
465 (return-from merge-interval-left predecessor))
466 (setf predecessor i)
467 (while (interval-parent predecessor)
468 (when (interval-right predecessor)
469 (setf predecessor (interval-parent predecessor))
470 (delete-interval i)
471 (return-from merge-interval-left predecessor))
472 (setf predecessor (interval-parent predecessor))
473 (decf (interval-length predecessor) absorb)
474 (check-total-length predecessor)
476 (error "merge-interval-left: gak")))
478 (defun copy-properties (source target)
479 (when (and (default-interval-p source)
480 (default-interval-p target))
481 (return-from copy-properties))
482 (setf (interval-plist target) (copy-list (interval-plist source))))
484 (defun merge-properties (source target)
485 "/* Merge the properties of interval SOURCE into the properties of
486 interval TARGET. That is to say, each property in SOURCE is added to
487 TARGET if TARGET has no such property as yet. */"
488 (unless (and (default-interval-p source)
489 (default-interval-p target))
490 (doplist (sym val (interval-plist source))
491 (let ((found (getf (interval-plist target) sym)))
492 (unless found
493 (setf (getf (interval-plist target) sym) val))))))
495 (defun merge-properties-sticky (pleft pright)
496 "Any property might be front-sticky on the left, rear-sticky on the left,
497 front-sticky on the right, or rear-sticky on the right; the 16 combinations
498 can be arranged in a matrix with rows denoting the left conditions and
499 columns denoting the right conditions:
500 _ __ _
501 _ FR FR FR FR
502 FR__ 0 1 2 3
503 _FR 4 5 6 7
504 FR 8 9 A B
505 FR C D E F
507 left-props = '(front-sticky (p8 p9 pa pb pc pd pe pf)
508 rear-nonsticky (p4 p5 p6 p7 p8 p9 pa pb)
509 p0 L p1 L p2 L p3 L p4 L p5 L p6 L p7 L
510 p8 L p9 L pa L pb L pc L pd L pe L pf L)
511 right-props = '(front-sticky (p2 p3 p6 p7 pa pb pe pf)
512 rear-nonsticky (p1 p2 p5 p6 p9 pa pd pe)
513 p0 R p1 R p2 R p3 R p4 R p5 R p6 R p7 R
514 p8 R p9 R pa R pb R pc R pd R pe R pf R)
516 We inherit from whoever has a sticky side facing us. If both sides
517 do (cases 2, 3, E, and F), then we inherit from whichever side has a
518 non-nil value for the current property. If both sides do, then we take
519 from the left.
521 When we inherit a property, we get its stickiness as well as its value.
522 So, when we merge the above two lists, we expect to get this:
524 result = '(front-sticky (p6 p7 pa pb pc pd pe pf)
525 rear-nonsticky (p6 pa)
526 p0 L p1 L p2 L p3 L p6 R p7 R
527 pa R pb R pc L pd L pe L pf L)
529 The optimizable special cases are:
530 left rear-nonsticky = nil, right front-sticky = nil (inherit left)
531 left rear-nonsticky = t, right front-sticky = t (inherit right)
532 left rear-nonsticky = t, right front-sticky = nil (inherit none)"
533 (labels ((tmem (sym set)
534 ;; Test for membership, allowing for t (actually any
535 ;; non-cons) to mean the universal set."
536 (if (consp set)
537 (find sym set)
538 set)))
539 (let (props
540 front
541 rear
542 (lfront (getf pleft 'front-sticky))
543 (lrear (getf pleft 'rear-nonsticky))
544 (rfront (getf pright 'front-sticky))
545 (rrear (getf pright 'rear-nonsticky))
546 cat use-left use-right)
547 (doplist (sym rval pright)
548 (unless (or (eq sym 'rear-nonsticky)
549 (eq sym 'front-sticky))
550 ;; Indicate whether the property is explicitly
551 ;; defined on the left. (We know it is defined
552 ;; explicitly on the right because otherwise we don't
553 ;; get here.)
554 (let* ((lval (getf pleft sym))
555 ;; Even if lrear or rfront say nothing about the
556 ;; stickiness of SYM,
557 ;; Vtext_property_default_nonsticky may give
558 ;; default stickiness to SYM.
559 (tmp (assoc sym *text-property-default-nonsticky*)))
560 (setf use-left (and lval
561 (not (or (tmem sym lrear)
562 (and (consp tmp)
563 (cdr tmp)))))
564 use-right (or (tmem sym lrear)
565 (and (consp tmp)
566 (null (cdr tmp)))))
567 (when (and use-left
568 use-right)
569 (cond ((null lval)
570 (setf use-left nil))
571 ((null rval)
572 (setf use-right nil))))
573 (cond (use-left
574 ;; We build props as (value sym ...) rather than (sym value ...)
575 ;; because we plan to nreverse it when we're done.
576 (setf (getf props sym) lval)
577 (when (tmem sym lfront)
578 (push sym front))
579 (when (tmem sym lrear)
580 (push sym rear)))
581 (use-right
582 (setf (getf props sym) rval)
583 (when (tmem sym rfront)
584 (push sym front))
585 (when (tmem sym rrear)
586 (push sym rear)))))))
587 ;; Now go through each element of PLEFT.
588 (doplist (sym lval pleft)
589 (unless (or (eq sym 'rear-nonsticky)
590 (eq sym 'front-sticky))
591 ;; If sym is in PRIGHT, we've already considered it.
592 (let* ((present (getf pright sym))
593 ;; Even if lrear or rfront say nothing about the
594 ;; stickiness of SYM,
595 ;; Vtext_property_default_nonsticky may give
596 ;; default stickiness to SYM.
597 (tmp (assoc sym *text-property-default-nonsticky*)))
598 ;; XXX: if sym is set in pright to nil, its the same
599 ;; as sym not being in the list.
600 (unless present
601 ;; Since rval is known to be nil in this loop, the test simplifies.
602 (cond ((not (or (tmem sym lrear)
603 (and (consp tmp)
604 (cdr tmp))))
605 (setf (getf props sym) lval)
606 (when (tmem sym lfront)
607 (push sym front)))
608 ((or (tmem sym rfront)
609 (and (consp tmp)
610 (null (cdr tmp))))
611 ;; The value is nil, but we still inherit the stickiness
612 ;; from the right.
613 (setf (getf props sym) lval)
614 (when (tmem sym rrear)
615 (push sym rear))))))))
616 (when rear
617 (setf (getf props 'rear-nonsticky) (nreverse rear)))
618 (setf cat (textget props 'category))
619 ;; If we have inherited a front-stick category property that is t,
620 ;; we don't need to set up a detailed one.
621 (when (and front
622 (not (and cat
623 (symbolp cat)
624 (eq (get cat 'front-sticky) t))))
625 (setf (getf props 'front-sticky) (nreverse front)))
626 props)))
628 (defun adjust-intervals-for-insertion (tree position length)
629 "Effect an adjustment corresponding to the addition of LENGTH characters
630 of text. Do this by finding the interval containing POSITION in the
631 interval tree TREE, and then adjusting all of its ancestors by adding
632 LENGTH to them.
634 If POSITION is the first character of an interval, meaning that point
635 is actually between the two intervals, make the new text belong to
636 the interval which is \"sticky\".
638 If both intervals are \"sticky\", then make them belong to the left-most
639 interval. Another possibility would be to create a new interval for
640 this text, and make it have the merged properties of both ends."
641 (let* ((parent (interval-parent tree))
642 (offset (if (typep parent 'buffer)
643 (buffer-min parent)
645 i temp eobp)
646 ;; If inserting at point-max of a buffer, that position will be out
647 ;; of range. Remember that buffer positions are 1-based.
648 (when (>= position (+ (total-length tree) offset))
649 (setf position (+ (total-length tree) offset)
650 eobp t))
651 (setf i (find-interval tree position))
652 ;; If in middle of an interval which is not sticky either way,
653 ;; we must not just give its properties to the insertion.
654 ;; So split this interval at the insertion point.
656 ;; Originally, the if condition here was this:
657 ;; (! (position == i->position || eobp)
658 ;; && END_NONSTICKY_P (i)
659 ;; && FRONT_NONSTICKY_P (i))
660 ;; But, these macros are now unreliable because of introduction of
661 ;; Vtext_property_default_nonsticky. So, we always check properties
662 ;; one by one if POSITION is in middle of an interval.
663 (unless (or (= position (interval-pt i))
664 eobp)
665 (let* ((rear (getf (interval-plist i) 'rear-nonsticky))
666 (front (getf (interval-plist i) 'front-sticky))
667 (problem t))
668 (when (or (and (not (consp rear)) rear)
669 (and (not (consp front)) front))
670 ;; All properties are nonsticky. We split the interval.
671 (setf problem nil))
673 ;; Does any actual property pose an actual problem? We break
674 ;; the loop if we find a nonsticky property.
675 (when problem
676 (setf problem (do* ((tail (interval-plist i) (cddr tail))
677 (prop (cdr tail) (cdr tail)))
678 ((or (endp tail)
679 (and (not (and (consp front)
680 (not (find prop front))))
681 (or (and (consp rear)
682 (not (find prop rear)))
683 (let ((tmp (assoc prop *text-property-default-nonsticky*)))
684 (and (consp tmp) tmp)))))
685 tail))))
686 ;; If any property is a real problem, split the interval.
687 (when problem
688 (setf temp (split-interval-right i (- position (interval-pt i))))
689 (copy-properties i temp)
690 (setf i temp))))
691 ;; If we are positioned between intervals, check the stickiness of
692 ;; both of them. We have to do this too, if we are at BEG or Z.
693 (if (or (= position (interval-pt i))
694 eobp)
695 (let ((prev (cond ((= position +beg+) nil)
696 (eobp i)
697 (t (previous-interval i)))))
698 (when eobp
699 (setf i nil))
700 ;; Even if we are positioned between intervals, we default
701 ;; to the left one if it exists. We extend it now and split
702 ;; off a part later, if stickiness demands it.
703 (do ((tmp (or prev i) (when (interval-has-parent tmp)
704 (interval-parent tmp))))
705 ((null tmp))
706 (incf (interval-length tmp) length)
707 ;; CHECK_TOTAL_LENGTH (temp);
708 (setf tmp (balance-possible-root-interval tmp)))
709 ;; If at least one interval has sticky properties, we check
710 ;; the stickiness property by property.
712 ;; Originally, the if condition here was this:
713 ;; (END_NONSTICKY_P (prev) || FRONT_STICKY_P (i))
714 ;; But, these macros are now unreliable because of introduction
715 ;; of Vtext_property_default_nonsticky. So, we always have to
716 ;; check stickiness of properties one by one. If cache of
717 ;; stickiness is implemented in the future, we may be able to
718 ;; use those macros again.
719 (let* ((pleft (when prev
720 (interval-plist prev)))
721 (pright (when i
722 (interval-plist i)))
723 (new-props (merge-properties-sticky pleft pright)))
724 (cond ((not prev)
725 ;; /* i.e. position == BEG */
726 (unless (plists-equal (interval-plist i) new-props)
727 (setf i (split-interval-left i length)
728 (interval-plist i) new-props)))
729 ((not (plists-equal (interval-plist prev) new-props))
730 (setf prev (split-interval-right prev (- position (interval-pt prev)))
731 (interval-plist prev) new-props)
732 (when (and i
733 (plists-equal (interval-plist prev) (interval-plist i)))
734 (merge-interval-right prev)))
735 ((and (not prev)
736 (not (null (interval-plist i))))
737 ;; Just split off a new interval at the left.
738 ;; Since I wasn't front-sticky, the empty plist is ok.
739 (setf i (split-interval-left i length))))))
740 ;; Otherwise just extend the interval.
741 (do ((tmp i (when (interval-has-parent tmp)
742 (interval-parent tmp))))
743 ((null tmp))
744 (incf (interval-length tmp) length)
745 ;; CHECK_TOTAL_LENGTH (temp);
746 (setf tmp (balance-possible-root-interval tmp))))
747 tree))
749 (defun interval-deletion-adjustment (tree from amount)
750 "Find the interval in TREE corresponding to the relative position
751 FROM and delete as much as possible of AMOUNT from that interval.
752 Return the amount actually deleted, and if the interval was
753 zeroed-out, delete that interval node from the tree.
755 Note that FROM is actually origin zero, aka relative to the
756 leftmost edge of tree. This is appropriate since we call ourselves
757 recursively on subtrees.
759 Do this by recursing down TREE to the interval in question, and
760 deleting the appropriate amount of text."
761 (let ((relative-position from))
762 (cond
763 ((null tree)
765 ;; Left branch
766 ((< relative-position (left-total-length tree))
767 (let ((subtract (interval-deletion-adjustment (interval-left tree)
768 relative-position
769 amount)))
770 (decf (interval-length tree) subtract)
771 ;; CHECK_TOTAL_LENGTH
772 subtract))
773 ;; Right branch
774 ((>= relative-position (- (total-length tree)
775 (right-total-length tree)))
776 (decf relative-position (- (interval-length tree)
777 (right-total-length tree)))
778 (let ((subtract (interval-deletion-adjustment (interval-right tree)
779 relative-position
780 amount)))
781 (decf (interval-length tree) subtract)
782 ;; CHECK_TOTAL_LENGTH
783 subtract))
784 ;; This node
786 ;; How much can we delete from this interval?
787 (let ((my-amount (- (interval-length tree)
788 (right-total-length tree)
789 relative-position)))
790 (when (> amount my-amount)
791 (setf amount my-amount))
792 (decf (interval-length tree) amount)
793 ;; CHECK_TOTAL_LENGTH
794 (when (zerop (total-length tree))
795 (delete-interval tree))
796 amount)))))
798 (defun adjust-intervals-for-deletion (buffer start length)
799 "Effect the adjustments necessary to the interval tree of BUFFER to
800 correspond to the deletion of LENGTH characters from that buffer
801 text. The deletion is effected at position START (which is a
802 buffer position, i.e. origin 1)."
803 (let ((left-to-delete length)
804 (tree (intervals buffer))
805 (offset (buffer-min buffer)))
806 (cond
807 ((null tree))
808 ((or (> start (+ offset (total-length tree)))
809 (> (+ start length) (+ offset (total-length tree))))
810 (error "gak ~a ~a ~a ~a" tree offset (total-length tree) length))
811 ((= length (total-length tree))
812 (setf (intervals buffer) nil))
813 ((only-interval-p tree)
814 (decf (interval-length tree) length)) ;; CHECK_TOTAL_LENGTH
816 (when (> start (+ offset (total-length tree)))
817 (setf start (+ offset (total-length tree))))
818 (while (> left-to-delete 0)
819 (decf left-to-delete
820 (interval-deletion-adjustment tree (- start offset) left-to-delete))
821 (setf tree (intervals buffer))
822 (when (= left-to-delete (interval-length tree))
823 (setf (intervals buffer) nil)
824 (return)))))))
826 (defun interval-start-pos (source)
827 (if (or (null source)
828 (not (typep (interval-parent source) 'buffer)))
830 (buffer-min (interval-parent source))))
832 (defun reproduce-tree (source parent)
833 (let ((tree (copy-interval source)))
834 (setf (interval-plist tree) (copy-list (interval-plist source))
835 (interval-parent tree) parent)
836 (when (interval-left source)
837 (setf (interval-left tree) (reproduce-tree (interval-left source) tree)))
838 (when (interval-right source)
839 (setf (interval-right tree) (reproduce-tree (interval-right source) tree)))
840 tree))
842 (defun set-properties (properties interval object)
843 (when (typep object 'buffer)
844 ;; record undo info
846 (setf (interval-plist interval) (copy-tree properties)))
848 (defun set-text-properties-1 (start end properties buffer i)
849 (let ((len (- end start))
850 (prev-changed nil)
851 unchanged)
852 (when (zerop len)
853 (return-from set-text-properties-1))
854 (when (minusp len)
855 (incf start len)
856 (setf len (abs len)))
857 (when (null i)
858 (setf i (find-interval (intervals buffer) start)))
859 (when (/= (interval-pt i) start)
860 (setf unchanged i
861 i (split-interval-right unchanged (- start (interval-pt unchanged))))
862 (when (> (interval-text-length i) len)
863 (copy-properties unchanged i)
864 (setf i (split-interval-left i len))
865 (set-properties properties i buffer)
866 (return-from set-text-properties-1))
867 (set-properties properties i buffer)
868 (when (= (interval-text-length i) len)
869 (return-from set-text-properties-1))
870 (setf prev-changed i)
871 (decf len (interval-text-length i))
872 (setf i (next-interval i)))
873 (while (> len 0)
874 (when (null i)
875 (error "borked."))
876 (when (>= (interval-text-length i) len)
877 (when (> (interval-text-length i) len)
878 (setf i (split-interval-left i len)))
879 (set-properties properties i buffer)
880 (when prev-changed
881 (merge-interval-left i))
882 (return-from set-text-properties-1))
883 (decf len (interval-text-length i))
884 ;; We have to call set_properties even if we are going
885 ;; to merge the intervals, so as to make the undo
886 ;; records and cause redisplay to happen.
887 (set-properties properties i buffer)
888 (if (null prev-changed)
889 (setf prev-changed i)
890 (setf prev-changed (merge-interval-left i)
891 i prev-changed))
892 (setf i (next-interval i)))))
894 (defun graft-intervals-into-buffer (source position length buffer inherit)
895 "Insert the intervals of SOURCE into BUFFER at POSITION.
896 LENGTH is the length of the text in SOURCE.
898 The `position' field of the SOURCE intervals is assumed to be
899 consistent with its parent; therefore, SOURCE must be an
900 interval tree made with copy_interval or must be the whole
901 tree of a buffer or a string.
903 This is used in insdel.c when inserting Lisp_Strings into the
904 buffer. The text corresponding to SOURCE is already in the buffer
905 when this is called. The intervals of new tree are a copy of those
906 belonging to the string being inserted; intervals are never
907 shared.
909 If the inserted text had no intervals associated, and we don't
910 want to inherit the surrounding text's properties, this function
911 simply returns -- offset_intervals should handle placing the
912 text in the correct interval, depending on the sticky bits.
914 If the inserted text had properties (intervals), then there are two
915 cases -- either insertion happened in the middle of some interval,
916 or between two intervals.
918 If the text goes into the middle of an interval, then new
919 intervals are created in the middle with only the properties of
920 the new text, *unless* the macro MERGE_INSERTIONS is true, in
921 which case the new text has the union of its properties and those
922 of the text into which it was inserted.
924 If the text goes between two intervals, then if neither interval
925 had its appropriate sticky property set (front_sticky, rear_sticky),
926 the new text has only its properties. If one of the sticky properties
927 is set, then the new text \"sticks\" to that region and its properties
928 depend on merging as above. If both the preceding and succeeding
929 intervals to the new text are \"sticky\", then the new text retains
930 only its properties, as if neither sticky property were set. Perhaps
931 we should consider merging all three sets of properties onto the new
932 text..."
933 (let ((tree (intervals buffer))
934 over-used
935 under over this prev)
936 ;; /* If the new text has no properties, then with inheritance it
937 ;; becomes part of whatever interval it was inserted into.
938 ;; To prevent inheritance, we must clear out the properties
939 ;; of the newly inserted text. */
940 (when (null source)
941 (when (and (not inherit)
942 tree
943 (> length 0))
944 ;; XSETBUFFER (buf, buffer);
945 (set-text-properties-1 position (+ position length) nil buffer 0))
946 (when (intervals buffer)
947 (setf (intervals buffer) (balance-an-interval (intervals buffer))))
948 (return-from graft-intervals-into-buffer))
949 (cond ((null tree)
950 ;; /* The inserted text constitutes the whole buffer, so
951 ;; simply copy over the interval structure. */
952 (when (= (- (buffer-size buffer) (buffer-min buffer))
953 (total-length source))
954 (setf (intervals buffer) (reproduce-tree source buffer)
955 (interval-pt (intervals buffer)) (buffer-min buffer))
956 (return-from graft-intervals-into-buffer))
957 ;; /* Create an interval tree in which to place a copy
958 ;; of the intervals of the inserted string. */
959 (setf tree (create-root-interval buffer)))
960 ((= (total-length tree)
961 (total-length source))
962 ;; /* If the buffer contains only the new string, but
963 ;; there was already some interval tree there, then it may be
964 ;; some zero length intervals. Eventually, do something clever
965 ;; about inserting properly. For now, just waste the old intervals. */
966 (setf (intervals buffer) (reproduce-tree source (interval-parent tree))
967 (interval-pt (intervals buffer)) (buffer-min buffer))
968 (return-from graft-intervals-into-buffer))
969 ((zerop (total-length tree))
970 (error "bork")))
971 (setf under (find-interval tree position)
972 this under
973 over (find-interval source (interval-start-pos source)))
974 (if (> position (interval-pt under))
975 (let ((end-unchanged (split-interval-left this (- position (interval-pt under)))))
976 (copy-properties under end-unchanged)
977 (setf (interval-pt under) position))
978 (setf prev (previous-interval under)))
979 (setf over-used 0)
980 (while over
981 (if (< (- (interval-text-length over) over-used)
982 (interval-text-length under))
983 (progn
984 (setf this (split-interval-left under (- (interval-text-length over)
985 over-used)))
986 (copy-properties under this))
987 (setf this under))
988 ;; /* THIS is now the interval to copy or merge into.
989 ;; OVER covers all of it. */
990 (if inherit
991 (merge-properties over this)
992 (copy-properties over this))
993 ;; /* If THIS and OVER end at the same place,
994 ;; advance OVER to a new source interval. */
995 (if (= (interval-text-length this)
996 (- (interval-text-length over) over-used))
997 (progn
998 (setf over (next-interval over)
999 over-used 0))
1000 ;; /* Otherwise just record that more of OVER has been used. */
1001 (incf over-used (interval-text-length this)))
1002 ;; /* Always advance to a new target interval. */
1003 (setf under (next-interval this)))
1004 (when (intervals buffer)
1005 (setf (intervals buffer) (balance-an-interval (intervals buffer))))))
1007 (defun offset-intervals (buffer start length)
1008 "Make the adjustments necessary to the interval tree of BUFFER to
1009 represent an addition or deletion of LENGTH characters starting
1010 at position START. Addition or deletion is indicated by the sign
1011 of LENGTH."
1012 (unless (or (null (intervals buffer))
1013 (zerop length))
1014 (if (> length 0)
1015 (adjust-intervals-for-insertion (intervals buffer) start length)
1016 (adjust-intervals-for-deletion buffer (+ start length) (- length)))))
1018 (provide :lice-0.1/intervals)