1 /* Code for doing intervals.
2 Copyright (C) 1993 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
23 Have to ensure that we can't put symbol nil on a plist, or some
24 functions may work incorrectly.
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.
29 Need to call *_left_hook when buffer is killed.
31 Scan for zero-length, or 0-length to see notes about handling
32 zero length interval-markers.
34 There are comments around about freeing intervals. It might be
35 faster to explicitly free them (put them on the free list) than
43 #include "intervals.h"
46 /* The rest of the file is within this conditional. */
47 #ifdef USE_TEXT_PROPERTIES
49 /* Factor for weight-balancing interval trees. */
50 Lisp_Object interval_balance_threshold
;
52 /* Utility functions for intervals. */
55 /* Create the root interval of some object, a buffer or string. */
58 create_root_interval (parent
)
61 INTERVAL
new = make_interval ();
63 if (XTYPE (parent
) == Lisp_Buffer
)
65 new->total_length
= BUF_Z (XBUFFER (parent
)) - 1;
66 XBUFFER (parent
)->intervals
= new;
68 else if (XTYPE (parent
) == Lisp_String
)
70 new->total_length
= XSTRING (parent
)->size
;
71 XSTRING (parent
)->intervals
= new;
74 new->parent
= (INTERVAL
) parent
;
80 /* Make the interval TARGET have exactly the properties of SOURCE */
83 copy_properties (source
, target
)
84 register INTERVAL source
, target
;
86 if (DEFAULT_INTERVAL_P (source
) && DEFAULT_INTERVAL_P (target
))
89 COPY_INTERVAL_CACHE (source
, target
);
90 target
->plist
= Fcopy_sequence (source
->plist
);
93 /* Merge the properties of interval SOURCE into the properties
94 of interval TARGET. That is to say, each property in SOURCE
95 is added to TARGET if TARGET has no such property as yet. */
98 merge_properties (source
, target
)
99 register INTERVAL source
, target
;
101 register Lisp_Object o
, sym
, val
;
103 if (DEFAULT_INTERVAL_P (source
) && DEFAULT_INTERVAL_P (target
))
106 MERGE_INTERVAL_CACHE (source
, target
);
109 while (! EQ (o
, Qnil
))
112 val
= Fmemq (sym
, target
->plist
);
118 target
->plist
= Fcons (sym
, Fcons (val
, target
->plist
));
126 /* Return 1 if the two intervals have the same properties,
130 intervals_equal (i0
, i1
)
133 register Lisp_Object i0_cdr
, i0_sym
, i1_val
;
136 if (DEFAULT_INTERVAL_P (i0
) && DEFAULT_INTERVAL_P (i1
))
139 if (DEFAULT_INTERVAL_P (i0
) || DEFAULT_INTERVAL_P (i1
))
142 i1_len
= XFASTINT (Flength (i1
->plist
));
143 if (i1_len
& 0x1) /* Paranoia -- plists are always even */
147 while (!NILP (i0_cdr
))
149 /* Lengths of the two plists were unequal */
153 i0_sym
= Fcar (i0_cdr
);
154 i1_val
= Fmemq (i0_sym
, i1
->plist
);
156 /* i0 has something i1 doesn't */
157 if (EQ (i1_val
, Qnil
))
160 /* i0 and i1 both have sym, but it has different values in each */
161 i0_cdr
= Fcdr (i0_cdr
);
162 if (! Fequal (i1_val
, Fcar (i0_cdr
)))
165 i0_cdr
= Fcdr (i0_cdr
);
169 /* Lengths of the two plists were unequal */
178 static int zero_length
;
180 /* Traverse an interval tree TREE, performing FUNCTION on each node.
181 Pass FUNCTION two args: an interval, and ARG. */
184 traverse_intervals (tree
, position
, depth
, function
, arg
)
187 void (* function
) ();
190 if (NULL_INTERVAL_P (tree
))
193 traverse_intervals (tree
->left
, position
, depth
+ 1, function
, arg
);
194 position
+= LEFT_TOTAL_LENGTH (tree
);
195 tree
->position
= position
;
196 (*function
) (tree
, arg
);
197 position
+= LENGTH (tree
);
198 traverse_intervals (tree
->right
, position
, depth
+ 1, function
, arg
);
202 /* These functions are temporary, for debugging purposes only. */
204 INTERVAL search_interval
, found_interval
;
207 check_for_interval (i
)
210 if (i
== search_interval
)
218 search_for_interval (i
, tree
)
219 register INTERVAL i
, tree
;
223 found_interval
= NULL_INTERVAL
;
224 traverse_intervals (tree
, 1, 0, &check_for_interval
, Qnil
);
225 return found_interval
;
229 inc_interval_count (i
)
246 traverse_intervals (i
, 1, 0, &inc_interval_count
, Qnil
);
252 root_interval (interval
)
255 register INTERVAL i
= interval
;
257 while (! ROOT_INTERVAL_P (i
))
264 /* Assuming that a left child exists, perform the following operation:
274 rotate_right (interval
)
278 INTERVAL B
= interval
->left
;
279 int len
= LENGTH (interval
);
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
;
286 interval
->parent
->right
= interval
->left
;
287 interval
->left
->parent
= interval
->parent
;
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
;
292 /* B becomes the parent of A. */
293 i
= interval
->left
->right
;
294 interval
->left
->right
= interval
;
295 interval
->parent
= interval
->left
;
297 /* A gets c as left child. */
299 if (! NULL_INTERVAL_P (i
))
300 i
->parent
= interval
;
301 interval
->total_length
= (len
+ LEFT_TOTAL_LENGTH (interval
)
302 + RIGHT_TOTAL_LENGTH (interval
));
307 /* Assuming that a right child exists, perform the following operation:
317 rotate_left (interval
)
321 INTERVAL B
= interval
->right
;
322 int len
= LENGTH (interval
);
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
;
329 interval
->parent
->right
= interval
->right
;
330 interval
->right
->parent
= interval
->parent
;
332 /* B must have the same total length of A. */
333 interval
->right
->total_length
= interval
->total_length
;
335 /* Make B the parent of A */
336 i
= interval
->right
->left
;
337 interval
->right
->left
= interval
;
338 interval
->parent
= interval
->right
;
340 /* Make A point to c */
342 if (! NULL_INTERVAL_P (i
))
343 i
->parent
= interval
;
344 interval
->total_length
= (len
+ LEFT_TOTAL_LENGTH (interval
)
345 + RIGHT_TOTAL_LENGTH (interval
));
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.
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
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. */
363 split_interval_right (interval
, offset
)
367 INTERVAL
new = make_interval ();
368 int position
= interval
->position
;
369 int new_length
= LENGTH (interval
) - offset
+ 1;
371 new->position
= position
+ offset
- 1;
372 new->parent
= interval
;
374 if (LEAF_INTERVAL_P (interval
) || NULL_RIGHT_CHILD (interval
))
376 interval
->right
= new;
377 new->total_length
= new_length
;
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;
387 new->total_length
= new_length
+ new->right
->total_length
;
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.
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
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. */
405 split_interval_left (interval
, offset
)
409 INTERVAL
new = make_interval ();
410 int position
= interval
->position
;
411 int new_length
= offset
- 1;
413 new->position
= interval
->position
;
414 interval
->position
= interval
->position
+ offset
- 1;
415 new->parent
= interval
;
417 if (NULL_LEFT_CHILD (interval
))
419 interval
->left
= new;
420 new->total_length
= new_length
;
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
= new_length
+ LEFT_TOTAL_LENGTH (new);
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.
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. */
443 find_interval (tree
, position
)
444 register INTERVAL tree
;
445 register int position
;
447 register int relative_position
= position
;
449 if (NULL_INTERVAL_P (tree
))
450 return NULL_INTERVAL
;
452 if (position
> TOTAL_LENGTH (tree
))
453 abort (); /* Paranoia */
455 position
= TOTAL_LENGTH (tree
);
460 if (relative_position
<= LEFT_TOTAL_LENGTH (tree
))
464 else if (relative_position
> (TOTAL_LENGTH (tree
)
465 - RIGHT_TOTAL_LENGTH (tree
)))
467 relative_position
-= (TOTAL_LENGTH (tree
)
468 - RIGHT_TOTAL_LENGTH (tree
));
473 tree
->position
= LEFT_TOTAL_LENGTH (tree
)
474 + position
- relative_position
+ 1;
480 /* Find the succeeding interval (lexicographically) to INTERVAL.
481 Sets the `position' field based on that of INTERVAL (see
485 next_interval (interval
)
486 register INTERVAL interval
;
488 register INTERVAL i
= interval
;
489 register int next_position
;
491 if (NULL_INTERVAL_P (i
))
492 return NULL_INTERVAL
;
493 next_position
= interval
->position
+ LENGTH (interval
);
495 if (! NULL_RIGHT_CHILD (i
))
498 while (! NULL_LEFT_CHILD (i
))
501 i
->position
= next_position
;
505 while (! NULL_PARENT (i
))
507 if (AM_LEFT_CHILD (i
))
510 i
->position
= next_position
;
517 return NULL_INTERVAL
;
520 /* Find the preceding interval (lexicographically) to INTERVAL.
521 Sets the `position' field based on that of INTERVAL (see
525 previous_interval (interval
)
526 register INTERVAL interval
;
529 register position_of_previous
;
531 if (NULL_INTERVAL_P (interval
))
532 return NULL_INTERVAL
;
534 if (! NULL_LEFT_CHILD (interval
))
537 while (! NULL_RIGHT_CHILD (i
))
540 i
->position
= interval
->position
- LENGTH (i
);
545 while (! NULL_PARENT (i
))
547 if (AM_RIGHT_CHILD (i
))
551 i
->position
= interval
->position
- LENGTH (i
);
557 return NULL_INTERVAL
;
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.
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
574 adjust_intervals_for_insertion (tree
, position
, length
)
576 int position
, length
;
578 register int relative_position
;
579 register INTERVAL
this;
581 if (TOTAL_LENGTH (tree
) == 0) /* Paranoia */
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
;
593 if (relative_position
<= LEFT_TOTAL_LENGTH (this))
595 this->total_length
+= length
;
598 else if (relative_position
> (TOTAL_LENGTH (this)
599 - RIGHT_TOTAL_LENGTH (this)))
601 relative_position
-= (TOTAL_LENGTH (this)
602 - RIGHT_TOTAL_LENGTH (this));
603 this->total_length
+= length
;
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;
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
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".
628 If both intervals are "sticky", then make them belong to the left-most
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. */
633 adjust_intervals_for_insertion (tree
, position
, length
)
635 int position
, length
;
639 if (TOTAL_LENGTH (tree
) == 0) /* Paranoia */
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
);
647 i
= find_interval (tree
, position
);
648 /* If we are positioned between intervals, check the stickiness of
650 if (position
== i
->position
653 register INTERVAL prev
= previous_interval (i
);
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_P (prev
))
662 while (! NULL_INTERVAL_P (i
))
664 i
->total_length
+= length
;
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
673 storing the resulting subtree into its parent. */
679 register INTERVAL migrate
, this;
680 register int migrate_amt
;
682 if (NULL_INTERVAL_P (i
->left
))
684 if (NULL_INTERVAL_P (i
->right
))
688 migrate_amt
= i
->left
->total_length
;
690 this->total_length
+= migrate_amt
;
691 while (! NULL_INTERVAL_P (this->left
))
694 this->total_length
+= migrate_amt
;
696 this->left
= migrate
;
697 migrate
->parent
= this;
702 /* Delete interval I from its tree by calling `delete_node'
703 and properly connecting the resultant subtree.
705 I is presumed to be empty; that is, no adjustments are made
706 for the length of I. */
712 register INTERVAL parent
;
713 int amt
= LENGTH (i
);
715 if (amt
> 0) /* Only used on zero-length intervals now. */
718 if (ROOT_INTERVAL_P (i
))
720 Lisp_Object owner
= (Lisp_Object
) i
->parent
;
721 parent
= delete_node (i
);
722 if (! NULL_INTERVAL_P (parent
))
723 parent
->parent
= (INTERVAL
) owner
;
725 if (XTYPE (owner
) == Lisp_Buffer
)
726 XBUFFER (owner
)->intervals
= parent
;
727 else if (XTYPE (owner
) == Lisp_String
)
728 XSTRING (owner
)->intervals
= parent
;
736 if (AM_LEFT_CHILD (i
))
738 parent
->left
= delete_node (i
);
739 if (! NULL_INTERVAL_P (parent
->left
))
740 parent
->left
->parent
= parent
;
744 parent
->right
= delete_node (i
);
745 if (! NULL_INTERVAL_P (parent
->right
))
746 parent
->right
->parent
= parent
;
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.
756 Do this by recursing down TREE to the interval in question, and
757 deleting the appropriate amount of text. */
760 interval_deletion_adjustment (tree
, from
, amount
)
761 register INTERVAL tree
;
762 register int from
, amount
;
764 register int relative_position
= from
;
766 if (NULL_INTERVAL_P (tree
))
770 if (relative_position
<= LEFT_TOTAL_LENGTH (tree
))
772 int subtract
= interval_deletion_adjustment (tree
->left
,
775 tree
->total_length
-= subtract
;
779 else if (relative_position
> (TOTAL_LENGTH (tree
)
780 - RIGHT_TOTAL_LENGTH (tree
)))
784 relative_position
-= (tree
->total_length
785 - RIGHT_TOTAL_LENGTH (tree
));
786 subtract
= interval_deletion_adjustment (tree
->right
,
789 tree
->total_length
-= subtract
;
792 /* Here -- this node */
795 /* If this is a zero-length, marker interval, then
798 if (relative_position
== LEFT_TOTAL_LENGTH (tree
) + 1)
800 /* This means we're deleting from the beginning of this interval. */
801 register int my_amount
= LENGTH (tree
);
803 if (amount
< my_amount
)
805 tree
->total_length
-= amount
;
810 tree
->total_length
-= my_amount
;
811 if (LENGTH (tree
) != 0)
812 abort (); /* Paranoia */
814 delete_interval (tree
);
818 else /* Deleting starting in the middle. */
820 register int my_amount
= ((tree
->total_length
821 - RIGHT_TOTAL_LENGTH (tree
))
822 - relative_position
+ 1);
824 if (amount
<= my_amount
)
826 tree
->total_length
-= amount
;
831 tree
->total_length
-= my_amount
;
837 /* Never reach here */
840 /* Effect the adjustments neccessary to the interval tree of BUFFER
841 to correspond to the deletion of LENGTH characters from that buffer
842 text. The deletion is effected at position START (relative to the
846 adjust_intervals_for_deletion (buffer
, start
, length
)
847 struct buffer
*buffer
;
850 register int left_to_delete
= length
;
851 register INTERVAL tree
= buffer
->intervals
;
852 register int deleted
;
854 if (NULL_INTERVAL_P (tree
))
857 if (length
== TOTAL_LENGTH (tree
))
859 buffer
->intervals
= NULL_INTERVAL
;
863 if (ONLY_INTERVAL_P (tree
))
865 tree
->total_length
-= length
;
869 if (start
> TOTAL_LENGTH (tree
))
870 start
= TOTAL_LENGTH (tree
);
871 while (left_to_delete
> 0)
873 left_to_delete
-= interval_deletion_adjustment (tree
, start
,
875 tree
= buffer
->intervals
;
876 if (left_to_delete
== tree
->total_length
)
878 buffer
->intervals
= NULL_INTERVAL
;
884 /* Make the adjustments neccessary to the interval tree of BUFFER to
885 represent an addition or deletion of LENGTH characters starting
886 at position START. Addition or deletion is indicated by the sign
890 offset_intervals (buffer
, start
, length
)
891 struct buffer
*buffer
;
894 if (NULL_INTERVAL_P (buffer
->intervals
) || length
== 0)
898 adjust_intervals_for_insertion (buffer
->intervals
, start
, length
);
900 adjust_intervals_for_deletion (buffer
, start
, -length
);
903 /* Merge interval I with its lexicographic successor. The resulting
904 interval is returned, and has the properties of the original
905 successor. The properties of I are lost. I is removed from the
909 The caller must verify that this is not the last (rightmost)
913 merge_interval_right (i
)
916 register int absorb
= LENGTH (i
);
917 register INTERVAL successor
;
919 /* Zero out this interval. */
920 i
->total_length
-= absorb
;
922 /* Find the succeeding interval. */
923 if (! NULL_RIGHT_CHILD (i
)) /* It's below us. Add absorb
926 successor
= i
->right
;
927 while (! NULL_LEFT_CHILD (successor
))
929 successor
->total_length
+= absorb
;
930 successor
= successor
->left
;
933 successor
->total_length
+= absorb
;
939 while (! NULL_PARENT (successor
)) /* It's above us. Subtract as
942 if (AM_LEFT_CHILD (successor
))
944 successor
= successor
->parent
;
949 successor
= successor
->parent
;
950 successor
->total_length
-= absorb
;
953 /* This must be the rightmost or last interval and cannot
954 be merged right. The caller should have known. */
958 /* Merge interval I with its lexicographic predecessor. The resulting
959 interval is returned, and has the properties of the original predecessor.
960 The properties of I are lost. Interval node I is removed from the tree.
963 The caller must verify that this is not the first (leftmost) interval. */
966 merge_interval_left (i
)
969 register int absorb
= LENGTH (i
);
970 register INTERVAL predecessor
;
972 /* Zero out this interval. */
973 i
->total_length
-= absorb
;
975 /* Find the preceding interval. */
976 if (! NULL_LEFT_CHILD (i
)) /* It's below us. Go down,
977 adding ABSORB as we go. */
979 predecessor
= i
->left
;
980 while (! NULL_RIGHT_CHILD (predecessor
))
982 predecessor
->total_length
+= absorb
;
983 predecessor
= predecessor
->right
;
986 predecessor
->total_length
+= absorb
;
992 while (! NULL_PARENT (predecessor
)) /* It's above us. Go up,
993 subtracting ABSORB. */
995 if (AM_RIGHT_CHILD (predecessor
))
997 predecessor
= predecessor
->parent
;
1002 predecessor
= predecessor
->parent
;
1003 predecessor
->total_length
-= absorb
;
1006 /* This must be the leftmost or first interval and cannot
1007 be merged left. The caller should have known. */
1011 /* Make an exact copy of interval tree SOURCE which descends from
1012 PARENT. This is done by recursing through SOURCE, copying
1013 the current interval and its properties, and then adjusting
1014 the pointers of the copy. */
1017 reproduce_tree (source
, parent
)
1018 INTERVAL source
, parent
;
1020 register INTERVAL t
= make_interval ();
1022 bcopy (source
, t
, INTERVAL_SIZE
);
1023 copy_properties (source
, t
);
1025 if (! NULL_LEFT_CHILD (source
))
1026 t
->left
= reproduce_tree (source
->left
, t
);
1027 if (! NULL_RIGHT_CHILD (source
))
1028 t
->right
= reproduce_tree (source
->right
, t
);
1033 /* Make a new interval of length LENGTH starting at START in the
1034 group of intervals INTERVALS, which is actually an interval tree.
1035 Returns the new interval.
1037 Generate an error if the new positions would overlap an existing
1041 make_new_interval (intervals
, start
, length
)
1047 slot
= find_interval (intervals
, start
);
1048 if (start
+ length
> slot
->position
+ LENGTH (slot
))
1049 error ("Interval would overlap");
1051 if (start
== slot
->position
&& length
== LENGTH (slot
))
1054 if (slot
->position
== start
)
1056 /* New right node. */
1057 split_interval_right (slot
, length
+ 1);
1061 if (slot
->position
+ LENGTH (slot
) == start
+ length
)
1063 /* New left node. */
1064 split_interval_left (slot
, LENGTH (slot
) - length
+ 1);
1068 /* Convert interval SLOT into three intervals. */
1069 split_interval_left (slot
, start
- slot
->position
+ 1);
1070 split_interval_right (slot
, length
+ 1);
1074 /* Insert the intervals of SOURCE into BUFFER at POSITION.
1076 This is used in insdel.c when inserting Lisp_Strings into
1077 the buffer. The text corresponding to SOURCE is already in
1078 the buffer when this is called. The intervals of new tree are
1079 those belonging to the string being inserted; a copy is not made.
1081 If the inserted text had no intervals associated, this function
1082 simply returns -- offset_intervals should handle placing the
1083 text in the correct interval, depending on the sticky bits.
1085 If the inserted text had properties (intervals), then there are two
1086 cases -- either insertion happened in the middle of some interval,
1087 or between two intervals.
1089 If the text goes into the middle of an interval, then new
1090 intervals are created in the middle with only the properties of
1091 the new text, *unless* the macro MERGE_INSERTIONS is true, in
1092 which case the new text has the union of its properties and those
1093 of the text into which it was inserted.
1095 If the text goes between two intervals, then if neither interval
1096 had its appropriate sticky property set (front_sticky, rear_sticky),
1097 the new text has only its properties. If one of the sticky properties
1098 is set, then the new text "sticks" to that region and its properties
1099 depend on merging as above. If both the preceding and succeding
1100 intervals to the new text are "sticky", then the new text retains
1101 only its properties, as if neither sticky property were set. Perhaps
1102 we should consider merging all three sets of properties onto the new
1106 graft_intervals_into_buffer (source
, position
, buffer
)
1109 struct buffer
*buffer
;
1111 register INTERVAL under
, over
, this, prev
;
1112 register INTERVAL tree
= buffer
->intervals
;
1115 /* If the new text has no properties, it becomes part of whatever
1116 interval it was inserted into. */
1117 if (NULL_INTERVAL_P (source
))
1120 if (NULL_INTERVAL_P (tree
))
1122 /* The inserted text constitutes the whole buffer, so
1123 simply copy over the interval structure. */
1124 if (BUF_Z (buffer
) == TOTAL_LENGTH (source
))
1126 buffer
->intervals
= reproduce_tree (source
, tree
->parent
);
1127 /* Explicitly free the old tree here. */
1132 /* Create an interval tree in which to place a copy
1133 of the intervals of the inserted string. */
1136 XSET (buf
, Lisp_Buffer
, buffer
);
1137 tree
= create_root_interval (buf
);
1141 if (TOTAL_LENGTH (tree
) == TOTAL_LENGTH (source
))
1142 /* If the buffer contains only the new string, but
1143 there was already some interval tree there, then it may be
1144 some zero length intervals. Eventually, do something clever
1145 about inserting properly. For now, just waste the old intervals. */
1147 buffer
->intervals
= reproduce_tree (source
, tree
->parent
);
1148 /* Explicitly free the old tree here. */
1153 /* Paranoia -- the text has already been added, so this buffer
1154 should be of non-zero length. */
1155 if (TOTAL_LENGTH (tree
) == 0)
1158 this = under
= find_interval (tree
, position
);
1159 if (NULL_INTERVAL_P (under
)) /* Paranoia */
1161 over
= find_interval (source
, 1);
1163 /* Here for insertion in the middle of an interval.
1164 Split off an equivalent interval to the right,
1165 then don't bother with it any more. */
1167 if (position
> under
->position
)
1169 INTERVAL end_unchanged
1170 = split_interval_left (this, position
- under
->position
+ 1);
1171 copy_properties (under
, end_unchanged
);
1172 under
->position
= position
;
1178 prev
= previous_interval (under
);
1179 if (prev
&& !END_STICKY_P (prev
))
1183 /* Insertion is now at beginning of UNDER. */
1185 /* The inserted text "sticks" to the interval `under',
1186 which means it gets those properties. */
1187 while (! NULL_INTERVAL_P (over
))
1189 position
= LENGTH (over
) + 1;
1190 if (position
< LENGTH (under
))
1191 this = split_interval_left (under
, position
);
1194 copy_properties (over
, this);
1195 /* Insertion at the end of an interval, PREV,
1196 inherits from PREV if PREV is sticky at the end. */
1197 if (prev
&& ! FRONT_STICKY_P (under
)
1198 && MERGE_INSERTIONS (prev
))
1199 merge_properties (prev
, this);
1200 /* Maybe it inherits from the following interval
1201 if that is sticky at the front. */
1202 else if ((FRONT_STICKY_P (under
) || middle
)
1203 && MERGE_INSERTIONS (under
))
1204 merge_properties (under
, this);
1205 over
= next_interval (over
);
1208 buffer
->intervals
= balance_intervals (buffer
->intervals
);
1212 /* Get the value of property PROP from PLIST,
1213 which is the plist of an interval.
1214 We check for direct properties and for categories with property PROP. */
1217 textget (plist
, prop
)
1219 register Lisp_Object prop
;
1221 register Lisp_Object tail
, fallback
;
1224 for (tail
= plist
; !NILP (tail
); tail
= Fcdr (Fcdr (tail
)))
1226 register Lisp_Object tem
;
1229 return Fcar (Fcdr (tail
));
1230 if (EQ (tem
, Qcategory
))
1231 fallback
= Fget (Fcar (Fcdr (tail
)), prop
);
1237 /* Set point in BUFFER to POSITION. If the target position is
1238 before an invisible character which is not displayed with a special glyph,
1239 move back to an ok place to display. */
1242 set_point (position
, buffer
)
1243 register int position
;
1244 register struct buffer
*buffer
;
1246 register INTERVAL to
, from
, toprev
, fromprev
, target
;
1247 register int iposition
= position
;
1249 register Lisp_Object obj
;
1250 int backwards
= (position
< BUF_PT (buffer
)) ? 1 : 0;
1251 int old_position
= buffer
->text
.pt
;
1253 if (position
== buffer
->text
.pt
)
1256 /* Check this now, before checking if the buffer has any intervals.
1257 That way, we can catch conditions which break this sanity check
1258 whether or not there are intervals in the buffer. */
1259 if (position
> BUF_Z (buffer
) || position
< BUF_BEG (buffer
))
1262 if (NULL_INTERVAL_P (buffer
->intervals
))
1264 buffer
->text
.pt
= position
;
1268 /* Position Z is really one past the last char in the buffer. */
1269 if (position
== BUF_ZV (buffer
))
1270 iposition
= position
- 1;
1272 /* Set TO to the interval containing the char after POSITION,
1273 and TOPREV to the interval containing the char before POSITION.
1274 Either one may be null. They may be equal. */
1275 to
= find_interval (buffer
->intervals
, iposition
);
1276 if (position
== BUF_BEGV (buffer
))
1278 else if (to
->position
== position
)
1279 toprev
= previous_interval (to
);
1280 else if (iposition
!= position
)
1281 toprev
= to
, to
= 0;
1285 buffer_point
= (BUF_PT (buffer
) == BUF_ZV (buffer
)
1286 ? BUF_ZV (buffer
) - 1
1289 /* Set FROM to the interval containing the char after PT,
1290 and FROMPREV to the interval containing the char before PT.
1291 Either one may be null. They may be equal. */
1292 /* We could cache this and save time. */
1293 from
= find_interval (buffer
->intervals
, buffer_point
);
1294 if (from
->position
== BUF_BEGV (buffer
))
1296 else if (from
->position
== BUF_PT (buffer
))
1297 fromprev
= previous_interval (from
);
1298 else if (buffer_point
!= BUF_PT (buffer
))
1299 fromprev
= from
, from
= 0;
1303 /* Moving within an interval */
1304 if (to
== from
&& toprev
== fromprev
&& INTERVAL_VISIBLE_P (to
))
1306 buffer
->text
.pt
= position
;
1310 /* If the new position is before an invisible character,
1311 move forward over all such. */
1312 while (! NULL_INTERVAL_P (to
)
1313 && ! INTERVAL_VISIBLE_P (to
)
1314 && ! DISPLAY_INVISIBLE_GLYPH (to
))
1317 to
= next_interval (to
);
1318 position
= to
->position
;
1321 buffer
->text
.pt
= position
;
1323 /* We run point-left and point-entered hooks here, iff the
1324 two intervals are not equivalent. These hooks take
1325 (old_point, new_point) as arguments. */
1326 if (! intervals_equal (from
, to
)
1327 || ! intervals_equal (fromprev
, toprev
))
1329 Lisp_Object leave_after
, leave_before
, enter_after
, enter_before
;
1332 leave_after
= textget (fromprev
->plist
, Qpoint_left
);
1336 leave_before
= textget (from
->plist
, Qpoint_left
);
1338 leave_before
= Qnil
;
1341 enter_after
= textget (toprev
->plist
, Qpoint_entered
);
1345 enter_before
= textget (to
->plist
, Qpoint_entered
);
1347 enter_before
= Qnil
;
1349 if (! EQ (leave_before
, enter_before
) && !NILP (leave_before
))
1350 call2 (leave_before
, old_position
, position
);
1351 if (! EQ (leave_after
, enter_after
) && !NILP (leave_after
))
1352 call2 (leave_after
, old_position
, position
);
1354 if (! EQ (enter_before
, leave_before
) && !NILP (enter_before
))
1355 call2 (enter_before
, old_position
, position
);
1356 if (! EQ (enter_after
, leave_after
) && !NILP (enter_after
))
1357 call2 (enter_after
, old_position
, position
);
1361 /* Set point temporarily, without checking any text properties. */
1364 temp_set_point (position
, buffer
)
1366 struct buffer
*buffer
;
1368 buffer
->text
.pt
= position
;
1371 /* Return the proper local map for position POSITION in BUFFER.
1372 Use the map specified by the local-map property, if any.
1373 Otherwise, use BUFFER's local map. */
1376 get_local_map (position
, buffer
)
1377 register int position
;
1378 register struct buffer
*buffer
;
1380 register INTERVAL interval
;
1381 Lisp_Object prop
, tem
;
1383 if (NULL_INTERVAL_P (buffer
->intervals
))
1384 return current_buffer
->keymap
;
1386 /* Perhaps we should just change `position' to the limit. */
1387 if (position
> BUF_Z (buffer
) || position
< BUF_BEG (buffer
))
1390 /* Position Z is really one past the last char in the buffer. */
1391 if (position
== BUF_ZV (buffer
))
1392 return current_buffer
->keymap
;
1394 interval
= find_interval (buffer
->intervals
, position
);
1395 prop
= textget (interval
->plist
, Qlocal_map
);
1397 return current_buffer
->keymap
;
1399 /* Use the local map only if it is valid. */
1400 tem
= Fkeymapp (prop
);
1404 return current_buffer
->keymap
;
1407 /* Call the modification hook functions in LIST, each with START and END. */
1410 call_mod_hooks (list
, start
, end
)
1411 Lisp_Object list
, start
, end
;
1413 struct gcpro gcpro1
;
1415 while (!NILP (list
))
1417 call2 (Fcar (list
), start
, end
);
1423 /* Check for read-only intervals and signal an error if we find one.
1424 Then check for any modification hooks in the range START up to
1425 (but not including) TO. Create a list of all these hooks in
1426 lexicographic order, eliminating consecutive extra copies of the
1427 same hook. Then call those hooks in order, with START and END - 1
1431 verify_interval_modification (buf
, start
, end
)
1435 register INTERVAL intervals
= buf
->intervals
;
1436 register INTERVAL i
, prev
;
1438 register Lisp_Object prev_mod_hooks
;
1439 Lisp_Object mod_hooks
;
1440 struct gcpro gcpro1
;
1443 prev_mod_hooks
= Qnil
;
1446 if (NULL_INTERVAL_P (intervals
))
1456 /* For an insert operation, check the two chars around the position. */
1460 Lisp_Object before
, after
;
1462 /* Set I to the interval containing the char after START,
1463 and PREV to the interval containing the char before START.
1464 Either one may be null. They may be equal. */
1465 i
= find_interval (intervals
,
1466 (start
== BUF_ZV (buf
) ? start
- 1 : start
));
1468 if (start
== BUF_BEGV (buf
))
1470 if (i
->position
== start
)
1471 prev
= previous_interval (i
);
1472 else if (i
->position
< start
)
1474 if (start
== BUF_ZV (buf
))
1477 if (NULL_INTERVAL_P (prev
))
1479 after
= textget (i
->plist
, Qread_only
);
1481 error ("Attempt to insert within read-only text");
1483 else if (NULL_INTERVAL_P (i
))
1485 before
= textget (prev
->plist
, Qread_only
);
1486 if (! NILP (before
))
1487 error ("Attempt to insert within read-only text");
1491 before
= textget (prev
->plist
, Qread_only
);
1492 after
= textget (i
->plist
, Qread_only
);
1493 if (! NILP (before
) && EQ (before
, after
))
1494 error ("Attempt to insert within read-only text");
1497 /* Run both mod hooks (just once if they're the same). */
1498 if (!NULL_INTERVAL_P (prev
))
1499 prev_mod_hooks
= textget (prev
->plist
, Qmodification_hooks
);
1500 if (!NULL_INTERVAL_P (i
))
1501 mod_hooks
= textget (i
->plist
, Qmodification_hooks
);
1503 if (! NILP (prev_mod_hooks
))
1504 call_mod_hooks (prev_mod_hooks
, make_number (start
),
1507 if (! NILP (mod_hooks
) && ! EQ (mod_hooks
, prev_mod_hooks
))
1508 call_mod_hooks (mod_hooks
, make_number (start
), make_number (end
));
1512 /* Loop over intervals on or next to START...END,
1513 collecting their hooks. */
1515 i
= find_interval (intervals
, start
);
1518 if (! INTERVAL_WRITABLE_P (i
))
1519 error ("Attempt to modify read-only text");
1521 mod_hooks
= textget (i
->plist
, Qmodification_hooks
);
1522 if (! NILP (mod_hooks
) && ! EQ (mod_hooks
, prev_mod_hooks
))
1524 hooks
= Fcons (mod_hooks
, hooks
);
1525 prev_mod_hooks
= mod_hooks
;
1528 i
= next_interval (i
);
1530 /* Keep going thru the interval containing the char before END. */
1531 while (! NULL_INTERVAL_P (i
) && i
->position
< end
);
1534 hooks
= Fnreverse (hooks
);
1535 while (! EQ (hooks
, Qnil
))
1537 call_mod_hooks (Fcar (hooks
), make_number (start
),
1539 hooks
= Fcdr (hooks
);
1545 /* Balance an interval node if the amount of text in its left and right
1546 subtrees differs by more than the percentage specified by
1547 `interval-balance-threshold'. */
1550 balance_an_interval (i
)
1553 register int total_children_size
= (LEFT_TOTAL_LENGTH (i
)
1554 + RIGHT_TOTAL_LENGTH (i
));
1555 register int threshold
= (XFASTINT (interval_balance_threshold
)
1556 * (total_children_size
/ 100));
1558 if (LEFT_TOTAL_LENGTH (i
) > RIGHT_TOTAL_LENGTH (i
)
1559 && (LEFT_TOTAL_LENGTH (i
) - RIGHT_TOTAL_LENGTH (i
)) > threshold
)
1560 return rotate_right (i
);
1562 if (LEFT_TOTAL_LENGTH (i
) > RIGHT_TOTAL_LENGTH (i
)
1563 && (LEFT_TOTAL_LENGTH (i
) - RIGHT_TOTAL_LENGTH (i
)) > threshold
)
1564 return rotate_right (i
);
1567 if (LEFT_TOTAL_LENGTH (i
) >
1568 (RIGHT_TOTAL_LENGTH (i
) + XINT (interval_balance_threshold
)))
1569 return rotate_right (i
);
1571 if (RIGHT_TOTAL_LENGTH (i
) >
1572 (LEFT_TOTAL_LENGTH (i
) + XINT (interval_balance_threshold
)))
1573 return rotate_left (i
);
1579 /* Balance the interval tree TREE. Balancing is by weight
1580 (the amount of text). */
1583 balance_intervals (tree
)
1584 register INTERVAL tree
;
1586 register INTERVAL new_tree
;
1588 if (NULL_INTERVAL_P (tree
))
1589 return NULL_INTERVAL
;
1595 new_tree
= balance_an_interval (new_tree
);
1597 while (new_tree
!= tree
);
1602 /* Produce an interval tree reflecting the intervals in
1603 TREE from START to START + LENGTH. */
1606 copy_intervals (tree
, start
, length
)
1610 register INTERVAL i
, new, t
;
1613 if (NULL_INTERVAL_P (tree
) || length
<= 0)
1614 return NULL_INTERVAL
;
1616 i
= find_interval (tree
, start
);
1617 if (NULL_INTERVAL_P (i
) || LENGTH (i
) == 0)
1620 /* If there is only one interval and it's the default, return nil. */
1621 if ((start
- i
->position
+ 1 + length
) < LENGTH (i
)
1622 && DEFAULT_INTERVAL_P (i
))
1623 return NULL_INTERVAL
;
1625 new = make_interval ();
1627 got
= (LENGTH (i
) - (start
- i
->position
));
1628 new->total_length
= length
;
1629 copy_properties (i
, new);
1632 while (got
< length
)
1634 i
= next_interval (i
);
1635 t
= split_interval_right (t
, got
+ 1);
1636 copy_properties (i
, t
);
1641 t
->total_length
-= (got
- length
);
1643 return balance_intervals (new);
1646 /* Give STRING the properties of BUFFER from POSITION to LENGTH. */
1649 copy_intervals_to_string (string
, buffer
, position
, length
)
1650 Lisp_Object string
, buffer
;
1651 int position
, length
;
1653 INTERVAL interval_copy
= copy_intervals (XBUFFER (buffer
)->intervals
,
1655 if (NULL_INTERVAL_P (interval_copy
))
1658 interval_copy
->parent
= (INTERVAL
) string
;
1659 XSTRING (string
)->intervals
= interval_copy
;
1662 #endif /* USE_TEXT_PROPERTIES */