1 /* Code for doing intervals.
2 Copyright (C) 1993, 1994, 1995, 1997, 1998, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
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"
49 /* Test for membership, allowing for t (actually any non-cons) to mean the
52 #define TMEM(sym, set) (CONSP (set) ? ! NILP (Fmemq (sym, set)) : ! NILP (set))
54 Lisp_Object
merge_properties_sticky ();
55 static INTERVAL reproduce_tree
P_ ((INTERVAL
, INTERVAL
));
56 static INTERVAL reproduce_tree_obj
P_ ((INTERVAL
, Lisp_Object
));
58 /* Utility functions for intervals. */
61 /* Create the root interval of some object, a buffer or string. */
64 create_root_interval (parent
)
69 CHECK_IMPURE (parent
);
71 new = make_interval ();
75 new->total_length
= (BUF_Z (XBUFFER (parent
))
76 - BUF_BEG (XBUFFER (parent
)));
77 CHECK_TOTAL_LENGTH (new);
78 BUF_INTERVALS (XBUFFER (parent
)) = new;
81 else if (STRINGP (parent
))
83 new->total_length
= SCHARS (parent
);
84 CHECK_TOTAL_LENGTH (new);
85 STRING_SET_INTERVALS (parent
, new);
89 SET_INTERVAL_OBJECT (new, parent
);
94 /* Make the interval TARGET have exactly the properties of SOURCE */
97 copy_properties (source
, target
)
98 register INTERVAL source
, target
;
100 if (DEFAULT_INTERVAL_P (source
) && DEFAULT_INTERVAL_P (target
))
103 COPY_INTERVAL_CACHE (source
, target
);
104 target
->plist
= Fcopy_sequence (source
->plist
);
107 /* Merge the properties of interval SOURCE into the properties
108 of interval TARGET. That is to say, each property in SOURCE
109 is added to TARGET if TARGET has no such property as yet. */
112 merge_properties (source
, target
)
113 register INTERVAL source
, target
;
115 register Lisp_Object o
, sym
, val
;
117 if (DEFAULT_INTERVAL_P (source
) && DEFAULT_INTERVAL_P (target
))
120 MERGE_INTERVAL_CACHE (source
, target
);
130 while (CONSP (val
) && !EQ (XCAR (val
), sym
))
141 target
->plist
= Fcons (sym
, Fcons (val
, target
->plist
));
147 /* Return 1 if the two intervals have the same properties,
151 intervals_equal (i0
, i1
)
154 register Lisp_Object i0_cdr
, i0_sym
;
155 register Lisp_Object i1_cdr
, i1_val
;
157 if (DEFAULT_INTERVAL_P (i0
) && DEFAULT_INTERVAL_P (i1
))
160 if (DEFAULT_INTERVAL_P (i0
) || DEFAULT_INTERVAL_P (i1
))
165 while (CONSP (i0_cdr
) && CONSP (i1_cdr
))
167 i0_sym
= XCAR (i0_cdr
);
168 i0_cdr
= XCDR (i0_cdr
);
170 return 0; /* abort (); */
172 while (CONSP (i1_val
) && !EQ (XCAR (i1_val
), i0_sym
))
174 i1_val
= XCDR (i1_val
);
176 return 0; /* abort (); */
177 i1_val
= XCDR (i1_val
);
180 /* i0 has something i1 doesn't. */
181 if (EQ (i1_val
, Qnil
))
184 /* i0 and i1 both have sym, but it has different values in each. */
186 || (i1_val
= XCDR (i1_val
), !CONSP (i1_val
))
187 || !EQ (XCAR (i1_val
), XCAR (i0_cdr
)))
190 i0_cdr
= XCDR (i0_cdr
);
192 i1_cdr
= XCDR (i1_cdr
);
194 return 0; /* abort (); */
195 i1_cdr
= XCDR (i1_cdr
);
198 /* Lengths of the two plists were equal. */
199 return (NILP (i0_cdr
) && NILP (i1_cdr
));
203 /* Traverse an interval tree TREE, performing FUNCTION on each node.
204 No guarantee is made about the order of traversal.
205 Pass FUNCTION two args: an interval, and ARG. */
208 traverse_intervals_noorder (tree
, function
, arg
)
210 void (* function
) P_ ((INTERVAL
, Lisp_Object
));
213 /* Minimize stack usage. */
214 while (!NULL_INTERVAL_P (tree
))
216 (*function
) (tree
, arg
);
217 if (NULL_INTERVAL_P (tree
->right
))
221 traverse_intervals_noorder (tree
->left
, function
, arg
);
227 /* Traverse an interval tree TREE, performing FUNCTION on each node.
228 Pass FUNCTION two args: an interval, and ARG. */
231 traverse_intervals (tree
, position
, function
, arg
)
234 void (* function
) P_ ((INTERVAL
, Lisp_Object
));
237 while (!NULL_INTERVAL_P (tree
))
239 traverse_intervals (tree
->left
, position
, function
, arg
);
240 position
+= LEFT_TOTAL_LENGTH (tree
);
241 tree
->position
= position
;
242 (*function
) (tree
, arg
);
243 position
+= LENGTH (tree
); tree
= tree
->right
;
251 static int zero_length
;
253 /* These functions are temporary, for debugging purposes only. */
255 INTERVAL search_interval
, found_interval
;
258 check_for_interval (i
)
261 if (i
== search_interval
)
269 search_for_interval (i
, tree
)
270 register INTERVAL i
, tree
;
274 found_interval
= NULL_INTERVAL
;
275 traverse_intervals_noorder (tree
, &check_for_interval
, Qnil
);
276 return found_interval
;
280 inc_interval_count (i
)
297 traverse_intervals_noorder (i
, &inc_interval_count
, Qnil
);
303 root_interval (interval
)
306 register INTERVAL i
= interval
;
308 while (! ROOT_INTERVAL_P (i
))
309 i
= INTERVAL_PARENT (i
);
315 /* Assuming that a left child exists, perform the following operation:
324 static INLINE INTERVAL
325 rotate_right (interval
)
329 INTERVAL B
= interval
->left
;
330 int old_total
= interval
->total_length
;
332 /* Deal with any Parent of A; make it point to B. */
333 if (! ROOT_INTERVAL_P (interval
))
335 if (AM_LEFT_CHILD (interval
))
336 INTERVAL_PARENT (interval
)->left
= B
;
338 INTERVAL_PARENT (interval
)->right
= B
;
340 COPY_INTERVAL_PARENT (B
, interval
);
342 /* Make B the parent of A */
345 SET_INTERVAL_PARENT (interval
, B
);
347 /* Make A point to c */
349 if (! NULL_INTERVAL_P (i
))
350 SET_INTERVAL_PARENT (i
, interval
);
352 /* A's total length is decreased by the length of B and its left child. */
353 interval
->total_length
-= B
->total_length
- LEFT_TOTAL_LENGTH (interval
);
354 CHECK_TOTAL_LENGTH (interval
);
356 /* B must have the same total length of A. */
357 B
->total_length
= old_total
;
358 CHECK_TOTAL_LENGTH (B
);
363 /* Assuming that a right child exists, perform the following operation:
372 static INLINE INTERVAL
373 rotate_left (interval
)
377 INTERVAL B
= interval
->right
;
378 int old_total
= interval
->total_length
;
380 /* Deal with any parent of A; make it point to B. */
381 if (! ROOT_INTERVAL_P (interval
))
383 if (AM_LEFT_CHILD (interval
))
384 INTERVAL_PARENT (interval
)->left
= B
;
386 INTERVAL_PARENT (interval
)->right
= B
;
388 COPY_INTERVAL_PARENT (B
, interval
);
390 /* Make B the parent of A */
393 SET_INTERVAL_PARENT (interval
, B
);
395 /* Make A point to c */
397 if (! NULL_INTERVAL_P (i
))
398 SET_INTERVAL_PARENT (i
, interval
);
400 /* A's total length is decreased by the length of B and its right child. */
401 interval
->total_length
-= B
->total_length
- RIGHT_TOTAL_LENGTH (interval
);
402 CHECK_TOTAL_LENGTH (interval
);
404 /* B must have the same total length of A. */
405 B
->total_length
= old_total
;
406 CHECK_TOTAL_LENGTH (B
);
411 /* Balance an interval tree with the assumption that the subtrees
412 themselves are already balanced. */
415 balance_an_interval (i
)
418 register int old_diff
, new_diff
;
422 old_diff
= LEFT_TOTAL_LENGTH (i
) - RIGHT_TOTAL_LENGTH (i
);
425 /* Since the left child is longer, there must be one. */
426 new_diff
= i
->total_length
- i
->left
->total_length
427 + RIGHT_TOTAL_LENGTH (i
->left
) - LEFT_TOTAL_LENGTH (i
->left
);
428 if (eabs (new_diff
) >= old_diff
)
430 i
= rotate_right (i
);
431 balance_an_interval (i
->right
);
433 else if (old_diff
< 0)
435 /* Since the right child is longer, there must be one. */
436 new_diff
= i
->total_length
- i
->right
->total_length
437 + LEFT_TOTAL_LENGTH (i
->right
) - RIGHT_TOTAL_LENGTH (i
->right
);
438 if (eabs (new_diff
) >= -old_diff
)
441 balance_an_interval (i
->left
);
449 /* Balance INTERVAL, potentially stuffing it back into its parent
452 static INLINE INTERVAL
453 balance_possible_root_interval (interval
)
454 register INTERVAL interval
;
459 if (!INTERVAL_HAS_OBJECT (interval
) && !INTERVAL_HAS_PARENT (interval
))
462 if (INTERVAL_HAS_OBJECT (interval
))
465 GET_INTERVAL_OBJECT (parent
, interval
);
467 interval
= balance_an_interval (interval
);
471 if (BUFFERP (parent
))
472 BUF_INTERVALS (XBUFFER (parent
)) = interval
;
473 else if (STRINGP (parent
))
474 STRING_SET_INTERVALS (parent
, interval
);
480 /* Balance the interval tree TREE. Balancing is by weight
481 (the amount of text). */
484 balance_intervals_internal (tree
)
485 register INTERVAL tree
;
487 /* Balance within each side. */
489 balance_intervals_internal (tree
->left
);
491 balance_intervals_internal (tree
->right
);
492 return balance_an_interval (tree
);
495 /* Advertised interface to balance intervals. */
498 balance_intervals (tree
)
501 if (tree
== NULL_INTERVAL
)
502 return NULL_INTERVAL
;
504 return balance_intervals_internal (tree
);
507 /* Split INTERVAL into two pieces, starting the second piece at
508 character position OFFSET (counting from 0), relative to INTERVAL.
509 INTERVAL becomes the left-hand piece, and the right-hand piece
510 (second, lexicographically) is returned.
512 The size and position fields of the two intervals are set based upon
513 those of the original interval. The property list of the new interval
514 is reset, thus it is up to the caller to do the right thing with the
517 Note that this does not change the position of INTERVAL; if it is a root,
518 it is still a root after this operation. */
521 split_interval_right (interval
, offset
)
525 INTERVAL
new = make_interval ();
526 int position
= interval
->position
;
527 int new_length
= LENGTH (interval
) - offset
;
529 new->position
= position
+ offset
;
530 SET_INTERVAL_PARENT (new, interval
);
532 if (NULL_RIGHT_CHILD (interval
))
534 interval
->right
= new;
535 new->total_length
= new_length
;
536 CHECK_TOTAL_LENGTH (new);
540 /* Insert the new node between INTERVAL and its right child. */
541 new->right
= interval
->right
;
542 SET_INTERVAL_PARENT (interval
->right
, new);
543 interval
->right
= new;
544 new->total_length
= new_length
+ new->right
->total_length
;
545 CHECK_TOTAL_LENGTH (new);
546 balance_an_interval (new);
549 balance_possible_root_interval (interval
);
554 /* Split INTERVAL into two pieces, starting the second piece at
555 character position OFFSET (counting from 0), relative to INTERVAL.
556 INTERVAL becomes the right-hand piece, and the left-hand piece
557 (first, lexicographically) is returned.
559 The size and position fields of the two intervals are set based upon
560 those of the original interval. The property list of the new interval
561 is reset, thus it is up to the caller to do the right thing with the
564 Note that this does not change the position of INTERVAL; if it is a root,
565 it is still a root after this operation. */
568 split_interval_left (interval
, offset
)
572 INTERVAL
new = make_interval ();
573 int new_length
= offset
;
575 new->position
= interval
->position
;
576 interval
->position
= interval
->position
+ offset
;
577 SET_INTERVAL_PARENT (new, interval
);
579 if (NULL_LEFT_CHILD (interval
))
581 interval
->left
= new;
582 new->total_length
= new_length
;
583 CHECK_TOTAL_LENGTH (new);
587 /* Insert the new node between INTERVAL and its left child. */
588 new->left
= interval
->left
;
589 SET_INTERVAL_PARENT (new->left
, new);
590 interval
->left
= new;
591 new->total_length
= new_length
+ new->left
->total_length
;
592 CHECK_TOTAL_LENGTH (new);
593 balance_an_interval (new);
596 balance_possible_root_interval (interval
);
601 /* Return the proper position for the first character
602 described by the interval tree SOURCE.
603 This is 1 if the parent is a buffer,
604 0 if the parent is a string or if there is no parent.
606 Don't use this function on an interval which is the child
607 of another interval! */
610 interval_start_pos (source
)
615 if (NULL_INTERVAL_P (source
))
618 if (! INTERVAL_HAS_OBJECT (source
))
620 GET_INTERVAL_OBJECT (parent
, source
);
621 if (BUFFERP (parent
))
622 return BUF_BEG (XBUFFER (parent
));
626 /* Find the interval containing text position POSITION in the text
627 represented by the interval tree TREE. POSITION is a buffer
628 position (starting from 1) or a string index (starting from 0).
629 If POSITION is at the end of the buffer or string,
630 return the interval containing the last character.
632 The `position' field, which is a cache of an interval's position,
633 is updated in the interval found. Other functions (e.g., next_interval)
634 will update this cache based on the result of find_interval. */
637 find_interval (tree
, position
)
638 register INTERVAL tree
;
639 register int position
;
641 /* The distance from the left edge of the subtree at TREE
643 register int relative_position
;
645 if (NULL_INTERVAL_P (tree
))
646 return NULL_INTERVAL
;
648 relative_position
= position
;
649 if (INTERVAL_HAS_OBJECT (tree
))
652 GET_INTERVAL_OBJECT (parent
, tree
);
653 if (BUFFERP (parent
))
654 relative_position
-= BUF_BEG (XBUFFER (parent
));
657 if (relative_position
> TOTAL_LENGTH (tree
))
658 abort (); /* Paranoia */
660 if (!handling_signal
)
661 tree
= balance_possible_root_interval (tree
);
665 if (relative_position
< LEFT_TOTAL_LENGTH (tree
))
669 else if (! NULL_RIGHT_CHILD (tree
)
670 && relative_position
>= (TOTAL_LENGTH (tree
)
671 - RIGHT_TOTAL_LENGTH (tree
)))
673 relative_position
-= (TOTAL_LENGTH (tree
)
674 - RIGHT_TOTAL_LENGTH (tree
));
680 = (position
- relative_position
/* left edge of *tree. */
681 + LEFT_TOTAL_LENGTH (tree
)); /* left edge of this interval. */
688 /* Find the succeeding interval (lexicographically) to INTERVAL.
689 Sets the `position' field based on that of INTERVAL (see
693 next_interval (interval
)
694 register INTERVAL interval
;
696 register INTERVAL i
= interval
;
697 register int next_position
;
699 if (NULL_INTERVAL_P (i
))
700 return NULL_INTERVAL
;
701 next_position
= interval
->position
+ LENGTH (interval
);
703 if (! NULL_RIGHT_CHILD (i
))
706 while (! NULL_LEFT_CHILD (i
))
709 i
->position
= next_position
;
713 while (! NULL_PARENT (i
))
715 if (AM_LEFT_CHILD (i
))
717 i
= INTERVAL_PARENT (i
);
718 i
->position
= next_position
;
722 i
= INTERVAL_PARENT (i
);
725 return NULL_INTERVAL
;
728 /* Find the preceding interval (lexicographically) to INTERVAL.
729 Sets the `position' field based on that of INTERVAL (see
733 previous_interval (interval
)
734 register INTERVAL interval
;
738 if (NULL_INTERVAL_P (interval
))
739 return NULL_INTERVAL
;
741 if (! NULL_LEFT_CHILD (interval
))
744 while (! NULL_RIGHT_CHILD (i
))
747 i
->position
= interval
->position
- LENGTH (i
);
752 while (! NULL_PARENT (i
))
754 if (AM_RIGHT_CHILD (i
))
756 i
= INTERVAL_PARENT (i
);
758 i
->position
= interval
->position
- LENGTH (i
);
761 i
= INTERVAL_PARENT (i
);
764 return NULL_INTERVAL
;
767 /* Find the interval containing POS given some non-NULL INTERVAL
768 in the same tree. Note that we need to update interval->position
769 if we go down the tree.
770 To speed up the process, we assume that the ->position of
771 I and all its parents is already uptodate. */
773 update_interval (i
, pos
)
777 if (NULL_INTERVAL_P (i
))
778 return NULL_INTERVAL
;
782 if (pos
< i
->position
)
785 if (pos
>= i
->position
- TOTAL_LENGTH (i
->left
))
787 i
->left
->position
= i
->position
- TOTAL_LENGTH (i
->left
)
788 + LEFT_TOTAL_LENGTH (i
->left
);
789 i
= i
->left
; /* Move to the left child */
791 else if (NULL_PARENT (i
))
792 error ("Point before start of properties");
794 i
= INTERVAL_PARENT (i
);
797 else if (pos
>= INTERVAL_LAST_POS (i
))
800 if (pos
< INTERVAL_LAST_POS (i
) + TOTAL_LENGTH (i
->right
))
802 i
->right
->position
= INTERVAL_LAST_POS (i
)
803 + LEFT_TOTAL_LENGTH (i
->right
);
804 i
= i
->right
; /* Move to the right child */
806 else if (NULL_PARENT (i
))
807 error ("Point %d after end of properties", pos
);
809 i
= INTERVAL_PARENT (i
);
819 /* Traverse a path down the interval tree TREE to the interval
820 containing POSITION, adjusting all nodes on the path for
821 an addition of LENGTH characters. Insertion between two intervals
822 (i.e., point == i->position, where i is second interval) means
823 text goes into second interval.
825 Modifications are needed to handle the hungry bits -- after simply
826 finding the interval at position (don't add length going down),
827 if it's the beginning of the interval, get the previous interval
828 and check the hungry bits of both. Then add the length going back up
832 adjust_intervals_for_insertion (tree
, position
, length
)
834 int position
, length
;
836 register int relative_position
;
837 register INTERVAL
this;
839 if (TOTAL_LENGTH (tree
) == 0) /* Paranoia */
842 /* If inserting at point-max of a buffer, that position
843 will be out of range */
844 if (position
> TOTAL_LENGTH (tree
))
845 position
= TOTAL_LENGTH (tree
);
846 relative_position
= position
;
851 if (relative_position
<= LEFT_TOTAL_LENGTH (this))
853 this->total_length
+= length
;
854 CHECK_TOTAL_LENGTH (this);
857 else if (relative_position
> (TOTAL_LENGTH (this)
858 - RIGHT_TOTAL_LENGTH (this)))
860 relative_position
-= (TOTAL_LENGTH (this)
861 - RIGHT_TOTAL_LENGTH (this));
862 this->total_length
+= length
;
863 CHECK_TOTAL_LENGTH (this);
868 /* If we are to use zero-length intervals as buffer pointers,
869 then this code will have to change. */
870 this->total_length
+= length
;
871 CHECK_TOTAL_LENGTH (this);
872 this->position
= LEFT_TOTAL_LENGTH (this)
873 + position
- relative_position
+ 1;
880 /* Effect an adjustment corresponding to the addition of LENGTH characters
881 of text. Do this by finding the interval containing POSITION in the
882 interval tree TREE, and then adjusting all of its ancestors by adding
885 If POSITION is the first character of an interval, meaning that point
886 is actually between the two intervals, make the new text belong to
887 the interval which is "sticky".
889 If both intervals are "sticky", then make them belong to the left-most
890 interval. Another possibility would be to create a new interval for
891 this text, and make it have the merged properties of both ends. */
894 adjust_intervals_for_insertion (tree
, position
, length
)
896 int position
, length
;
899 register INTERVAL temp
;
904 if (TOTAL_LENGTH (tree
) == 0) /* Paranoia */
907 GET_INTERVAL_OBJECT (parent
, tree
);
908 offset
= (BUFFERP (parent
) ? BUF_BEG (XBUFFER (parent
)) : 0);
910 /* If inserting at point-max of a buffer, that position will be out
911 of range. Remember that buffer positions are 1-based. */
912 if (position
>= TOTAL_LENGTH (tree
) + offset
)
914 position
= TOTAL_LENGTH (tree
) + offset
;
918 i
= find_interval (tree
, position
);
920 /* If in middle of an interval which is not sticky either way,
921 we must not just give its properties to the insertion.
922 So split this interval at the insertion point.
924 Originally, the if condition here was this:
925 (! (position == i->position || eobp)
926 && END_NONSTICKY_P (i)
927 && FRONT_NONSTICKY_P (i))
928 But, these macros are now unreliable because of introduction of
929 Vtext_property_default_nonsticky. So, we always check properties
930 one by one if POSITION is in middle of an interval. */
931 if (! (position
== i
->position
|| eobp
))
934 Lisp_Object front
, rear
;
938 /* Properties font-sticky and rear-nonsticky override
939 Vtext_property_default_nonsticky. So, if they are t, we can
940 skip one by one checking of properties. */
941 rear
= textget (i
->plist
, Qrear_nonsticky
);
942 if (! CONSP (rear
) && ! NILP (rear
))
944 /* All properties are nonsticky. We split the interval. */
947 front
= textget (i
->plist
, Qfront_sticky
);
948 if (! CONSP (front
) && ! NILP (front
))
950 /* All properties are sticky. We don't split the interval. */
955 /* Does any actual property pose an actual problem? We break
956 the loop if we find a nonsticky property. */
957 for (; CONSP (tail
); tail
= Fcdr (XCDR (tail
)))
959 Lisp_Object prop
, tmp
;
962 /* Is this particular property front-sticky? */
963 if (CONSP (front
) && ! NILP (Fmemq (prop
, front
)))
966 /* Is this particular property rear-nonsticky? */
967 if (CONSP (rear
) && ! NILP (Fmemq (prop
, rear
)))
970 /* Is this particular property recorded as sticky or
971 nonsticky in Vtext_property_default_nonsticky? */
972 tmp
= Fassq (prop
, Vtext_property_default_nonsticky
);
980 /* By default, a text property is rear-sticky, thus we
981 continue the loop. */
985 /* If any property is a real problem, split the interval. */
988 temp
= split_interval_right (i
, position
- i
->position
);
989 copy_properties (i
, temp
);
994 /* If we are positioned between intervals, check the stickiness of
995 both of them. We have to do this too, if we are at BEG or Z. */
996 if (position
== i
->position
|| eobp
)
998 register INTERVAL prev
;
1000 if (position
== BEG
)
1008 prev
= previous_interval (i
);
1010 /* Even if we are positioned between intervals, we default
1011 to the left one if it exists. We extend it now and split
1012 off a part later, if stickiness demands it. */
1013 for (temp
= prev
? prev
: i
; temp
; temp
= INTERVAL_PARENT_OR_NULL (temp
))
1015 temp
->total_length
+= length
;
1016 CHECK_TOTAL_LENGTH (temp
);
1017 temp
= balance_possible_root_interval (temp
);
1020 /* If at least one interval has sticky properties,
1021 we check the stickiness property by property.
1023 Originally, the if condition here was this:
1024 (END_NONSTICKY_P (prev) || FRONT_STICKY_P (i))
1025 But, these macros are now unreliable because of introduction
1026 of Vtext_property_default_nonsticky. So, we always have to
1027 check stickiness of properties one by one. If cache of
1028 stickiness is implemented in the future, we may be able to
1029 use those macros again. */
1032 Lisp_Object pleft
, pright
;
1033 struct interval newi
;
1035 pleft
= NULL_INTERVAL_P (prev
) ? Qnil
: prev
->plist
;
1036 pright
= NULL_INTERVAL_P (i
) ? Qnil
: i
->plist
;
1037 newi
.plist
= merge_properties_sticky (pleft
, pright
);
1039 if (! prev
) /* i.e. position == BEG */
1041 if (! intervals_equal (i
, &newi
))
1043 i
= split_interval_left (i
, length
);
1044 i
->plist
= newi
.plist
;
1047 else if (! intervals_equal (prev
, &newi
))
1049 prev
= split_interval_right (prev
,
1050 position
- prev
->position
);
1051 prev
->plist
= newi
.plist
;
1052 if (! NULL_INTERVAL_P (i
)
1053 && intervals_equal (prev
, i
))
1054 merge_interval_right (prev
);
1057 /* We will need to update the cache here later. */
1059 else if (! prev
&& ! NILP (i
->plist
))
1061 /* Just split off a new interval at the left.
1062 Since I wasn't front-sticky, the empty plist is ok. */
1063 i
= split_interval_left (i
, length
);
1067 /* Otherwise just extend the interval. */
1070 for (temp
= i
; temp
; temp
= INTERVAL_PARENT_OR_NULL (temp
))
1072 temp
->total_length
+= length
;
1073 CHECK_TOTAL_LENGTH (temp
);
1074 temp
= balance_possible_root_interval (temp
);
1081 /* Any property might be front-sticky on the left, rear-sticky on the left,
1082 front-sticky on the right, or rear-sticky on the right; the 16 combinations
1083 can be arranged in a matrix with rows denoting the left conditions and
1084 columns denoting the right conditions:
1092 left-props = '(front-sticky (p8 p9 pa pb pc pd pe pf)
1093 rear-nonsticky (p4 p5 p6 p7 p8 p9 pa pb)
1094 p0 L p1 L p2 L p3 L p4 L p5 L p6 L p7 L
1095 p8 L p9 L pa L pb L pc L pd L pe L pf L)
1096 right-props = '(front-sticky (p2 p3 p6 p7 pa pb pe pf)
1097 rear-nonsticky (p1 p2 p5 p6 p9 pa pd pe)
1098 p0 R p1 R p2 R p3 R p4 R p5 R p6 R p7 R
1099 p8 R p9 R pa R pb R pc R pd R pe R pf R)
1101 We inherit from whoever has a sticky side facing us. If both sides
1102 do (cases 2, 3, E, and F), then we inherit from whichever side has a
1103 non-nil value for the current property. If both sides do, then we take
1106 When we inherit a property, we get its stickiness as well as its value.
1107 So, when we merge the above two lists, we expect to get this:
1109 result = '(front-sticky (p6 p7 pa pb pc pd pe pf)
1110 rear-nonsticky (p6 pa)
1111 p0 L p1 L p2 L p3 L p6 R p7 R
1112 pa R pb R pc L pd L pe L pf L)
1114 The optimizable special cases are:
1115 left rear-nonsticky = nil, right front-sticky = nil (inherit left)
1116 left rear-nonsticky = t, right front-sticky = t (inherit right)
1117 left rear-nonsticky = t, right front-sticky = nil (inherit none)
1121 merge_properties_sticky (pleft
, pright
)
1122 Lisp_Object pleft
, pright
;
1124 register Lisp_Object props
, front
, rear
;
1125 Lisp_Object lfront
, lrear
, rfront
, rrear
;
1126 register Lisp_Object tail1
, tail2
, sym
, lval
, rval
, cat
;
1127 int use_left
, use_right
;
1133 lfront
= textget (pleft
, Qfront_sticky
);
1134 lrear
= textget (pleft
, Qrear_nonsticky
);
1135 rfront
= textget (pright
, Qfront_sticky
);
1136 rrear
= textget (pright
, Qrear_nonsticky
);
1138 /* Go through each element of PRIGHT. */
1139 for (tail1
= pright
; CONSP (tail1
); tail1
= Fcdr (XCDR (tail1
)))
1145 /* Sticky properties get special treatment. */
1146 if (EQ (sym
, Qrear_nonsticky
) || EQ (sym
, Qfront_sticky
))
1149 rval
= Fcar (XCDR (tail1
));
1150 for (tail2
= pleft
; CONSP (tail2
); tail2
= Fcdr (XCDR (tail2
)))
1151 if (EQ (sym
, XCAR (tail2
)))
1154 /* Indicate whether the property is explicitly defined on the left.
1155 (We know it is defined explicitly on the right
1156 because otherwise we don't get here.) */
1157 lpresent
= ! NILP (tail2
);
1158 lval
= (NILP (tail2
) ? Qnil
: Fcar (Fcdr (tail2
)));
1160 /* Even if lrear or rfront say nothing about the stickiness of
1161 SYM, Vtext_property_default_nonsticky may give default
1162 stickiness to SYM. */
1163 tmp
= Fassq (sym
, Vtext_property_default_nonsticky
);
1164 use_left
= (lpresent
1165 && ! (TMEM (sym
, lrear
)
1166 || (CONSP (tmp
) && ! NILP (XCDR (tmp
)))));
1167 use_right
= (TMEM (sym
, rfront
)
1168 || (CONSP (tmp
) && NILP (XCDR (tmp
))));
1169 if (use_left
&& use_right
)
1173 else if (NILP (rval
))
1178 /* We build props as (value sym ...) rather than (sym value ...)
1179 because we plan to nreverse it when we're done. */
1180 props
= Fcons (lval
, Fcons (sym
, props
));
1181 if (TMEM (sym
, lfront
))
1182 front
= Fcons (sym
, front
);
1183 if (TMEM (sym
, lrear
))
1184 rear
= Fcons (sym
, rear
);
1188 props
= Fcons (rval
, Fcons (sym
, props
));
1189 if (TMEM (sym
, rfront
))
1190 front
= Fcons (sym
, front
);
1191 if (TMEM (sym
, rrear
))
1192 rear
= Fcons (sym
, rear
);
1196 /* Now go through each element of PLEFT. */
1197 for (tail2
= pleft
; CONSP (tail2
); tail2
= Fcdr (XCDR (tail2
)))
1203 /* Sticky properties get special treatment. */
1204 if (EQ (sym
, Qrear_nonsticky
) || EQ (sym
, Qfront_sticky
))
1207 /* If sym is in PRIGHT, we've already considered it. */
1208 for (tail1
= pright
; CONSP (tail1
); tail1
= Fcdr (XCDR (tail1
)))
1209 if (EQ (sym
, XCAR (tail1
)))
1214 lval
= Fcar (XCDR (tail2
));
1216 /* Even if lrear or rfront say nothing about the stickiness of
1217 SYM, Vtext_property_default_nonsticky may give default
1218 stickiness to SYM. */
1219 tmp
= Fassq (sym
, Vtext_property_default_nonsticky
);
1221 /* Since rval is known to be nil in this loop, the test simplifies. */
1222 if (! (TMEM (sym
, lrear
) || (CONSP (tmp
) && ! NILP (XCDR (tmp
)))))
1224 props
= Fcons (lval
, Fcons (sym
, props
));
1225 if (TMEM (sym
, lfront
))
1226 front
= Fcons (sym
, front
);
1228 else if (TMEM (sym
, rfront
) || (CONSP (tmp
) && NILP (XCDR (tmp
))))
1230 /* The value is nil, but we still inherit the stickiness
1232 front
= Fcons (sym
, front
);
1233 if (TMEM (sym
, rrear
))
1234 rear
= Fcons (sym
, rear
);
1237 props
= Fnreverse (props
);
1239 props
= Fcons (Qrear_nonsticky
, Fcons (Fnreverse (rear
), props
));
1241 cat
= textget (props
, Qcategory
);
1244 /* If we have inherited a front-stick category property that is t,
1245 we don't need to set up a detailed one. */
1246 ! (! NILP (cat
) && SYMBOLP (cat
)
1247 && EQ (Fget (cat
, Qfront_sticky
), Qt
)))
1248 props
= Fcons (Qfront_sticky
, Fcons (Fnreverse (front
), props
));
1253 /* Delete a node I from its interval tree by merging its subtrees
1254 into one subtree which is then returned. Caller is responsible for
1255 storing the resulting subtree into its parent. */
1259 register INTERVAL i
;
1261 register INTERVAL migrate
, this;
1262 register int migrate_amt
;
1264 if (NULL_INTERVAL_P (i
->left
))
1266 if (NULL_INTERVAL_P (i
->right
))
1270 migrate_amt
= i
->left
->total_length
;
1272 this->total_length
+= migrate_amt
;
1273 while (! NULL_INTERVAL_P (this->left
))
1276 this->total_length
+= migrate_amt
;
1278 CHECK_TOTAL_LENGTH (this);
1279 this->left
= migrate
;
1280 SET_INTERVAL_PARENT (migrate
, this);
1285 /* Delete interval I from its tree by calling `delete_node'
1286 and properly connecting the resultant subtree.
1288 I is presumed to be empty; that is, no adjustments are made
1289 for the length of I. */
1293 register INTERVAL i
;
1295 register INTERVAL parent
;
1296 int amt
= LENGTH (i
);
1298 if (amt
> 0) /* Only used on zero-length intervals now. */
1301 if (ROOT_INTERVAL_P (i
))
1304 GET_INTERVAL_OBJECT (owner
, i
);
1305 parent
= delete_node (i
);
1306 if (! NULL_INTERVAL_P (parent
))
1307 SET_INTERVAL_OBJECT (parent
, owner
);
1309 if (BUFFERP (owner
))
1310 BUF_INTERVALS (XBUFFER (owner
)) = parent
;
1311 else if (STRINGP (owner
))
1312 STRING_SET_INTERVALS (owner
, parent
);
1319 parent
= INTERVAL_PARENT (i
);
1320 if (AM_LEFT_CHILD (i
))
1322 parent
->left
= delete_node (i
);
1323 if (! NULL_INTERVAL_P (parent
->left
))
1324 SET_INTERVAL_PARENT (parent
->left
, parent
);
1328 parent
->right
= delete_node (i
);
1329 if (! NULL_INTERVAL_P (parent
->right
))
1330 SET_INTERVAL_PARENT (parent
->right
, parent
);
1334 /* Find the interval in TREE corresponding to the relative position
1335 FROM and delete as much as possible of AMOUNT from that interval.
1336 Return the amount actually deleted, and if the interval was
1337 zeroed-out, delete that interval node from the tree.
1339 Note that FROM is actually origin zero, aka relative to the
1340 leftmost edge of tree. This is appropriate since we call ourselves
1341 recursively on subtrees.
1343 Do this by recursing down TREE to the interval in question, and
1344 deleting the appropriate amount of text. */
1347 interval_deletion_adjustment (tree
, from
, amount
)
1348 register INTERVAL tree
;
1349 register int from
, amount
;
1351 register int relative_position
= from
;
1353 if (NULL_INTERVAL_P (tree
))
1357 if (relative_position
< LEFT_TOTAL_LENGTH (tree
))
1359 int subtract
= interval_deletion_adjustment (tree
->left
,
1362 tree
->total_length
-= subtract
;
1363 CHECK_TOTAL_LENGTH (tree
);
1367 else if (relative_position
>= (TOTAL_LENGTH (tree
)
1368 - RIGHT_TOTAL_LENGTH (tree
)))
1372 relative_position
-= (tree
->total_length
1373 - RIGHT_TOTAL_LENGTH (tree
));
1374 subtract
= interval_deletion_adjustment (tree
->right
,
1377 tree
->total_length
-= subtract
;
1378 CHECK_TOTAL_LENGTH (tree
);
1381 /* Here -- this node. */
1384 /* How much can we delete from this interval? */
1385 int my_amount
= ((tree
->total_length
1386 - RIGHT_TOTAL_LENGTH (tree
))
1387 - relative_position
);
1389 if (amount
> my_amount
)
1392 tree
->total_length
-= amount
;
1393 CHECK_TOTAL_LENGTH (tree
);
1394 if (LENGTH (tree
) == 0)
1395 delete_interval (tree
);
1400 /* Never reach here. */
1403 /* Effect the adjustments necessary to the interval tree of BUFFER to
1404 correspond to the deletion of LENGTH characters from that buffer
1405 text. The deletion is effected at position START (which is a
1406 buffer position, i.e. origin 1). */
1409 adjust_intervals_for_deletion (buffer
, start
, length
)
1410 struct buffer
*buffer
;
1413 register int left_to_delete
= length
;
1414 register INTERVAL tree
= BUF_INTERVALS (buffer
);
1418 GET_INTERVAL_OBJECT (parent
, tree
);
1419 offset
= (BUFFERP (parent
) ? BUF_BEG (XBUFFER (parent
)) : 0);
1421 if (NULL_INTERVAL_P (tree
))
1424 if (start
> offset
+ TOTAL_LENGTH (tree
)
1425 || start
+ length
> offset
+ TOTAL_LENGTH (tree
))
1428 if (length
== TOTAL_LENGTH (tree
))
1430 BUF_INTERVALS (buffer
) = NULL_INTERVAL
;
1434 if (ONLY_INTERVAL_P (tree
))
1436 tree
->total_length
-= length
;
1437 CHECK_TOTAL_LENGTH (tree
);
1441 if (start
> offset
+ TOTAL_LENGTH (tree
))
1442 start
= offset
+ TOTAL_LENGTH (tree
);
1443 while (left_to_delete
> 0)
1445 left_to_delete
-= interval_deletion_adjustment (tree
, start
- offset
,
1447 tree
= BUF_INTERVALS (buffer
);
1448 if (left_to_delete
== tree
->total_length
)
1450 BUF_INTERVALS (buffer
) = NULL_INTERVAL
;
1456 /* Make the adjustments necessary to the interval tree of BUFFER to
1457 represent an addition or deletion of LENGTH characters starting
1458 at position START. Addition or deletion is indicated by the sign
1462 offset_intervals (buffer
, start
, length
)
1463 struct buffer
*buffer
;
1466 if (NULL_INTERVAL_P (BUF_INTERVALS (buffer
)) || length
== 0)
1470 adjust_intervals_for_insertion (BUF_INTERVALS (buffer
), start
, length
);
1472 adjust_intervals_for_deletion (buffer
, start
, -length
);
1475 /* Merge interval I with its lexicographic successor. The resulting
1476 interval is returned, and has the properties of the original
1477 successor. The properties of I are lost. I is removed from the
1481 The caller must verify that this is not the last (rightmost)
1485 merge_interval_right (i
)
1486 register INTERVAL i
;
1488 register int absorb
= LENGTH (i
);
1489 register INTERVAL successor
;
1491 /* Zero out this interval. */
1492 i
->total_length
-= absorb
;
1493 CHECK_TOTAL_LENGTH (i
);
1495 /* Find the succeeding interval. */
1496 if (! NULL_RIGHT_CHILD (i
)) /* It's below us. Add absorb
1499 successor
= i
->right
;
1500 while (! NULL_LEFT_CHILD (successor
))
1502 successor
->total_length
+= absorb
;
1503 CHECK_TOTAL_LENGTH (successor
);
1504 successor
= successor
->left
;
1507 successor
->total_length
+= absorb
;
1508 CHECK_TOTAL_LENGTH (successor
);
1509 delete_interval (i
);
1514 while (! NULL_PARENT (successor
)) /* It's above us. Subtract as
1517 if (AM_LEFT_CHILD (successor
))
1519 successor
= INTERVAL_PARENT (successor
);
1520 delete_interval (i
);
1524 successor
= INTERVAL_PARENT (successor
);
1525 successor
->total_length
-= absorb
;
1526 CHECK_TOTAL_LENGTH (successor
);
1529 /* This must be the rightmost or last interval and cannot
1530 be merged right. The caller should have known. */
1534 /* Merge interval I with its lexicographic predecessor. The resulting
1535 interval is returned, and has the properties of the original predecessor.
1536 The properties of I are lost. Interval node I is removed from the tree.
1539 The caller must verify that this is not the first (leftmost) interval. */
1542 merge_interval_left (i
)
1543 register INTERVAL i
;
1545 register int absorb
= LENGTH (i
);
1546 register INTERVAL predecessor
;
1548 /* Zero out this interval. */
1549 i
->total_length
-= absorb
;
1550 CHECK_TOTAL_LENGTH (i
);
1552 /* Find the preceding interval. */
1553 if (! NULL_LEFT_CHILD (i
)) /* It's below us. Go down,
1554 adding ABSORB as we go. */
1556 predecessor
= i
->left
;
1557 while (! NULL_RIGHT_CHILD (predecessor
))
1559 predecessor
->total_length
+= absorb
;
1560 CHECK_TOTAL_LENGTH (predecessor
);
1561 predecessor
= predecessor
->right
;
1564 predecessor
->total_length
+= absorb
;
1565 CHECK_TOTAL_LENGTH (predecessor
);
1566 delete_interval (i
);
1571 while (! NULL_PARENT (predecessor
)) /* It's above us. Go up,
1572 subtracting ABSORB. */
1574 if (AM_RIGHT_CHILD (predecessor
))
1576 predecessor
= INTERVAL_PARENT (predecessor
);
1577 delete_interval (i
);
1581 predecessor
= INTERVAL_PARENT (predecessor
);
1582 predecessor
->total_length
-= absorb
;
1583 CHECK_TOTAL_LENGTH (predecessor
);
1586 /* This must be the leftmost or first interval and cannot
1587 be merged left. The caller should have known. */
1591 /* Make an exact copy of interval tree SOURCE which descends from
1592 PARENT. This is done by recursing through SOURCE, copying
1593 the current interval and its properties, and then adjusting
1594 the pointers of the copy. */
1597 reproduce_tree (source
, parent
)
1598 INTERVAL source
, parent
;
1600 register INTERVAL t
= make_interval ();
1602 bcopy (source
, t
, INTERVAL_SIZE
);
1603 copy_properties (source
, t
);
1604 SET_INTERVAL_PARENT (t
, parent
);
1605 if (! NULL_LEFT_CHILD (source
))
1606 t
->left
= reproduce_tree (source
->left
, t
);
1607 if (! NULL_RIGHT_CHILD (source
))
1608 t
->right
= reproduce_tree (source
->right
, t
);
1614 reproduce_tree_obj (source
, parent
)
1618 register INTERVAL t
= make_interval ();
1620 bcopy (source
, t
, INTERVAL_SIZE
);
1621 copy_properties (source
, t
);
1622 SET_INTERVAL_OBJECT (t
, parent
);
1623 if (! NULL_LEFT_CHILD (source
))
1624 t
->left
= reproduce_tree (source
->left
, t
);
1625 if (! NULL_RIGHT_CHILD (source
))
1626 t
->right
= reproduce_tree (source
->right
, t
);
1632 /* Nobody calls this. Perhaps it's a vestige of an earlier design. */
1634 /* Make a new interval of length LENGTH starting at START in the
1635 group of intervals INTERVALS, which is actually an interval tree.
1636 Returns the new interval.
1638 Generate an error if the new positions would overlap an existing
1642 make_new_interval (intervals
, start
, length
)
1648 slot
= find_interval (intervals
, start
);
1649 if (start
+ length
> slot
->position
+ LENGTH (slot
))
1650 error ("Interval would overlap");
1652 if (start
== slot
->position
&& length
== LENGTH (slot
))
1655 if (slot
->position
== start
)
1657 /* New right node. */
1658 split_interval_right (slot
, length
);
1662 if (slot
->position
+ LENGTH (slot
) == start
+ length
)
1664 /* New left node. */
1665 split_interval_left (slot
, LENGTH (slot
) - length
);
1669 /* Convert interval SLOT into three intervals. */
1670 split_interval_left (slot
, start
- slot
->position
);
1671 split_interval_right (slot
, length
);
1676 /* Insert the intervals of SOURCE into BUFFER at POSITION.
1677 LENGTH is the length of the text in SOURCE.
1679 The `position' field of the SOURCE intervals is assumed to be
1680 consistent with its parent; therefore, SOURCE must be an
1681 interval tree made with copy_interval or must be the whole
1682 tree of a buffer or a string.
1684 This is used in insdel.c when inserting Lisp_Strings into the
1685 buffer. The text corresponding to SOURCE is already in the buffer
1686 when this is called. The intervals of new tree are a copy of those
1687 belonging to the string being inserted; intervals are never
1690 If the inserted text had no intervals associated, and we don't
1691 want to inherit the surrounding text's properties, this function
1692 simply returns -- offset_intervals should handle placing the
1693 text in the correct interval, depending on the sticky bits.
1695 If the inserted text had properties (intervals), then there are two
1696 cases -- either insertion happened in the middle of some interval,
1697 or between two intervals.
1699 If the text goes into the middle of an interval, then new
1700 intervals are created in the middle with only the properties of
1701 the new text, *unless* the macro MERGE_INSERTIONS is true, in
1702 which case the new text has the union of its properties and those
1703 of the text into which it was inserted.
1705 If the text goes between two intervals, then if neither interval
1706 had its appropriate sticky property set (front_sticky, rear_sticky),
1707 the new text has only its properties. If one of the sticky properties
1708 is set, then the new text "sticks" to that region and its properties
1709 depend on merging as above. If both the preceding and succeeding
1710 intervals to the new text are "sticky", then the new text retains
1711 only its properties, as if neither sticky property were set. Perhaps
1712 we should consider merging all three sets of properties onto the new
1716 graft_intervals_into_buffer (source
, position
, length
, buffer
, inherit
)
1718 int position
, length
;
1719 struct buffer
*buffer
;
1722 register INTERVAL under
, over
, this, prev
;
1723 register INTERVAL tree
;
1726 tree
= BUF_INTERVALS (buffer
);
1728 /* If the new text has no properties, then with inheritance it
1729 becomes part of whatever interval it was inserted into.
1730 To prevent inheritance, we must clear out the properties
1731 of the newly inserted text. */
1732 if (NULL_INTERVAL_P (source
))
1735 if (!inherit
&& !NULL_INTERVAL_P (tree
) && length
> 0)
1737 XSETBUFFER (buf
, buffer
);
1738 set_text_properties_1 (make_number (position
),
1739 make_number (position
+ length
),
1742 if (! NULL_INTERVAL_P (BUF_INTERVALS (buffer
)))
1743 /* Shouldn't be necessary. -stef */
1744 BUF_INTERVALS (buffer
) = balance_an_interval (BUF_INTERVALS (buffer
));
1748 if (NULL_INTERVAL_P (tree
))
1750 /* The inserted text constitutes the whole buffer, so
1751 simply copy over the interval structure. */
1752 if ((BUF_Z (buffer
) - BUF_BEG (buffer
)) == TOTAL_LENGTH (source
))
1755 XSETBUFFER (buf
, buffer
);
1756 BUF_INTERVALS (buffer
) = reproduce_tree_obj (source
, buf
);
1757 BUF_INTERVALS (buffer
)->position
= BEG
;
1758 BUF_INTERVALS (buffer
)->up_obj
= 1;
1760 /* Explicitly free the old tree here? */
1765 /* Create an interval tree in which to place a copy
1766 of the intervals of the inserted string. */
1769 XSETBUFFER (buf
, buffer
);
1770 tree
= create_root_interval (buf
);
1773 else if (TOTAL_LENGTH (tree
) == TOTAL_LENGTH (source
))
1774 /* If the buffer contains only the new string, but
1775 there was already some interval tree there, then it may be
1776 some zero length intervals. Eventually, do something clever
1777 about inserting properly. For now, just waste the old intervals. */
1779 BUF_INTERVALS (buffer
) = reproduce_tree (source
, INTERVAL_PARENT (tree
));
1780 BUF_INTERVALS (buffer
)->position
= BEG
;
1781 BUF_INTERVALS (buffer
)->up_obj
= 1;
1782 /* Explicitly free the old tree here. */
1786 /* Paranoia -- the text has already been added, so this buffer
1787 should be of non-zero length. */
1788 else if (TOTAL_LENGTH (tree
) == 0)
1791 this = under
= find_interval (tree
, position
);
1792 if (NULL_INTERVAL_P (under
)) /* Paranoia */
1794 over
= find_interval (source
, interval_start_pos (source
));
1796 /* Here for insertion in the middle of an interval.
1797 Split off an equivalent interval to the right,
1798 then don't bother with it any more. */
1800 if (position
> under
->position
)
1802 INTERVAL end_unchanged
1803 = split_interval_left (this, position
- under
->position
);
1804 copy_properties (under
, end_unchanged
);
1805 under
->position
= position
;
1809 /* This call may have some effect because previous_interval may
1810 update `position' fields of intervals. Thus, don't ignore it
1811 for the moment. Someone please tell me the truth (K.Handa). */
1812 prev
= previous_interval (under
);
1814 /* But, this code surely has no effect. And, anyway,
1815 END_NONSTICKY_P is unreliable now. */
1816 if (prev
&& !END_NONSTICKY_P (prev
))
1821 /* Insertion is now at beginning of UNDER. */
1823 /* The inserted text "sticks" to the interval `under',
1824 which means it gets those properties.
1825 The properties of under are the result of
1826 adjust_intervals_for_insertion, so stickiness has
1827 already been taken care of. */
1829 /* OVER is the interval we are copying from next.
1830 OVER_USED says how many characters' worth of OVER
1831 have already been copied into target intervals.
1832 UNDER is the next interval in the target. */
1834 while (! NULL_INTERVAL_P (over
))
1836 /* If UNDER is longer than OVER, split it. */
1837 if (LENGTH (over
) - over_used
< LENGTH (under
))
1839 this = split_interval_left (under
, LENGTH (over
) - over_used
);
1840 copy_properties (under
, this);
1845 /* THIS is now the interval to copy or merge into.
1846 OVER covers all of it. */
1848 merge_properties (over
, this);
1850 copy_properties (over
, this);
1852 /* If THIS and OVER end at the same place,
1853 advance OVER to a new source interval. */
1854 if (LENGTH (this) == LENGTH (over
) - over_used
)
1856 over
= next_interval (over
);
1860 /* Otherwise just record that more of OVER has been used. */
1861 over_used
+= LENGTH (this);
1863 /* Always advance to a new target interval. */
1864 under
= next_interval (this);
1867 if (! NULL_INTERVAL_P (BUF_INTERVALS (buffer
)))
1868 BUF_INTERVALS (buffer
) = balance_an_interval (BUF_INTERVALS (buffer
));
1872 /* Get the value of property PROP from PLIST,
1873 which is the plist of an interval.
1874 We check for direct properties, for categories with property PROP,
1875 and for PROP appearing on the default-text-properties list. */
1878 textget (plist
, prop
)
1880 register Lisp_Object prop
;
1882 return lookup_char_property (plist
, prop
, 1);
1886 lookup_char_property (plist
, prop
, textprop
)
1888 register Lisp_Object prop
;
1891 register Lisp_Object tail
, fallback
= Qnil
;
1893 for (tail
= plist
; CONSP (tail
); tail
= Fcdr (XCDR (tail
)))
1895 register Lisp_Object tem
;
1898 return Fcar (XCDR (tail
));
1899 if (EQ (tem
, Qcategory
))
1901 tem
= Fcar (XCDR (tail
));
1903 fallback
= Fget (tem
, prop
);
1907 if (! NILP (fallback
))
1909 /* Check for alternative properties */
1910 tail
= Fassq (prop
, Vchar_property_alias_alist
);
1914 for (; NILP (fallback
) && CONSP (tail
); tail
= XCDR (tail
))
1915 fallback
= Fplist_get (plist
, XCAR (tail
));
1918 if (textprop
&& NILP (fallback
) && CONSP (Vdefault_text_properties
))
1919 fallback
= Fplist_get (Vdefault_text_properties
, prop
);
1924 /* Set point "temporarily", without checking any text properties. */
1927 temp_set_point (struct buffer
*buffer
, EMACS_INT charpos
)
1929 temp_set_point_both (buffer
, charpos
,
1930 buf_charpos_to_bytepos (buffer
, charpos
));
1933 /* Set point in BUFFER "temporarily" to CHARPOS, which corresponds to
1934 byte position BYTEPOS. */
1937 temp_set_point_both (struct buffer
*buffer
,
1938 EMACS_INT charpos
, EMACS_INT bytepos
)
1940 /* In a single-byte buffer, the two positions must be equal. */
1941 if (BUF_ZV (buffer
) == BUF_ZV_BYTE (buffer
)
1942 && charpos
!= bytepos
)
1945 if (charpos
> bytepos
)
1948 if (charpos
> BUF_ZV (buffer
) || charpos
< BUF_BEGV (buffer
))
1951 BUF_PT_BYTE (buffer
) = bytepos
;
1952 BUF_PT (buffer
) = charpos
;
1955 /* Set point in BUFFER to CHARPOS. If the target position is
1956 before an intangible character, move to an ok place. */
1959 set_point (EMACS_INT charpos
)
1961 set_point_both (charpos
, buf_charpos_to_bytepos (current_buffer
, charpos
));
1964 /* If there's an invisible character at position POS + TEST_OFFS in the
1965 current buffer, and the invisible property has a `stickiness' such that
1966 inserting a character at position POS would inherit the property it,
1967 return POS + ADJ, otherwise return POS. If TEST_INTANG is non-zero,
1968 then intangibility is required as well as invisibleness.
1970 TEST_OFFS should be either 0 or -1, and ADJ should be either 1 or -1.
1972 Note that `stickiness' is determined by overlay marker insertion types,
1973 if the invisible property comes from an overlay. */
1976 adjust_for_invis_intang (pos
, test_offs
, adj
, test_intang
)
1977 int pos
, test_offs
, adj
, test_intang
;
1979 Lisp_Object invis_propval
, invis_overlay
;
1980 Lisp_Object test_pos
;
1982 if ((adj
< 0 && pos
+ adj
< BEGV
) || (adj
> 0 && pos
+ adj
> ZV
))
1983 /* POS + ADJ would be beyond the buffer bounds, so do no adjustment. */
1986 test_pos
= make_number (pos
+ test_offs
);
1989 = get_char_property_and_overlay (test_pos
, Qinvisible
, Qnil
,
1993 || ! NILP (Fget_char_property (test_pos
, Qintangible
, Qnil
)))
1994 && TEXT_PROP_MEANS_INVISIBLE (invis_propval
)
1995 /* This next test is true if the invisible property has a stickiness
1996 such that an insertion at POS would inherit it. */
1997 && (NILP (invis_overlay
)
1998 /* Invisible property is from a text-property. */
1999 ? (text_property_stickiness (Qinvisible
, make_number (pos
), Qnil
)
2000 == (test_offs
== 0 ? 1 : -1))
2001 /* Invisible property is from an overlay. */
2003 ? XMARKER (OVERLAY_START (invis_overlay
))->insertion_type
== 0
2004 : XMARKER (OVERLAY_END (invis_overlay
))->insertion_type
== 1)))
2010 /* Set point in BUFFER to CHARPOS, which corresponds to byte
2011 position BYTEPOS. If the target position is
2012 before an intangible character, move to an ok place. */
2015 set_point_both (EMACS_INT charpos
, EMACS_INT bytepos
)
2017 register INTERVAL to
, from
, toprev
, fromprev
;
2018 EMACS_INT buffer_point
;
2019 EMACS_INT old_position
= PT
;
2020 /* This ensures that we move forward past intangible text when the
2021 initial position is the same as the destination, in the rare
2022 instances where this is important, e.g. in line-move-finish
2024 int backwards
= (charpos
< old_position
? 1 : 0);
2026 EMACS_INT original_position
;
2028 current_buffer
->point_before_scroll
= Qnil
;
2033 /* In a single-byte buffer, the two positions must be equal. */
2034 eassert (ZV
!= ZV_BYTE
|| charpos
== bytepos
);
2036 /* Check this now, before checking if the buffer has any intervals.
2037 That way, we can catch conditions which break this sanity check
2038 whether or not there are intervals in the buffer. */
2039 eassert (charpos
<= ZV
&& charpos
>= BEGV
);
2041 have_overlays
= (current_buffer
->overlays_before
2042 || current_buffer
->overlays_after
);
2044 /* If we have no text properties and overlays,
2045 then we can do it quickly. */
2046 if (NULL_INTERVAL_P (BUF_INTERVALS (current_buffer
)) && ! have_overlays
)
2048 temp_set_point_both (current_buffer
, charpos
, bytepos
);
2052 /* Set TO to the interval containing the char after CHARPOS,
2053 and TOPREV to the interval containing the char before CHARPOS.
2054 Either one may be null. They may be equal. */
2055 to
= find_interval (BUF_INTERVALS (current_buffer
), charpos
);
2056 if (charpos
== BEGV
)
2058 else if (to
&& to
->position
== charpos
)
2059 toprev
= previous_interval (to
);
2063 buffer_point
= (PT
== ZV
? ZV
- 1 : PT
);
2065 /* Set FROM to the interval containing the char after PT,
2066 and FROMPREV to the interval containing the char before PT.
2067 Either one may be null. They may be equal. */
2068 /* We could cache this and save time. */
2069 from
= find_interval (BUF_INTERVALS (current_buffer
), buffer_point
);
2070 if (buffer_point
== BEGV
)
2072 else if (from
&& from
->position
== PT
)
2073 fromprev
= previous_interval (from
);
2074 else if (buffer_point
!= PT
)
2075 fromprev
= from
, from
= 0;
2079 /* Moving within an interval. */
2080 if (to
== from
&& toprev
== fromprev
&& INTERVAL_VISIBLE_P (to
)
2083 temp_set_point_both (current_buffer
, charpos
, bytepos
);
2087 original_position
= charpos
;
2089 /* If the new position is between two intangible characters
2090 with the same intangible property value,
2091 move forward or backward until a change in that property. */
2092 if (NILP (Vinhibit_point_motion_hooks
)
2093 && ((! NULL_INTERVAL_P (to
) && ! NULL_INTERVAL_P (toprev
))
2095 /* Intangibility never stops us from positioning at the beginning
2096 or end of the buffer, so don't bother checking in that case. */
2097 && charpos
!= BEGV
&& charpos
!= ZV
)
2100 Lisp_Object intangible_propval
;
2104 /* If the preceding character is both intangible and invisible,
2105 and the invisible property is `rear-sticky', perturb it so
2106 that the search starts one character earlier -- this ensures
2107 that point can never move to the end of an invisible/
2108 intangible/rear-sticky region. */
2109 charpos
= adjust_for_invis_intang (charpos
, -1, -1, 1);
2111 XSETINT (pos
, charpos
);
2113 /* If following char is intangible,
2114 skip back over all chars with matching intangible property. */
2116 intangible_propval
= Fget_char_property (pos
, Qintangible
, Qnil
);
2118 if (! NILP (intangible_propval
))
2120 while (XINT (pos
) > BEGV
2121 && EQ (Fget_char_property (make_number (XINT (pos
) - 1),
2123 intangible_propval
))
2124 pos
= Fprevious_char_property_change (pos
, Qnil
);
2126 /* Set CHARPOS from POS, and if the final intangible character
2127 that we skipped over is also invisible, and the invisible
2128 property is `front-sticky', perturb it to be one character
2129 earlier -- this ensures that point can never move to the
2130 beginning of an invisible/intangible/front-sticky region. */
2131 charpos
= adjust_for_invis_intang (XINT (pos
), 0, -1, 0);
2136 /* If the following character is both intangible and invisible,
2137 and the invisible property is `front-sticky', perturb it so
2138 that the search starts one character later -- this ensures
2139 that point can never move to the beginning of an
2140 invisible/intangible/front-sticky region. */
2141 charpos
= adjust_for_invis_intang (charpos
, 0, 1, 1);
2143 XSETINT (pos
, charpos
);
2145 /* If preceding char is intangible,
2146 skip forward over all chars with matching intangible property. */
2148 intangible_propval
= Fget_char_property (make_number (charpos
- 1),
2151 if (! NILP (intangible_propval
))
2153 while (XINT (pos
) < ZV
2154 && EQ (Fget_char_property (pos
, Qintangible
, Qnil
),
2155 intangible_propval
))
2156 pos
= Fnext_char_property_change (pos
, Qnil
);
2158 /* Set CHARPOS from POS, and if the final intangible character
2159 that we skipped over is also invisible, and the invisible
2160 property is `rear-sticky', perturb it to be one character
2161 later -- this ensures that point can never move to the
2162 end of an invisible/intangible/rear-sticky region. */
2163 charpos
= adjust_for_invis_intang (XINT (pos
), -1, 1, 0);
2167 bytepos
= buf_charpos_to_bytepos (current_buffer
, charpos
);
2170 if (charpos
!= original_position
)
2172 /* Set TO to the interval containing the char after CHARPOS,
2173 and TOPREV to the interval containing the char before CHARPOS.
2174 Either one may be null. They may be equal. */
2175 to
= find_interval (BUF_INTERVALS (current_buffer
), charpos
);
2176 if (charpos
== BEGV
)
2178 else if (to
&& to
->position
== charpos
)
2179 toprev
= previous_interval (to
);
2184 /* Here TO is the interval after the stopping point
2185 and TOPREV is the interval before the stopping point.
2186 One or the other may be null. */
2188 temp_set_point_both (current_buffer
, charpos
, bytepos
);
2190 /* We run point-left and point-entered hooks here, if the
2191 two intervals are not equivalent. These hooks take
2192 (old_point, new_point) as arguments. */
2193 if (NILP (Vinhibit_point_motion_hooks
)
2194 && (! intervals_equal (from
, to
)
2195 || ! intervals_equal (fromprev
, toprev
)))
2197 Lisp_Object leave_after
, leave_before
, enter_after
, enter_before
;
2200 leave_before
= textget (fromprev
->plist
, Qpoint_left
);
2202 leave_before
= Qnil
;
2205 leave_after
= textget (from
->plist
, Qpoint_left
);
2210 enter_before
= textget (toprev
->plist
, Qpoint_entered
);
2212 enter_before
= Qnil
;
2215 enter_after
= textget (to
->plist
, Qpoint_entered
);
2219 if (! EQ (leave_before
, enter_before
) && !NILP (leave_before
))
2220 call2 (leave_before
, make_number (old_position
),
2221 make_number (charpos
));
2222 if (! EQ (leave_after
, enter_after
) && !NILP (leave_after
))
2223 call2 (leave_after
, make_number (old_position
),
2224 make_number (charpos
));
2226 if (! EQ (enter_before
, leave_before
) && !NILP (enter_before
))
2227 call2 (enter_before
, make_number (old_position
),
2228 make_number (charpos
));
2229 if (! EQ (enter_after
, leave_after
) && !NILP (enter_after
))
2230 call2 (enter_after
, make_number (old_position
),
2231 make_number (charpos
));
2235 /* Move point to POSITION, unless POSITION is inside an intangible
2236 segment that reaches all the way to point. */
2239 move_if_not_intangible (position
)
2243 Lisp_Object intangible_propval
;
2245 XSETINT (pos
, position
);
2247 if (! NILP (Vinhibit_point_motion_hooks
))
2248 /* If intangible is inhibited, always move point to POSITION. */
2250 else if (PT
< position
&& XINT (pos
) < ZV
)
2252 /* We want to move forward, so check the text before POSITION. */
2254 intangible_propval
= Fget_char_property (pos
,
2257 /* If following char is intangible,
2258 skip back over all chars with matching intangible property. */
2259 if (! NILP (intangible_propval
))
2260 while (XINT (pos
) > BEGV
2261 && EQ (Fget_char_property (make_number (XINT (pos
) - 1),
2263 intangible_propval
))
2264 pos
= Fprevious_char_property_change (pos
, Qnil
);
2266 else if (XINT (pos
) > BEGV
)
2268 /* We want to move backward, so check the text after POSITION. */
2270 intangible_propval
= Fget_char_property (make_number (XINT (pos
) - 1),
2273 /* If following char is intangible,
2274 skip forward over all chars with matching intangible property. */
2275 if (! NILP (intangible_propval
))
2276 while (XINT (pos
) < ZV
2277 && EQ (Fget_char_property (pos
, Qintangible
, Qnil
),
2278 intangible_propval
))
2279 pos
= Fnext_char_property_change (pos
, Qnil
);
2282 else if (position
< BEGV
)
2284 else if (position
> ZV
)
2287 /* If the whole stretch between PT and POSITION isn't intangible,
2288 try moving to POSITION (which means we actually move farther
2289 if POSITION is inside of intangible text). */
2291 if (XINT (pos
) != PT
)
2295 /* If text at position POS has property PROP, set *VAL to the property
2296 value, *START and *END to the beginning and end of a region that
2297 has the same property, and return 1. Otherwise return 0.
2299 OBJECT is the string or buffer to look for the property in;
2300 nil means the current buffer. */
2303 get_property_and_range (pos
, prop
, val
, start
, end
, object
)
2305 Lisp_Object prop
, *val
;
2306 EMACS_INT
*start
, *end
;
2309 INTERVAL i
, prev
, next
;
2312 i
= find_interval (BUF_INTERVALS (current_buffer
), pos
);
2313 else if (BUFFERP (object
))
2314 i
= find_interval (BUF_INTERVALS (XBUFFER (object
)), pos
);
2315 else if (STRINGP (object
))
2316 i
= find_interval (STRING_INTERVALS (object
), pos
);
2320 if (NULL_INTERVAL_P (i
) || (i
->position
+ LENGTH (i
) <= pos
))
2322 *val
= textget (i
->plist
, prop
);
2326 next
= i
; /* remember it in advance */
2327 prev
= previous_interval (i
);
2328 while (! NULL_INTERVAL_P (prev
)
2329 && EQ (*val
, textget (prev
->plist
, prop
)))
2330 i
= prev
, prev
= previous_interval (prev
);
2331 *start
= i
->position
;
2333 next
= next_interval (i
);
2334 while (! NULL_INTERVAL_P (next
)
2335 && EQ (*val
, textget (next
->plist
, prop
)))
2336 i
= next
, next
= next_interval (next
);
2337 *end
= i
->position
+ LENGTH (i
);
2342 /* Return the proper local keymap TYPE for position POSITION in
2343 BUFFER; TYPE should be one of `keymap' or `local-map'. Use the map
2344 specified by the PROP property, if any. Otherwise, if TYPE is
2345 `local-map' use BUFFER's local map.
2347 POSITION must be in the accessible part of BUFFER. */
2350 get_local_map (position
, buffer
, type
)
2351 register int position
;
2352 register struct buffer
*buffer
;
2355 Lisp_Object prop
, lispy_position
, lispy_buffer
;
2356 int old_begv
, old_zv
, old_begv_byte
, old_zv_byte
;
2358 /* Perhaps we should just change `position' to the limit. */
2359 if (position
> BUF_ZV (buffer
) || position
< BUF_BEGV (buffer
))
2362 /* Ignore narrowing, so that a local map continues to be valid even if
2363 the visible region contains no characters and hence no properties. */
2364 old_begv
= BUF_BEGV (buffer
);
2365 old_zv
= BUF_ZV (buffer
);
2366 old_begv_byte
= BUF_BEGV_BYTE (buffer
);
2367 old_zv_byte
= BUF_ZV_BYTE (buffer
);
2368 BUF_BEGV (buffer
) = BUF_BEG (buffer
);
2369 BUF_ZV (buffer
) = BUF_Z (buffer
);
2370 BUF_BEGV_BYTE (buffer
) = BUF_BEG_BYTE (buffer
);
2371 BUF_ZV_BYTE (buffer
) = BUF_Z_BYTE (buffer
);
2373 XSETFASTINT (lispy_position
, position
);
2374 XSETBUFFER (lispy_buffer
, buffer
);
2375 /* First check if the CHAR has any property. This is because when
2376 we click with the mouse, the mouse pointer is really pointing
2377 to the CHAR after POS. */
2378 prop
= Fget_char_property (lispy_position
, type
, lispy_buffer
);
2379 /* If not, look at the POS's properties. This is necessary because when
2380 editing a field with a `local-map' property, we want insertion at the end
2381 to obey the `local-map' property. */
2383 prop
= get_pos_property (lispy_position
, type
, lispy_buffer
);
2385 BUF_BEGV (buffer
) = old_begv
;
2386 BUF_ZV (buffer
) = old_zv
;
2387 BUF_BEGV_BYTE (buffer
) = old_begv_byte
;
2388 BUF_ZV_BYTE (buffer
) = old_zv_byte
;
2390 /* Use the local map only if it is valid. */
2391 prop
= get_keymap (prop
, 0, 0);
2395 if (EQ (type
, Qkeymap
))
2398 return buffer
->keymap
;
2401 /* Produce an interval tree reflecting the intervals in
2402 TREE from START to START + LENGTH.
2403 The new interval tree has no parent and has a starting-position of 0. */
2406 copy_intervals (tree
, start
, length
)
2410 register INTERVAL i
, new, t
;
2411 register int got
, prevlen
;
2413 if (NULL_INTERVAL_P (tree
) || length
<= 0)
2414 return NULL_INTERVAL
;
2416 i
= find_interval (tree
, start
);
2417 if (NULL_INTERVAL_P (i
) || LENGTH (i
) == 0)
2420 /* If there is only one interval and it's the default, return nil. */
2421 if ((start
- i
->position
+ 1 + length
) < LENGTH (i
)
2422 && DEFAULT_INTERVAL_P (i
))
2423 return NULL_INTERVAL
;
2425 new = make_interval ();
2427 got
= (LENGTH (i
) - (start
- i
->position
));
2428 new->total_length
= length
;
2429 CHECK_TOTAL_LENGTH (new);
2430 copy_properties (i
, new);
2434 while (got
< length
)
2436 i
= next_interval (i
);
2437 t
= split_interval_right (t
, prevlen
);
2438 copy_properties (i
, t
);
2439 prevlen
= LENGTH (i
);
2443 return balance_an_interval (new);
2446 /* Give STRING the properties of BUFFER from POSITION to LENGTH. */
2449 copy_intervals_to_string (string
, buffer
, position
, length
)
2451 struct buffer
*buffer
;
2452 int position
, length
;
2454 INTERVAL interval_copy
= copy_intervals (BUF_INTERVALS (buffer
),
2456 if (NULL_INTERVAL_P (interval_copy
))
2459 SET_INTERVAL_OBJECT (interval_copy
, string
);
2460 STRING_SET_INTERVALS (string
, interval_copy
);
2463 /* Return 1 if strings S1 and S2 have identical properties; 0 otherwise.
2464 Assume they have identical characters. */
2467 compare_string_intervals (s1
, s2
)
2472 int end
= SCHARS (s1
);
2474 i1
= find_interval (STRING_INTERVALS (s1
), 0);
2475 i2
= find_interval (STRING_INTERVALS (s2
), 0);
2479 /* Determine how far we can go before we reach the end of I1 or I2. */
2480 int len1
= (i1
!= 0 ? INTERVAL_LAST_POS (i1
) : end
) - pos
;
2481 int len2
= (i2
!= 0 ? INTERVAL_LAST_POS (i2
) : end
) - pos
;
2482 int distance
= min (len1
, len2
);
2484 /* If we ever find a mismatch between the strings,
2486 if (! intervals_equal (i1
, i2
))
2489 /* Advance POS till the end of the shorter interval,
2490 and advance one or both interval pointers for the new position. */
2492 if (len1
== distance
)
2493 i1
= next_interval (i1
);
2494 if (len2
== distance
)
2495 i2
= next_interval (i2
);
2500 /* Recursively adjust interval I in the current buffer
2501 for setting enable_multibyte_characters to MULTI_FLAG.
2502 The range of interval I is START ... END in characters,
2503 START_BYTE ... END_BYTE in bytes. */
2506 set_intervals_multibyte_1 (i
, multi_flag
, start
, start_byte
, end
, end_byte
)
2509 int start
, start_byte
, end
, end_byte
;
2511 /* Fix the length of this interval. */
2513 i
->total_length
= end
- start
;
2515 i
->total_length
= end_byte
- start_byte
;
2516 CHECK_TOTAL_LENGTH (i
);
2518 if (TOTAL_LENGTH (i
) == 0)
2520 delete_interval (i
);
2524 /* Recursively fix the length of the subintervals. */
2527 int left_end
, left_end_byte
;
2532 left_end_byte
= start_byte
+ LEFT_TOTAL_LENGTH (i
);
2533 left_end
= BYTE_TO_CHAR (left_end_byte
);
2535 temp
= CHAR_TO_BYTE (left_end
);
2537 /* If LEFT_END_BYTE is in the middle of a character,
2538 adjust it and LEFT_END to a char boundary. */
2539 if (left_end_byte
> temp
)
2541 left_end_byte
= temp
;
2543 if (left_end_byte
< temp
)
2546 left_end_byte
= CHAR_TO_BYTE (left_end
);
2551 left_end
= start
+ LEFT_TOTAL_LENGTH (i
);
2552 left_end_byte
= CHAR_TO_BYTE (left_end
);
2555 set_intervals_multibyte_1 (i
->left
, multi_flag
, start
, start_byte
,
2556 left_end
, left_end_byte
);
2560 int right_start_byte
, right_start
;
2566 right_start_byte
= end_byte
- RIGHT_TOTAL_LENGTH (i
);
2567 right_start
= BYTE_TO_CHAR (right_start_byte
);
2569 /* If RIGHT_START_BYTE is in the middle of a character,
2570 adjust it and RIGHT_START to a char boundary. */
2571 temp
= CHAR_TO_BYTE (right_start
);
2573 if (right_start_byte
< temp
)
2575 right_start_byte
= temp
;
2577 if (right_start_byte
> temp
)
2580 right_start_byte
= CHAR_TO_BYTE (right_start
);
2585 right_start
= end
- RIGHT_TOTAL_LENGTH (i
);
2586 right_start_byte
= CHAR_TO_BYTE (right_start
);
2589 set_intervals_multibyte_1 (i
->right
, multi_flag
,
2590 right_start
, right_start_byte
,
2594 /* Rounding to char boundaries can theoretically ake this interval
2595 spurious. If so, delete one child, and copy its property list
2596 to this interval. */
2597 if (LEFT_TOTAL_LENGTH (i
) + RIGHT_TOTAL_LENGTH (i
) >= TOTAL_LENGTH (i
))
2601 (i
)->plist
= (i
)->left
->plist
;
2602 (i
)->left
->total_length
= 0;
2603 delete_interval ((i
)->left
);
2607 (i
)->plist
= (i
)->right
->plist
;
2608 (i
)->right
->total_length
= 0;
2609 delete_interval ((i
)->right
);
2614 /* Update the intervals of the current buffer
2615 to fit the contents as multibyte (if MULTI_FLAG is 1)
2616 or to fit them as non-multibyte (if MULTI_FLAG is 0). */
2619 set_intervals_multibyte (multi_flag
)
2622 if (BUF_INTERVALS (current_buffer
))
2623 set_intervals_multibyte_1 (BUF_INTERVALS (current_buffer
), multi_flag
,
2624 BEG
, BEG_BYTE
, Z
, Z_BYTE
);
2627 /* arch-tag: 3d402b60-083c-4271-b4a3-ebd9a74bfe27
2628 (do not change this comment) */