* keymap.c (access_keymap, store_in_keymap,
[bpt/emacs.git] / src / intervals.c
CommitLineData
a50699fd
JA
1/* Code for doing intervals.
2 Copyright (C) 1991, 1992 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21/* NOTES:
22
23 Have to ensure that we can't put symbol nil on a plist, or some
24 functions may work incorrectly.
25
26 An idea: Have the owner of the tree keep count of splits and/or
27 insertion lengths (in intervals), and balance after every N.
28
29 Need to call *_left_hook when buffer is killed.
30
31 Scan for zero-length, or 0-length to see notes about handling
32 zero length interval-markers.
33
34 There are comments around about freeing intervals. It might be
35 faster to explicitly free them (put them on the free list) than
36 to GC them.
37
38*/
39
40
41#include "config.h"
42#include "lisp.h"
43#include "intervals.h"
44#include "buffer.h"
a50699fd 45
d2f7a802
JA
46/* The rest of the file is within this conditional. */
47#ifdef USE_TEXT_PROPERTIES
48
a50699fd
JA
49/* Factor for weight-balancing interval trees. */
50Lisp_Object interval_balance_threshold;
51\f
52/* Utility functions for intervals. */
53
54
55/* Create the root interval of some object, a buffer or string. */
56
57INTERVAL
58create_root_interval (parent)
59 Lisp_Object parent;
60{
61 INTERVAL new = make_interval ();
62
63 if (XTYPE (parent) == Lisp_Buffer)
64 {
65 new->total_length = BUF_Z (XBUFFER (parent)) - 1;
66 XBUFFER (parent)->intervals = new;
67 }
68 else if (XTYPE (parent) == Lisp_String)
69 {
70 new->total_length = XSTRING (parent)->size;
71 XSTRING (parent)->intervals = new;
72 }
73
74 new->parent = (INTERVAL) parent;
75 new->position = 1;
76
77 return new;
78}
79
80/* Make the interval TARGET have exactly the properties of SOURCE */
81
82void
83copy_properties (source, target)
84 register INTERVAL source, target;
85{
86 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
87 return;
88
89 COPY_INTERVAL_CACHE (source, target);
90 target->plist = Fcopy_sequence (source->plist);
91}
92
93/* Merge the properties of interval SOURCE into the properties
94 of interval TARGET. */
95
96static void
97merge_properties (source, target)
98 register INTERVAL source, target;
99{
100 register Lisp_Object o, sym, val;
101
102 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
103 return;
104
105 MERGE_INTERVAL_CACHE (source, target);
106
107 o = source->plist;
108 while (! EQ (o, Qnil))
109 {
110 sym = Fcar (o);
111 val = Fmemq (sym, target->plist);
112
113 if (NILP (val))
114 {
115 o = Fcdr (o);
116 val = Fcar (o);
117 target->plist = Fcons (sym, Fcons (val, target->plist));
118 o = Fcdr (o);
119 }
120 else
121 o = Fcdr (Fcdr (o));
122 }
123}
124
125/* Return 1 if the two intervals have the same properties,
126 0 otherwise. */
127
128int
129intervals_equal (i0, i1)
130 INTERVAL i0, i1;
131{
132 register Lisp_Object i0_cdr, i0_sym, i1_val;
133 register i1_len;
134
135 if (DEFAULT_INTERVAL_P (i0) && DEFAULT_INTERVAL_P (i1))
136 return 1;
137
138 i1_len = XFASTINT (Flength (i1->plist));
139 if (i1_len & 0x1) /* Paranoia -- plists are always even */
140 abort ();
141 i1_len /= 2;
142 i0_cdr = i0->plist;
143 while (!NILP (i0_cdr))
144 {
145 /* Lengths of the two plists were unequal */
146 if (i1_len == 0)
147 return 0;
148
149 i0_sym = Fcar (i0_cdr);
150 i1_val = Fmemq (i0_sym, i1->plist);
151
152 /* i0 has something i1 doesn't */
153 if (EQ (i1_val, Qnil))
154 return 0;
155
156 /* i0 and i1 both have sym, but it has different values in each */
157 i0_cdr = Fcdr (i0_cdr);
158 if (! Fequal (i1_val, Fcar (i0_cdr)))
159 return 0;
160
161 i0_cdr = Fcdr (i0_cdr);
162 i1_len--;
163 }
164
165 /* Lengths of the two plists were unequal */
166 if (i1_len > 0)
167 return 0;
168
169 return 1;
170}
171\f
172static int icount;
173static int idepth;
174static int zero_length;
175
176static int depth;
177
178/* Traverse an interval tree TREE, performing FUNCTION on each node.
179
180 Perhaps we should pass the depth as an argument. */
181
182void
183traverse_intervals (tree, position, function)
184 INTERVAL tree;
185 int position;
186 void (* function) ();
187{
188 if (NULL_INTERVAL_P (tree))
189 return;
190
191 depth++;
192 traverse_intervals (tree->left, position, function);
193 position += LEFT_TOTAL_LENGTH (tree);
194 tree->position = position;
195 (*function) (tree);
196 position += LENGTH (tree);
197 traverse_intervals (tree->right, position, function);
198 depth--;
199}
200\f
201#if 0
202/* These functions are temporary, for debugging purposes only. */
203
204INTERVAL search_interval, found_interval;
205
206void
207check_for_interval (i)
208 register INTERVAL i;
209{
210 if (i == search_interval)
211 {
212 found_interval = i;
213 icount++;
214 }
215}
216
217INTERVAL
218search_for_interval (i, tree)
219 register INTERVAL i, tree;
220{
221 icount = 0;
222 search_interval = i;
223 found_interval = NULL_INTERVAL;
224 traverse_intervals (tree, 1, &check_for_interval);
225 return found_interval;
226}
227
228static void
229inc_interval_count (i)
230 INTERVAL i;
231{
232 icount++;
233 if (LENGTH (i) == 0)
234 zero_length++;
235 if (depth > idepth)
236 idepth = depth;
237}
238
239int
240count_intervals (i)
241 register INTERVAL i;
242{
243 icount = 0;
244 idepth = 0;
245 zero_length = 0;
246 traverse_intervals (i, 1, &inc_interval_count);
247
248 return icount;
249}
250
251static INTERVAL
252root_interval (interval)
253 INTERVAL interval;
254{
255 register INTERVAL i = interval;
256
257 while (! ROOT_INTERVAL_P (i))
258 i = i->parent;
259
260 return i;
261}
262#endif
263\f
264/* Assuming that a left child exists, perform the following operation:
265
266 A B
267 / \ / \
268 B => A
269 / \ / \
270 c c
271*/
272
273static INTERVAL
274rotate_right (interval)
275 INTERVAL interval;
276{
277 INTERVAL i;
278 INTERVAL B = interval->left;
279 int len = LENGTH (interval);
280
281 /* Deal with any Parent of A; make it point to B. */
282 if (! ROOT_INTERVAL_P (interval))
283 if (AM_LEFT_CHILD (interval))
284 interval->parent->left = interval->left;
285 else
286 interval->parent->right = interval->left;
287 interval->left->parent = interval->parent;
288
289 /* B gets the same length as A, since it get A's position in the tree. */
290 interval->left->total_length = interval->total_length;
291
292 /* B becomes the parent of A. */
293 i = interval->left->right;
294 interval->left->right = interval;
295 interval->parent = interval->left;
296
297 /* A gets c as left child. */
298 interval->left = i;
299 if (! NULL_INTERVAL_P (i))
300 i->parent = interval;
301 interval->total_length = (len + LEFT_TOTAL_LENGTH (interval)
302 + RIGHT_TOTAL_LENGTH (interval));
303
304 return B;
305}
306\f
307/* Assuming that a right child exists, perform the following operation:
308
309 A B
310 / \ / \
311 B => A
312 / \ / \
313 c c
314*/
315
316static INTERVAL
317rotate_left (interval)
318 INTERVAL interval;
319{
320 INTERVAL i;
321 INTERVAL B = interval->right;
322 int len = LENGTH (interval);
323
324 /* Deal with the parent of A. */
325 if (! ROOT_INTERVAL_P (interval))
326 if (AM_LEFT_CHILD (interval))
327 interval->parent->left = interval->right;
328 else
329 interval->parent->right = interval->right;
330 interval->right->parent = interval->parent;
331
332 /* B must have the same total length of A. */
333 interval->right->total_length = interval->total_length;
334
335 /* Make B the parent of A */
336 i = interval->right->left;
337 interval->right->left = interval;
338 interval->parent = interval->right;
339
340 /* Make A point to c */
341 interval->right = i;
342 if (! NULL_INTERVAL_P (i))
343 i->parent = interval;
344 interval->total_length = (len + LEFT_TOTAL_LENGTH (interval)
345 + RIGHT_TOTAL_LENGTH (interval));
346
347 return B;
348}
349\f
90ba40fc
JA
350/* Split INTERVAL into two pieces, starting the second piece at character
351 position OFFSET (counting from 1), relative to INTERVAL. The right-hand
352 piece (second, lexicographically) is returned.
353
354 The size and position fields of the two intervals are set based upon
355 those of the original interval. The property list of the new interval
356 is reset, thus it is up to the caller to do the right thing with the
357 result.
a50699fd
JA
358
359 Note that this does not change the position of INTERVAL; if it is a root,
360 it is still a root after this operation. */
361
362INTERVAL
90ba40fc 363split_interval_right (interval, offset)
a50699fd 364 INTERVAL interval;
90ba40fc 365 int offset;
a50699fd
JA
366{
367 INTERVAL new = make_interval ();
368 int position = interval->position;
90ba40fc 369 int new_length = LENGTH (interval) - offset + 1;
a50699fd 370
90ba40fc 371 new->position = position + offset - 1;
a50699fd 372 new->parent = interval;
a50699fd
JA
373
374 if (LEAF_INTERVAL_P (interval) || NULL_RIGHT_CHILD (interval))
375 {
376 interval->right = new;
377 new->total_length = new_length;
378
379 return new;
380 }
381
382 /* Insert the new node between INTERVAL and its right child. */
383 new->right = interval->right;
384 interval->right->parent = new;
385 interval->right = new;
386
387 new->total_length = new_length + new->right->total_length;
388
389 return new;
390}
391
90ba40fc
JA
392/* Split INTERVAL into two pieces, starting the second piece at character
393 position OFFSET (counting from 1), relative to INTERVAL. The left-hand
394 piece (first, lexicographically) is returned.
a50699fd 395
90ba40fc
JA
396 The size and position fields of the two intervals are set based upon
397 those of the original interval. The property list of the new interval
398 is reset, thus it is up to the caller to do the right thing with the
399 result.
400
401 Note that this does not change the position of INTERVAL; if it is a root,
402 it is still a root after this operation. */
a50699fd
JA
403
404INTERVAL
90ba40fc 405split_interval_left (interval, offset)
a50699fd 406 INTERVAL interval;
90ba40fc 407 int offset;
a50699fd
JA
408{
409 INTERVAL new = make_interval ();
410 int position = interval->position;
90ba40fc 411 int new_length = offset - 1;
a50699fd 412
a50699fd 413 new->position = interval->position;
90ba40fc 414 interval->position = interval->position + offset - 1;
a50699fd
JA
415 new->parent = interval;
416
417 if (NULL_LEFT_CHILD (interval))
418 {
419 interval->left = new;
420 new->total_length = new_length;
421
422 return new;
423 }
424
425 /* Insert the new node between INTERVAL and its left child. */
426 new->left = interval->left;
427 new->left->parent = new;
428 interval->left = new;
429 new->total_length = LENGTH (new) + LEFT_TOTAL_LENGTH (new);
430
431 return new;
432}
433\f
90ba40fc
JA
434/* Find the interval containing text position POSITION in the text
435 represented by the interval tree TREE. POSITION is relative to
436 the beginning of that text.
a50699fd 437
90ba40fc
JA
438 The `position' field, which is a cache of an interval's position,
439 is updated in the interval found. Other functions (e.g., next_interval)
440 will update this cache based on the result of find_interval. */
441
442INLINE INTERVAL
a50699fd
JA
443find_interval (tree, position)
444 register INTERVAL tree;
445 register int position;
446{
447 register int relative_position = position;
448
449 if (NULL_INTERVAL_P (tree))
450 return NULL_INTERVAL;
451
452 if (position > TOTAL_LENGTH (tree))
453 abort (); /* Paranoia */
454#if 0
455 position = TOTAL_LENGTH (tree);
456#endif
457
458 while (1)
459 {
460 if (relative_position <= LEFT_TOTAL_LENGTH (tree))
461 {
462 tree = tree->left;
463 }
464 else if (relative_position > (TOTAL_LENGTH (tree)
465 - RIGHT_TOTAL_LENGTH (tree)))
466 {
467 relative_position -= (TOTAL_LENGTH (tree)
468 - RIGHT_TOTAL_LENGTH (tree));
469 tree = tree->right;
470 }
471 else
472 {
473 tree->position = LEFT_TOTAL_LENGTH (tree)
474 + position - relative_position + 1;
475 return tree;
476 }
477 }
478}
479\f
480/* Find the succeeding interval (lexicographically) to INTERVAL.
90ba40fc
JA
481 Sets the `position' field based on that of INTERVAL (see
482 find_interval). */
a50699fd
JA
483
484INTERVAL
485next_interval (interval)
486 register INTERVAL interval;
487{
488 register INTERVAL i = interval;
489 register int next_position;
490
491 if (NULL_INTERVAL_P (i))
492 return NULL_INTERVAL;
493 next_position = interval->position + LENGTH (interval);
494
495 if (! NULL_RIGHT_CHILD (i))
496 {
497 i = i->right;
498 while (! NULL_LEFT_CHILD (i))
499 i = i->left;
500
501 i->position = next_position;
502 return i;
503 }
504
505 while (! NULL_PARENT (i))
506 {
507 if (AM_LEFT_CHILD (i))
508 {
509 i = i->parent;
510 i->position = next_position;
511 return i;
512 }
513
514 i = i->parent;
515 }
516
517 return NULL_INTERVAL;
518}
519
520/* Find the preceding interval (lexicographically) to INTERVAL.
90ba40fc
JA
521 Sets the `position' field based on that of INTERVAL (see
522 find_interval). */
a50699fd
JA
523
524INTERVAL
525previous_interval (interval)
526 register INTERVAL interval;
527{
528 register INTERVAL i;
529 register position_of_previous;
530
531 if (NULL_INTERVAL_P (interval))
532 return NULL_INTERVAL;
533
534 if (! NULL_LEFT_CHILD (interval))
535 {
536 i = interval->left;
537 while (! NULL_RIGHT_CHILD (i))
538 i = i->right;
539
540 i->position = interval->position - LENGTH (i);
541 return i;
542 }
543
544 i = interval;
545 while (! NULL_PARENT (i))
546 {
547 if (AM_RIGHT_CHILD (i))
548 {
549 i = i->parent;
550
551 i->position = interval->position - LENGTH (i);
552 return i;
553 }
554 i = i->parent;
555 }
556
557 return NULL_INTERVAL;
558}
559\f
90ba40fc 560#if 0
a50699fd
JA
561/* Traverse a path down the interval tree TREE to the interval
562 containing POSITION, adjusting all nodes on the path for
563 an addition of LENGTH characters. Insertion between two intervals
564 (i.e., point == i->position, where i is second interval) means
565 text goes into second interval.
566
567 Modifications are needed to handle the hungry bits -- after simply
568 finding the interval at position (don't add length going down),
569 if it's the beginning of the interval, get the previous interval
570 and check the hugry bits of both. Then add the length going back up
571 to the root. */
572
573static INTERVAL
574adjust_intervals_for_insertion (tree, position, length)
575 INTERVAL tree;
576 int position, length;
577{
578 register int relative_position;
579 register INTERVAL this;
580
581 if (TOTAL_LENGTH (tree) == 0) /* Paranoia */
582 abort ();
583
584 /* If inserting at point-max of a buffer, that position
585 will be out of range */
586 if (position > TOTAL_LENGTH (tree))
587 position = TOTAL_LENGTH (tree);
588 relative_position = position;
589 this = tree;
590
591 while (1)
592 {
593 if (relative_position <= LEFT_TOTAL_LENGTH (this))
594 {
595 this->total_length += length;
596 this = this->left;
597 }
598 else if (relative_position > (TOTAL_LENGTH (this)
599 - RIGHT_TOTAL_LENGTH (this)))
600 {
601 relative_position -= (TOTAL_LENGTH (this)
602 - RIGHT_TOTAL_LENGTH (this));
603 this->total_length += length;
604 this = this->right;
605 }
606 else
607 {
608 /* If we are to use zero-length intervals as buffer pointers,
609 then this code will have to change. */
610 this->total_length += length;
611 this->position = LEFT_TOTAL_LENGTH (this)
612 + position - relative_position + 1;
613 return tree;
614 }
615 }
616}
90ba40fc
JA
617#endif
618
619/* Effect an adjustment corresponding to the addition of LENGTH characters
620 of text. Do this by finding the interval containing POSITION in the
621 interval tree TREE, and then adjusting all of it's ancestors by adding
622 LENGTH to them.
623
624 If POSITION is the first character of an interval, meaning that point
625 is actually between the two intervals, make the new text belong to
626 the interval which is "sticky".
627
1d1d7ba0 628 If both intervals are "sticky", then make them belong to the left-most
90ba40fc
JA
629 interval. Another possibility would be to create a new interval for
630 this text, and make it have the merged properties of both ends. */
631
632static INTERVAL
633adjust_intervals_for_insertion (tree, position, length)
634 INTERVAL tree;
635 int position, length;
636{
637 register INTERVAL i;
638
639 if (TOTAL_LENGTH (tree) == 0) /* Paranoia */
640 abort ();
641
642 /* If inserting at point-max of a buffer, that position
643 will be out of range. */
644 if (position > TOTAL_LENGTH (tree))
645 position = TOTAL_LENGTH (tree);
646
647 i = find_interval (tree, position);
648 /* If we are positioned between intervals, check the stickiness of
649 both of them. */
650 if (position == i->position
651 && position != 1)
652 {
249a6da9 653 register INTERVAL prev = previous_interval (i);
90ba40fc
JA
654
655 /* If both intervals are sticky here, then default to the
656 left-most one. But perhaps we should create a new
657 interval here instead... */
658 if (END_STICKY (prev))
659 i = prev;
660 }
661
662 while (! NULL_INTERVAL_P (i))
663 {
664 i->total_length += length;
249a6da9 665 i = i->parent;
90ba40fc
JA
666 }
667
668 return tree;
669}
a50699fd 670\f
90ba40fc
JA
671/* Delete an node I from its interval tree by merging its subtrees
672 into one subtree which is then returned. Caller is responsible for
a50699fd
JA
673 storing the resulting subtree into its parent. */
674
675static INTERVAL
676delete_node (i)
677 register INTERVAL i;
678{
679 register INTERVAL migrate, this;
680 register int migrate_amt;
681
682 if (NULL_INTERVAL_P (i->left))
683 return i->right;
684 if (NULL_INTERVAL_P (i->right))
685 return i->left;
686
687 migrate = i->left;
688 migrate_amt = i->left->total_length;
689 this = i->right;
690 this->total_length += migrate_amt;
691 while (! NULL_INTERVAL_P (this->left))
692 {
693 this = this->left;
694 this->total_length += migrate_amt;
695 }
696 this->left = migrate;
697 migrate->parent = this;
698
699 return i->right;
700}
701
702/* Delete interval I from its tree by calling `delete_node'
703 and properly connecting the resultant subtree.
704
705 I is presumed to be empty; that is, no adjustments are made
706 for the length of I. */
707
708void
709delete_interval (i)
710 register INTERVAL i;
711{
712 register INTERVAL parent;
713 int amt = LENGTH (i);
714
715 if (amt > 0) /* Only used on zero-length intervals now. */
716 abort ();
717
718 if (ROOT_INTERVAL_P (i))
719 {
720 Lisp_Object owner = (Lisp_Object) i->parent;
721 parent = delete_node (i);
722 if (! NULL_INTERVAL_P (parent))
723 parent->parent = (INTERVAL) owner;
724
725 if (XTYPE (owner) == Lisp_Buffer)
726 XBUFFER (owner)->intervals = parent;
727 else if (XTYPE (owner) == Lisp_String)
728 XSTRING (owner)->intervals = parent;
729 else
730 abort ();
731
732 return;
733 }
734
735 parent = i->parent;
736 if (AM_LEFT_CHILD (i))
737 {
738 parent->left = delete_node (i);
739 if (! NULL_INTERVAL_P (parent->left))
740 parent->left->parent = parent;
741 }
742 else
743 {
744 parent->right = delete_node (i);
745 if (! NULL_INTERVAL_P (parent->right))
746 parent->right->parent = parent;
747 }
748}
749\f
1d1d7ba0
JA
750/* Find the interval in TREE corresponding to the character position FROM
751 and delete as much as possible of AMOUNT from that interval, starting
752 after the relative position of FROM within it. Return the amount
753 actually deleted, and if the interval was zeroed-out, delete that
754 interval node from the tree.
a50699fd 755
1d1d7ba0
JA
756 Do this by recursing down TREE to the interval in question, and
757 deleting the appropriate amount of text. */
a50699fd
JA
758
759static int
760interval_deletion_adjustment (tree, from, amount)
761 register INTERVAL tree;
762 register int from, amount;
763{
764 register int relative_position = from;
765
766 if (NULL_INTERVAL_P (tree))
767 return 0;
768
769 /* Left branch */
770 if (relative_position <= LEFT_TOTAL_LENGTH (tree))
771 {
772 int subtract = interval_deletion_adjustment (tree->left,
773 relative_position,
774 amount);
775 tree->total_length -= subtract;
776 return subtract;
777 }
778 /* Right branch */
779 else if (relative_position > (TOTAL_LENGTH (tree)
780 - RIGHT_TOTAL_LENGTH (tree)))
781 {
782 int subtract;
783
784 relative_position -= (tree->total_length
785 - RIGHT_TOTAL_LENGTH (tree));
786 subtract = interval_deletion_adjustment (tree->right,
787 relative_position,
788 amount);
789 tree->total_length -= subtract;
790 return subtract;
791 }
792 /* Here -- this node */
793 else
794 {
795 /* If this is a zero-length, marker interval, then
796 we must skip it. */
797
798 if (relative_position == LEFT_TOTAL_LENGTH (tree) + 1)
799 {
800 /* This means we're deleting from the beginning of this interval. */
801 register int my_amount = LENGTH (tree);
802
803 if (amount < my_amount)
804 {
805 tree->total_length -= amount;
806 return amount;
807 }
808 else
809 {
810 tree->total_length -= my_amount;
811 if (LENGTH (tree) != 0)
812 abort (); /* Paranoia */
813
814 delete_interval (tree);
815 return my_amount;
816 }
817 }
818 else /* Deleting starting in the middle. */
819 {
820 register int my_amount = ((tree->total_length
821 - RIGHT_TOTAL_LENGTH (tree))
822 - relative_position + 1);
823
824 if (amount <= my_amount)
825 {
826 tree->total_length -= amount;
827 return amount;
828 }
829 else
830 {
831 tree->total_length -= my_amount;
832 return my_amount;
833 }
834 }
835 }
836
1d1d7ba0 837 /* Never reach here */
a50699fd
JA
838 abort ();
839}
840
1d1d7ba0
JA
841/* Effect the adjustments neccessary to the interval tree of BUFFER
842 to correspond to the deletion of LENGTH characters from that buffer
843 text. The deletion is effected at position START (relative to the
844 buffer). */
845
a50699fd
JA
846static void
847adjust_intervals_for_deletion (buffer, start, length)
848 struct buffer *buffer;
849 int start, length;
850{
851 register int left_to_delete = length;
852 register INTERVAL tree = buffer->intervals;
853 register int deleted;
854
855 if (NULL_INTERVAL_P (tree))
856 return;
857
858 if (length == TOTAL_LENGTH (tree))
859 {
860 buffer->intervals = NULL_INTERVAL;
861 return;
862 }
863
864 if (ONLY_INTERVAL_P (tree))
865 {
866 tree->total_length -= length;
867 return;
868 }
869
870 if (start > TOTAL_LENGTH (tree))
871 start = TOTAL_LENGTH (tree);
872 while (left_to_delete > 0)
873 {
874 left_to_delete -= interval_deletion_adjustment (tree, start,
875 left_to_delete);
876 tree = buffer->intervals;
877 if (left_to_delete == tree->total_length)
878 {
879 buffer->intervals = NULL_INTERVAL;
880 return;
881 }
882 }
883}
884\f
1d1d7ba0
JA
885/* Make the adjustments neccessary to the interval tree of BUFFER to
886 represent an addition or deletion of LENGTH characters starting
887 at position START. Addition or deletion is indicated by the sign
888 of LENGTH. */
a50699fd
JA
889
890INLINE void
891offset_intervals (buffer, start, length)
892 struct buffer *buffer;
893 int start, length;
894{
895 if (NULL_INTERVAL_P (buffer->intervals) || length == 0)
896 return;
897
898 if (length > 0)
899 adjust_intervals_for_insertion (buffer->intervals, start, length);
900 else
901 adjust_intervals_for_deletion (buffer, start, -length);
902}
9c79dd1b
JA
903\f
904/* Merge interval I with its lexicographic successor. The resulting
905 interval is returned, and has the properties of the original
906 successor. The properties of I are lost. I is removed from the
907 interval tree.
908
909 IMPORTANT:
910 The caller must verify that this is not the last (rightmost)
911 interval. */
912
913INTERVAL
914merge_interval_right (i)
915 register INTERVAL i;
916{
917 register int absorb = LENGTH (i);
918 register INTERVAL successor;
919
920 /* Zero out this interval. */
921 i->total_length -= absorb;
922
923 /* Find the succeeding interval. */
924 if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb
925 as we descend. */
926 {
927 successor = i->right;
928 while (! NULL_LEFT_CHILD (successor))
929 {
930 successor->total_length += absorb;
931 successor = successor->left;
932 }
933
934 successor->total_length += absorb;
935 delete_interval (i);
936 return successor;
937 }
938
939 successor = i;
940 while (! NULL_PARENT (successor)) /* It's above us. Subtract as
941 we ascend. */
942 {
943 if (AM_LEFT_CHILD (successor))
944 {
945 successor = successor->parent;
946 delete_interval (i);
947 return successor;
948 }
949
950 successor = successor->parent;
951 successor->total_length -= absorb;
952 }
953
954 /* This must be the rightmost or last interval and cannot
955 be merged right. The caller should have known. */
956 abort ();
957}
958\f
959/* Merge interval I with its lexicographic predecessor. The resulting
960 interval is returned, and has the properties of the original predecessor.
961 The properties of I are lost. Interval node I is removed from the tree.
962
963 IMPORTANT:
964 The caller must verify that this is not the first (leftmost) interval. */
965
966INTERVAL
967merge_interval_left (i)
968 register INTERVAL i;
969{
970 register int absorb = LENGTH (i);
971 register INTERVAL predecessor;
972
973 /* Zero out this interval. */
974 i->total_length -= absorb;
975
976 /* Find the preceding interval. */
977 if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down,
978 adding ABSORB as we go. */
979 {
980 predecessor = i->left;
981 while (! NULL_RIGHT_CHILD (predecessor))
982 {
983 predecessor->total_length += absorb;
984 predecessor = predecessor->right;
985 }
986
987 predecessor->total_length += absorb;
988 delete_interval (i);
989 return predecessor;
990 }
991
992 predecessor = i;
993 while (! NULL_PARENT (predecessor)) /* It's above us. Go up,
994 subtracting ABSORB. */
995 {
996 if (AM_RIGHT_CHILD (predecessor))
997 {
998 predecessor = predecessor->parent;
999 delete_interval (i);
1000 return predecessor;
1001 }
1002
1003 predecessor = predecessor->parent;
1004 predecessor->total_length -= absorb;
1005 }
a50699fd 1006
9c79dd1b
JA
1007 /* This must be the leftmost or first interval and cannot
1008 be merged left. The caller should have known. */
1009 abort ();
1010}
1011\f
1d1d7ba0
JA
1012/* Make an exact copy of interval tree SOURCE which descends from
1013 PARENT. This is done by recursing through SOURCE, copying
1014 the current interval and its properties, and then adjusting
1015 the pointers of the copy. */
1016
a50699fd
JA
1017static INTERVAL
1018reproduce_tree (source, parent)
1019 INTERVAL source, parent;
1020{
1021 register INTERVAL t = make_interval ();
1022
1023 bcopy (source, t, INTERVAL_SIZE);
1024 copy_properties (source, t);
1025 t->parent = parent;
1026 if (! NULL_LEFT_CHILD (source))
1027 t->left = reproduce_tree (source->left, t);
1028 if (! NULL_RIGHT_CHILD (source))
1029 t->right = reproduce_tree (source->right, t);
1030
1031 return t;
1032}
1033
1d1d7ba0
JA
1034/* Make a new interval of length LENGTH starting at START in the
1035 group of intervals INTERVALS, which is actually an interval tree.
1036 Returns the new interval.
1037
1038 Generate an error if the new positions would overlap an existing
1039 interval. */
1040
a50699fd
JA
1041static INTERVAL
1042make_new_interval (intervals, start, length)
1043 INTERVAL intervals;
1044 int start, length;
1045{
1046 INTERVAL slot;
1047
1048 slot = find_interval (intervals, start);
1049 if (start + length > slot->position + LENGTH (slot))
1050 error ("Interval would overlap");
1051
1052 if (start == slot->position && length == LENGTH (slot))
1053 return slot;
1054
1055 if (slot->position == start)
1056 {
1057 /* New right node. */
1058 split_interval_right (slot, length + 1);
1059 return slot;
1060 }
1061
1062 if (slot->position + LENGTH (slot) == start + length)
1063 {
1064 /* New left node. */
1065 split_interval_left (slot, LENGTH (slot) - length + 1);
1066 return slot;
1067 }
1068
1069 /* Convert interval SLOT into three intervals. */
1070 split_interval_left (slot, start - slot->position + 1);
1071 split_interval_right (slot, length + 1);
1072 return slot;
1073}
1074
9c79dd1b 1075/* Insert the intervals of SOURCE into BUFFER at POSITION.
a50699fd
JA
1076
1077 This is used in insdel.c when inserting Lisp_Strings into
9c79dd1b 1078 the buffer. The text corresponding to SOURCE is already in
a50699fd
JA
1079 the buffer when this is called. The intervals of new tree are
1080 those belonging to the string being inserted; a copy is not made.
1081
1082 If the inserted text had no intervals associated, this function
1083 simply returns -- offset_intervals should handle placing the
90ba40fc 1084 text in the correct interval, depending on the sticky bits.
a50699fd
JA
1085
1086 If the inserted text had properties (intervals), then there are two
1087 cases -- either insertion happened in the middle of some interval,
1088 or between two intervals.
1089
1090 If the text goes into the middle of an interval, then new
1091 intervals are created in the middle with only the properties of
1092 the new text, *unless* the macro MERGE_INSERTIONS is true, in
1093 which case the new text has the union of its properties and those
1094 of the text into which it was inserted.
1095
1096 If the text goes between two intervals, then if neither interval
90ba40fc
JA
1097 had its appropriate sticky property set (front_sticky, rear_sticky),
1098 the new text has only its properties. If one of the sticky properties
a50699fd
JA
1099 is set, then the new text "sticks" to that region and its properties
1100 depend on merging as above. If both the preceding and succeding
90ba40fc
JA
1101 intervals to the new text are "sticky", then the new text retains
1102 only its properties, as if neither sticky property were set. Perhaps
a50699fd
JA
1103 we should consider merging all three sets of properties onto the new
1104 text... */
1105
1106void
9c79dd1b
JA
1107graft_intervals_into_buffer (source, position, buffer)
1108 INTERVAL source;
a50699fd 1109 int position;
9c79dd1b 1110 struct buffer *buffer;
a50699fd
JA
1111{
1112 register INTERVAL under, over, this;
9c79dd1b 1113 register INTERVAL tree = buffer->intervals;
a50699fd
JA
1114
1115 /* If the new text has no properties, it becomes part of whatever
1116 interval it was inserted into. */
9c79dd1b 1117 if (NULL_INTERVAL_P (source))
a50699fd
JA
1118 return;
1119
1120 /* Paranoia -- the text has already been added, so this buffer
1121 should be of non-zero length. */
1122 if (TOTAL_LENGTH (tree) == 0)
1123 abort ();
1124
1125 if (NULL_INTERVAL_P (tree))
1126 {
1127 /* The inserted text constitutes the whole buffer, so
1128 simply copy over the interval structure. */
249a6da9 1129 if (BUF_Z (buffer) == TOTAL_LENGTH (source))
a50699fd 1130 {
9c79dd1b 1131 buffer->intervals = reproduce_tree (source, tree->parent);
a50699fd
JA
1132 /* Explicitly free the old tree here. */
1133
1134 return;
1135 }
1136
1137 /* Create an interval tree in which to place a copy
1138 of the intervals of the inserted string. */
1139 {
249a6da9
JA
1140 Lisp_Object buf;
1141 XSET (buf, Lisp_Buffer, buffer);
a50699fd
JA
1142 create_root_interval (buffer);
1143 }
1144 }
1145 else
9c79dd1b 1146 if (TOTAL_LENGTH (tree) == TOTAL_LENGTH (source))
a50699fd
JA
1147
1148 /* If the buffer contains only the new string, but
1149 there was already some interval tree there, then it may be
1150 some zero length intervals. Eventually, do something clever
1151 about inserting properly. For now, just waste the old intervals. */
1152 {
9c79dd1b 1153 buffer->intervals = reproduce_tree (source, tree->parent);
a50699fd
JA
1154 /* Explicitly free the old tree here. */
1155
1156 return;
1157 }
1158
1159 this = under = find_interval (tree, position);
1160 if (NULL_INTERVAL_P (under)) /* Paranoia */
1161 abort ();
9c79dd1b 1162 over = find_interval (source, 1);
a50699fd
JA
1163
1164 /* Insertion between intervals */
1165 if (position == under->position)
1166 {
1167 /* First interval -- none precede it. */
1168 if (position == 1)
1169 {
90ba40fc 1170 if (! FRONT_STICKY (under))
a50699fd
JA
1171 /* The inserted string keeps its own properties. */
1172 while (! NULL_INTERVAL_P (over))
1173 {
1174 position = LENGTH (over) + 1;
1175 this = split_interval_left (this, position);
1176 copy_properties (over, this);
1177 over = next_interval (over);
1178 }
1179 else
9c79dd1b
JA
1180 /* This string "sticks" to the first interval, `under',
1181 which means it gets those properties. */
a50699fd
JA
1182 while (! NULL_INTERVAL_P (over))
1183 {
1184 position = LENGTH (over) + 1;
1185 this = split_interval_left (this, position);
1186 copy_properties (under, this);
1187 if (MERGE_INSERTIONS (under))
1188 merge_properties (over, this);
1189 over = next_interval (over);
1190 }
1191 }
1192 else
1193 {
1194 INTERVAL prev = previous_interval (under);
1195 if (NULL_INTERVAL_P (prev))
1196 abort ();
1197
90ba40fc 1198 if (END_STICKY (prev))
a50699fd 1199 {
90ba40fc
JA
1200 if (FRONT_STICKY (under))
1201 /* The intervals go inbetween as the two sticky
a50699fd
JA
1202 properties cancel each other. Should we change
1203 this policy? */
1204 while (! NULL_INTERVAL_P (over))
1205 {
1206 position = LENGTH (over) + 1;
1207 this = split_interval_left (this, position);
1208 copy_properties (over, this);
1209 over = next_interval (over);
1210 }
1211 else
1212 /* The intervals stick to prev */
1213 while (! NULL_INTERVAL_P (over))
1214 {
1215 position = LENGTH (over) + 1;
1216 this = split_interval_left (this, position);
1217 copy_properties (prev, this);
1218 if (MERGE_INSERTIONS (prev))
1219 merge_properties (over, this);
1220 over = next_interval (over);
1221 }
1222 }
1223 else
1224 {
90ba40fc 1225 if (FRONT_STICKY (under))
9c79dd1b
JA
1226 /* The inserted text "sticks" to the interval `under',
1227 which means it gets those properties. */
a50699fd
JA
1228 while (! NULL_INTERVAL_P (over))
1229 {
1230 position = LENGTH (over) + 1;
1231 this = split_interval_left (this, position);
1232 copy_properties (under, this);
1233 if (MERGE_INSERTIONS (under))
1234 merge_properties (over, this);
1235 over = next_interval (over);
1236 }
1237 else
1238 /* The intervals go inbetween */
1239 while (! NULL_INTERVAL_P (over))
1240 {
1241 position = LENGTH (over) + 1;
1242 this = split_interval_left (this, position);
1243 copy_properties (over, this);
1244 over = next_interval (over);
1245 }
1246 }
1247 }
1248
9c79dd1b 1249 buffer->intervals = balance_intervals (buffer->intervals);
a50699fd
JA
1250 return;
1251 }
1252
1253 /* Here for insertion in the middle of an interval. */
1254
9c79dd1b 1255 if (TOTAL_LENGTH (source) < LENGTH (this))
a50699fd
JA
1256 {
1257 INTERVAL end_unchanged
9c79dd1b 1258 = split_interval_right (this, TOTAL_LENGTH (source) + 1);
a50699fd
JA
1259 copy_properties (under, end_unchanged);
1260 }
1261
1262 position = position - tree->position + 1;
1263 while (! NULL_INTERVAL_P (over))
1264 {
1265 this = split_interval_right (under, position);
1266 copy_properties (over, this);
1267 if (MERGE_INSERTIONS (under))
1268 merge_properties (under, this);
1269
1270 position = LENGTH (over) + 1;
1271 over = next_interval (over);
1272 }
1273
9c79dd1b 1274 buffer->intervals = balance_intervals (buffer->intervals);
a50699fd
JA
1275 return;
1276}
1277
a50699fd
JA
1278/* Set point in BUFFER to POSITION. If the target position is in
1279 an invisible interval which is not displayed with a special glyph,
1280 skip intervals until we find one. Point may be at the first
1281 position of an invisible interval, if it is displayed with a
d7e3e52b 1282 special glyph. */
a50699fd
JA
1283
1284void
1285set_point (position, buffer)
1286 register int position;
1287 register struct buffer *buffer;
1288{
1289 register INTERVAL to, from, target;
1290 register int iposition = position;
1291 int buffer_point;
1292 register Lisp_Object obj;
1293 int backwards = (position < BUF_PT (buffer)) ? 1 : 0;
9c79dd1b 1294 int old_position = buffer->text.pt;
a50699fd
JA
1295
1296 if (position == buffer->text.pt)
1297 return;
1298
1299 if (NULL_INTERVAL_P (buffer->intervals))
1300 {
1301 buffer->text.pt = position;
1302 return;
1303 }
1304
1305 /* Perhaps we should just change `position' to the limit. */
1306 if (position > BUF_Z (buffer) || position < BUF_BEG (buffer))
1307 abort ();
1308
1309 /* Position Z is really one past the last char in the buffer. */
1310 if (position == BUF_Z (buffer))
1311 iposition = position - 1;
1312
1313 to = find_interval (buffer->intervals, iposition);
1314 buffer_point =(BUF_PT (buffer) == BUF_Z (buffer)
1315 ? BUF_Z (buffer) - 1
1316 : BUF_PT (buffer));
9c79dd1b
JA
1317
1318 /* We could cache this and save time. */
a50699fd 1319 from = find_interval (buffer->intervals, buffer_point);
9c79dd1b 1320
a50699fd
JA
1321 if (NULL_INTERVAL_P (to) || NULL_INTERVAL_P (from))
1322 abort (); /* Paranoia */
1323
1324 /* Moving within an interval */
1325 if (to == from && INTERVAL_VISIBLE_P (to))
1326 {
1327 buffer->text.pt = position;
1328 return;
1329 }
1330
1331 /* Here for the case of moving into another interval. */
1332
1333 target = to;
1334 while (! INTERVAL_VISIBLE_P (to) && ! DISPLAY_INVISIBLE_GLYPH (to)
1335 && ! NULL_INTERVAL_P (to))
1336 to = (backwards ? previous_interval (to) : next_interval (to));
1337 if (NULL_INTERVAL_P (to))
1338 return;
1339
1340 /* Here we know we are actually moving to another interval. */
1341 if (INTERVAL_VISIBLE_P (to))
1342 {
1343 /* If we skipped some intervals, go to the closest point
1344 in the interval we've stopped at. */
1345 if (to != target)
1346 buffer->text.pt = (backwards
1347 ? to->position + LENGTH (to) - 1
1348 : to->position);
1349 else
1350 buffer->text.pt = position;
1351 }
1352 else
1353 buffer->text.pt = to->position;
1354
d7e3e52b
JA
1355 /* We run point-left and point-entered hooks here, iff the
1356 two intervals are not equivalent. These hooks take
1357 (old_point, new_point) as arguments. */
9c79dd1b
JA
1358 if (! intervals_equal (from, to))
1359 {
1360 Lisp_Object val;
1361
1362 val = Fget (Qpoint_left, from->plist);
1363 if (! NILP (val))
1364 call2 (val, old_position, position);
1365
1366 val = Fget (Qpoint_entered, to->plist);
1367 if (! NILP (val))
1368 call2 (val, old_position, position);
1369 }
a50699fd
JA
1370}
1371
9c79dd1b 1372/* Set point temporarily, without checking any text properties. */
a50699fd 1373
9c79dd1b
JA
1374INLINE void
1375temp_set_point (position, buffer)
1376 int position;
1377 struct buffer *buffer;
1378{
1379 buffer->text.pt = position;
1380}
1381
1382/* Check for read-only intervals and signal an error if we find one.
1383 Then check for any modification hooks in the range START up to
1384 (but not including) TO. Create a list of all these hooks in
1385 lexicographic order, eliminating consecutive extra copies of the
1386 same hook. Then call those hooks in order, with START and END - 1
1387 as arguments. */
a50699fd
JA
1388
1389void
1390verify_interval_modification (buf, start, end)
1391 struct buffer *buf;
1392 int start, end;
1393{
1394 register INTERVAL intervals = buf->intervals;
1395 register INTERVAL i;
249a6da9 1396 Lisp_Object hooks = Qnil;
9c79dd1b
JA
1397 register prev_mod_hook = Qnil;
1398 register Lisp_Object mod_hook;
1399 struct gcpro gcpro1;
a50699fd
JA
1400
1401 if (NULL_INTERVAL_P (intervals))
1402 return;
1403
1404 if (start > end)
1405 {
1406 int temp = start;
1407 start = end;
1408 end = temp;
1409 }
1410
1411 if (start == BUF_Z (buf))
1412 {
9c79dd1b 1413 /* This should not be getting called on empty buffers. */
a50699fd
JA
1414 if (BUF_Z (buf) == 1)
1415 abort ();
1416
1417 i = find_interval (intervals, start - 1);
90ba40fc 1418 if (! END_STICKY_P (i))
a50699fd
JA
1419 return;
1420 }
1421 else
1422 i = find_interval (intervals, start);
1423
1424 do
1425 {
a50699fd 1426 if (! INTERVAL_WRITABLE_P (i))
9c79dd1b
JA
1427 error ("Attempt to modify read-only text");
1428
a50699fd 1429 mod_hook = Fget (Qmodification, i->plist);
9c79dd1b
JA
1430 if (! NILP (mod_hook) && ! EQ (mod_hook, prev_mod_hook))
1431 {
1432 hooks = Fcons (mod_hook, hooks);
1433 prev_mod_hook = mod_hook;
1434 }
1435
a50699fd
JA
1436 i = next_interval (i);
1437 }
1438 while (! NULL_INTERVAL_P (i) && i->position <= end);
1439
9c79dd1b 1440 GCPRO1 (hooks);
a50699fd
JA
1441 hooks = Fnreverse (hooks);
1442 while (! EQ (hooks, Qnil))
9c79dd1b
JA
1443 {
1444 call2 (Fcar (hooks), start, end - 1);
1445 hooks = Fcdr (hooks);
1446 }
1447 UNGCPRO;
a50699fd
JA
1448}
1449
1450/* Balance an interval node if the amount of text in its left and right
1451 subtrees differs by more than the percentage specified by
1452 `interval-balance-threshold'. */
1453
1454static INTERVAL
1455balance_an_interval (i)
1456 INTERVAL i;
1457{
1458 register int total_children_size = (LEFT_TOTAL_LENGTH (i)
1459 + RIGHT_TOTAL_LENGTH (i));
1460 register int threshold = (XFASTINT (interval_balance_threshold)
1461 * (total_children_size / 100));
1462
1463 if (LEFT_TOTAL_LENGTH (i) > RIGHT_TOTAL_LENGTH (i)
1464 && (LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i)) > threshold)
1465 return rotate_right (i);
1466
1467 if (LEFT_TOTAL_LENGTH (i) > RIGHT_TOTAL_LENGTH (i)
1468 && (LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i)) > threshold)
1469 return rotate_right (i);
1470
1471#if 0
1472 if (LEFT_TOTAL_LENGTH (i) >
1473 (RIGHT_TOTAL_LENGTH (i) + XINT (interval_balance_threshold)))
1474 return rotate_right (i);
1475
1476 if (RIGHT_TOTAL_LENGTH (i) >
1477 (LEFT_TOTAL_LENGTH (i) + XINT (interval_balance_threshold)))
1478 return rotate_left (i);
1479#endif
1480
1481 return i;
1482}
1483
1484/* Balance the interval tree TREE. Balancing is by weight
1485 (the amount of text). */
1486
1487INTERVAL
1488balance_intervals (tree)
1489 register INTERVAL tree;
1490{
1491 register INTERVAL new_tree;
1492
1493 if (NULL_INTERVAL_P (tree))
1494 return NULL_INTERVAL;
1495
1496 new_tree = tree;
1497 do
1498 {
1499 tree = new_tree;
1500 new_tree = balance_an_interval (new_tree);
1501 }
1502 while (new_tree != tree);
1503
1504 return new_tree;
1505}
1506
9c79dd1b 1507/* Produce an interval tree reflecting the intervals in
a50699fd
JA
1508 TREE from START to START + LENGTH. */
1509
1510static INTERVAL
1511copy_intervals (tree, start, length)
1512 INTERVAL tree;
1513 int start, length;
1514{
1515 register INTERVAL i, new, t;
1516 register int got;
1517
1518 if (NULL_INTERVAL_P (tree) || length <= 0)
1519 return NULL_INTERVAL;
1520
1521 i = find_interval (tree, start);
1522 if (NULL_INTERVAL_P (i) || LENGTH (i) == 0)
1523 abort ();
1524
1525 /* If there is only one interval and it's the default, return nil. */
1526 if ((start - i->position + 1 + length) < LENGTH (i)
1527 && DEFAULT_INTERVAL_P (i))
1528 return NULL_INTERVAL;
1529
1530 new = make_interval ();
1531 new->position = 1;
1532 got = (LENGTH (i) - (start - i->position));
9c79dd1b 1533 new->total_length = length;
a50699fd
JA
1534 copy_properties (i, new);
1535
1536 t = new;
1537 while (got < length)
1538 {
1539 i = next_interval (i);
9c79dd1b 1540 t = split_interval_right (t, got + 1);
a50699fd
JA
1541 copy_properties (i, t);
1542 got += LENGTH (i);
1543 }
1544
1545 if (got > length)
1546 t->total_length -= (got - length);
1547
1548 return balance_intervals (new);
1549}
1550
a50699fd
JA
1551/* Give STRING the properties of BUFFER from POSITION to LENGTH. */
1552
d7e3e52b 1553INLINE void
a50699fd
JA
1554copy_intervals_to_string (string, buffer, position, length)
1555 Lisp_Object string, buffer;
1556 int position, length;
1557{
1558 INTERVAL interval_copy = copy_intervals (XBUFFER (buffer)->intervals,
1559 position, length);
1560 if (NULL_INTERVAL_P (interval_copy))
1561 return;
1562
1563 interval_copy->parent = (INTERVAL) string;
1564 XSTRING (string)->intervals = interval_copy;
1565}
d2f7a802
JA
1566
1567#endif /* USE_TEXT_PROPERTIES */