Don't show drag cursor when modeline can't be dragged (Bug#16647).
[emacs.git] / src / intervals.c
blob703c0cefbd50c9f01eaa7f4ed28dfbf4392e194a
1 /* Code for doing intervals.
2 Copyright (C) 1993-1995, 1997-1998, 2001-2014 Free Software
3 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/>. */
21 /* NOTES:
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
36 to GC them.
41 #include <config.h>
43 #include <intprops.h>
44 #include "lisp.h"
45 #include "intervals.h"
46 #include "character.h"
47 #include "buffer.h"
48 #include "puresize.h"
49 #include "keyboard.h"
50 #include "keymap.h"
52 /* Test for membership, allowing for t (actually any non-cons) to mean the
53 universal set. */
55 #define TMEM(sym, set) (CONSP (set) ? ! NILP (Fmemq (sym, set)) : ! NILP (set))
57 static Lisp_Object merge_properties_sticky (Lisp_Object, Lisp_Object);
58 static INTERVAL merge_interval_right (INTERVAL);
59 static INTERVAL reproduce_tree (INTERVAL, INTERVAL);
61 /* Utility functions for intervals. */
63 /* Use these functions to set pointer slots of struct interval. */
65 static void
66 set_interval_left (INTERVAL i, INTERVAL left)
68 i->left = left;
71 static void
72 set_interval_right (INTERVAL i, INTERVAL right)
74 i->right = right;
77 /* Make the parent of D be whatever the parent of S is, regardless
78 of the type. This is used when balancing an interval tree. */
80 static void
81 copy_interval_parent (INTERVAL d, INTERVAL s)
83 d->up = s->up;
84 d->up_obj = s->up_obj;
87 /* Create the root interval of some object, a buffer or string. */
89 INTERVAL
90 create_root_interval (Lisp_Object parent)
92 INTERVAL new;
94 CHECK_IMPURE (parent);
96 new = make_interval ();
98 if (BUFFERP (parent))
100 new->total_length = (BUF_Z (XBUFFER (parent))
101 - BUF_BEG (XBUFFER (parent)));
102 eassert (TOTAL_LENGTH (new) >= 0);
103 set_buffer_intervals (XBUFFER (parent), new);
104 new->position = BEG;
106 else if (STRINGP (parent))
108 new->total_length = SCHARS (parent);
109 eassert (TOTAL_LENGTH (new) >= 0);
110 set_string_intervals (parent, new);
111 new->position = 0;
114 set_interval_object (new, parent);
116 return new;
119 /* Make the interval TARGET have exactly the properties of SOURCE */
121 void
122 copy_properties (register INTERVAL source, register INTERVAL target)
124 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
125 return;
127 COPY_INTERVAL_CACHE (source, target);
128 set_interval_plist (target, Fcopy_sequence (source->plist));
131 /* Merge the properties of interval SOURCE into the properties
132 of interval TARGET. That is to say, each property in SOURCE
133 is added to TARGET if TARGET has no such property as yet. */
135 static void
136 merge_properties (register INTERVAL source, register INTERVAL target)
138 register Lisp_Object o, sym, val;
140 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
141 return;
143 MERGE_INTERVAL_CACHE (source, target);
145 o = source->plist;
146 while (CONSP (o))
148 sym = XCAR (o);
149 o = XCDR (o);
150 CHECK_CONS (o);
152 val = target->plist;
153 while (CONSP (val) && !EQ (XCAR (val), sym))
155 val = XCDR (val);
156 if (!CONSP (val))
157 break;
158 val = XCDR (val);
161 if (NILP (val))
163 val = XCAR (o);
164 set_interval_plist (target, Fcons (sym, Fcons (val, target->plist)));
166 o = XCDR (o);
170 /* Return true if the two intervals have the same properties. */
172 bool
173 intervals_equal (INTERVAL i0, INTERVAL i1)
175 Lisp_Object i0_cdr, i0_sym;
176 Lisp_Object i1_cdr, i1_val;
178 if (DEFAULT_INTERVAL_P (i0) && DEFAULT_INTERVAL_P (i1))
179 return 1;
181 if (DEFAULT_INTERVAL_P (i0) || DEFAULT_INTERVAL_P (i1))
182 return 0;
184 i0_cdr = i0->plist;
185 i1_cdr = i1->plist;
186 while (CONSP (i0_cdr) && CONSP (i1_cdr))
188 i0_sym = XCAR (i0_cdr);
189 i0_cdr = XCDR (i0_cdr);
190 if (!CONSP (i0_cdr))
191 return 0;
192 i1_val = i1->plist;
193 while (CONSP (i1_val) && !EQ (XCAR (i1_val), i0_sym))
195 i1_val = XCDR (i1_val);
196 if (!CONSP (i1_val))
197 return 0;
198 i1_val = XCDR (i1_val);
201 /* i0 has something i1 doesn't. */
202 if (EQ (i1_val, Qnil))
203 return 0;
205 /* i0 and i1 both have sym, but it has different values in each. */
206 if (!CONSP (i1_val)
207 || (i1_val = XCDR (i1_val), !CONSP (i1_val))
208 || !EQ (XCAR (i1_val), XCAR (i0_cdr)))
209 return 0;
211 i0_cdr = XCDR (i0_cdr);
213 i1_cdr = XCDR (i1_cdr);
214 if (!CONSP (i1_cdr))
215 return 0;
216 i1_cdr = XCDR (i1_cdr);
219 /* Lengths of the two plists were equal. */
220 return (NILP (i0_cdr) && NILP (i1_cdr));
224 /* Traverse an interval tree TREE, performing FUNCTION on each node.
225 No guarantee is made about the order of traversal.
226 Pass FUNCTION two args: an interval, and ARG. */
228 void
229 traverse_intervals_noorder (INTERVAL tree, void (*function) (INTERVAL, Lisp_Object), Lisp_Object arg)
231 /* Minimize stack usage. */
232 while (tree)
234 (*function) (tree, arg);
235 if (!tree->right)
236 tree = tree->left;
237 else
239 traverse_intervals_noorder (tree->left, function, arg);
240 tree = tree->right;
245 /* Traverse an interval tree TREE, performing FUNCTION on each node.
246 Pass FUNCTION two args: an interval, and ARG. */
248 void
249 traverse_intervals (INTERVAL tree, ptrdiff_t position,
250 void (*function) (INTERVAL, Lisp_Object), Lisp_Object arg)
252 while (tree)
254 traverse_intervals (tree->left, position, function, arg);
255 position += LEFT_TOTAL_LENGTH (tree);
256 tree->position = position;
257 (*function) (tree, arg);
258 position += LENGTH (tree); tree = tree->right;
262 #if 0
264 static int icount;
265 static int idepth;
266 static int zero_length;
268 /* These functions are temporary, for debugging purposes only. */
270 INTERVAL search_interval, found_interval;
272 void
273 check_for_interval (INTERVAL i)
275 if (i == search_interval)
277 found_interval = i;
278 icount++;
282 INTERVAL
283 search_for_interval (INTERVAL i, INTERVAL tree)
285 icount = 0;
286 search_interval = i;
287 found_interval = NULL;
288 traverse_intervals_noorder (tree, &check_for_interval, Qnil);
289 return found_interval;
292 static void
293 inc_interval_count (INTERVAL i)
295 icount++;
296 if (LENGTH (i) == 0)
297 zero_length++;
298 if (depth > idepth)
299 idepth = depth;
303 count_intervals (INTERVAL i)
305 icount = 0;
306 idepth = 0;
307 zero_length = 0;
308 traverse_intervals_noorder (i, &inc_interval_count, Qnil);
310 return icount;
313 static INTERVAL
314 root_interval (INTERVAL interval)
316 register INTERVAL i = interval;
318 while (! ROOT_INTERVAL_P (i))
319 i = INTERVAL_PARENT (i);
321 return i;
323 #endif
325 /* Assuming that a left child exists, perform the following operation:
328 / \ / \
329 B => A
330 / \ / \
334 static INTERVAL
335 rotate_right (INTERVAL interval)
337 INTERVAL i;
338 INTERVAL B = interval->left;
339 ptrdiff_t old_total = interval->total_length;
341 /* Deal with any Parent of A; make it point to B. */
342 if (! ROOT_INTERVAL_P (interval))
344 if (AM_LEFT_CHILD (interval))
345 set_interval_left (INTERVAL_PARENT (interval), B);
346 else
347 set_interval_right (INTERVAL_PARENT (interval), B);
349 copy_interval_parent (B, interval);
351 /* Make B the parent of A */
352 i = B->right;
353 set_interval_right (B, interval);
354 set_interval_parent (interval, B);
356 /* Make A point to c */
357 set_interval_left (interval, i);
358 if (i)
359 set_interval_parent (i, interval);
361 /* A's total length is decreased by the length of B and its left child. */
362 interval->total_length -= B->total_length - LEFT_TOTAL_LENGTH (interval);
363 eassert (TOTAL_LENGTH (interval) >= 0);
365 /* B must have the same total length of A. */
366 B->total_length = old_total;
367 eassert (TOTAL_LENGTH (B) >= 0);
369 return B;
372 /* Assuming that a right child exists, perform the following operation:
375 / \ / \
376 B => A
377 / \ / \
381 static INTERVAL
382 rotate_left (INTERVAL interval)
384 INTERVAL i;
385 INTERVAL B = interval->right;
386 ptrdiff_t old_total = interval->total_length;
388 /* Deal with any parent of A; make it point to B. */
389 if (! ROOT_INTERVAL_P (interval))
391 if (AM_LEFT_CHILD (interval))
392 set_interval_left (INTERVAL_PARENT (interval), B);
393 else
394 set_interval_right (INTERVAL_PARENT (interval), B);
396 copy_interval_parent (B, interval);
398 /* Make B the parent of A */
399 i = B->left;
400 set_interval_left (B, interval);
401 set_interval_parent (interval, B);
403 /* Make A point to c */
404 set_interval_right (interval, i);
405 if (i)
406 set_interval_parent (i, interval);
408 /* A's total length is decreased by the length of B and its right child. */
409 interval->total_length -= B->total_length - RIGHT_TOTAL_LENGTH (interval);
410 eassert (TOTAL_LENGTH (interval) >= 0);
412 /* B must have the same total length of A. */
413 B->total_length = old_total;
414 eassert (TOTAL_LENGTH (B) >= 0);
416 return B;
419 /* Balance an interval tree with the assumption that the subtrees
420 themselves are already balanced. */
422 static INTERVAL
423 balance_an_interval (INTERVAL i)
425 register ptrdiff_t old_diff, new_diff;
427 while (1)
429 old_diff = LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i);
430 if (old_diff > 0)
432 /* Since the left child is longer, there must be one. */
433 new_diff = i->total_length - i->left->total_length
434 + RIGHT_TOTAL_LENGTH (i->left) - LEFT_TOTAL_LENGTH (i->left);
435 if (eabs (new_diff) >= old_diff)
436 break;
437 i = rotate_right (i);
438 balance_an_interval (i->right);
440 else if (old_diff < 0)
442 /* Since the right child is longer, there must be one. */
443 new_diff = i->total_length - i->right->total_length
444 + LEFT_TOTAL_LENGTH (i->right) - RIGHT_TOTAL_LENGTH (i->right);
445 if (eabs (new_diff) >= -old_diff)
446 break;
447 i = rotate_left (i);
448 balance_an_interval (i->left);
450 else
451 break;
453 return i;
456 /* Balance INTERVAL, potentially stuffing it back into its parent
457 Lisp Object. */
459 static INTERVAL
460 balance_possible_root_interval (INTERVAL interval)
462 Lisp_Object parent;
463 bool have_parent = 0;
465 if (!INTERVAL_HAS_OBJECT (interval) && !INTERVAL_HAS_PARENT (interval))
466 return interval;
468 if (INTERVAL_HAS_OBJECT (interval))
470 have_parent = 1;
471 GET_INTERVAL_OBJECT (parent, interval);
473 interval = balance_an_interval (interval);
475 if (have_parent)
477 if (BUFFERP (parent))
478 set_buffer_intervals (XBUFFER (parent), interval);
479 else if (STRINGP (parent))
480 set_string_intervals (parent, interval);
483 return interval;
486 /* Balance the interval tree TREE. Balancing is by weight
487 (the amount of text). */
489 static INTERVAL
490 balance_intervals_internal (register INTERVAL tree)
492 /* Balance within each side. */
493 if (tree->left)
494 balance_intervals_internal (tree->left);
495 if (tree->right)
496 balance_intervals_internal (tree->right);
497 return balance_an_interval (tree);
500 /* Advertised interface to balance intervals. */
502 INTERVAL
503 balance_intervals (INTERVAL tree)
505 return tree ? balance_intervals_internal (tree) : NULL;
508 /* Rebalance text properties of B. */
510 static void
511 buffer_balance_intervals (struct buffer *b)
513 INTERVAL i;
515 eassert (b != NULL);
516 i = buffer_intervals (b);
517 if (i)
518 set_buffer_intervals (b, balance_an_interval (i));
521 /* Split INTERVAL into two pieces, starting the second piece at
522 character position OFFSET (counting from 0), relative to INTERVAL.
523 INTERVAL becomes the left-hand piece, and the right-hand piece
524 (second, lexicographically) is returned.
526 The size and position fields of the two intervals are set based upon
527 those of the original interval. The property list of the new interval
528 is reset, thus it is up to the caller to do the right thing with the
529 result.
531 Note that this does not change the position of INTERVAL; if it is a root,
532 it is still a root after this operation. */
534 INTERVAL
535 split_interval_right (INTERVAL interval, ptrdiff_t offset)
537 INTERVAL new = make_interval ();
538 ptrdiff_t position = interval->position;
539 ptrdiff_t new_length = LENGTH (interval) - offset;
541 new->position = position + offset;
542 set_interval_parent (new, interval);
544 if (NULL_RIGHT_CHILD (interval))
546 set_interval_right (interval, new);
547 new->total_length = new_length;
548 eassert (TOTAL_LENGTH (new) >= 0);
550 else
552 /* Insert the new node between INTERVAL and its right child. */
553 set_interval_right (new, interval->right);
554 set_interval_parent (interval->right, new);
555 set_interval_right (interval, new);
556 new->total_length = new_length + new->right->total_length;
557 eassert (TOTAL_LENGTH (new) >= 0);
558 balance_an_interval (new);
561 balance_possible_root_interval (interval);
563 return new;
566 /* Split INTERVAL into two pieces, starting the second piece at
567 character position OFFSET (counting from 0), relative to INTERVAL.
568 INTERVAL becomes the right-hand piece, and the left-hand piece
569 (first, lexicographically) is returned.
571 The size and position fields of the two intervals are set based upon
572 those of the original interval. The property list of the new interval
573 is reset, thus it is up to the caller to do the right thing with the
574 result.
576 Note that this does not change the position of INTERVAL; if it is a root,
577 it is still a root after this operation. */
579 INTERVAL
580 split_interval_left (INTERVAL interval, ptrdiff_t offset)
582 INTERVAL new = make_interval ();
583 ptrdiff_t new_length = offset;
585 new->position = interval->position;
586 interval->position = interval->position + offset;
587 set_interval_parent (new, interval);
589 if (NULL_LEFT_CHILD (interval))
591 set_interval_left (interval, new);
592 new->total_length = new_length;
593 eassert (TOTAL_LENGTH (new) >= 0);
595 else
597 /* Insert the new node between INTERVAL and its left child. */
598 set_interval_left (new, interval->left);
599 set_interval_parent (new->left, new);
600 set_interval_left (interval, new);
601 new->total_length = new_length + new->left->total_length;
602 eassert (TOTAL_LENGTH (new) >= 0);
603 balance_an_interval (new);
606 balance_possible_root_interval (interval);
608 return new;
611 /* Return the proper position for the first character
612 described by the interval tree SOURCE.
613 This is 1 if the parent is a buffer,
614 0 if the parent is a string or if there is no parent.
616 Don't use this function on an interval which is the child
617 of another interval! */
619 static int
620 interval_start_pos (INTERVAL source)
622 Lisp_Object parent;
624 if (!source)
625 return 0;
627 if (! INTERVAL_HAS_OBJECT (source))
628 return 0;
629 GET_INTERVAL_OBJECT (parent, source);
630 if (BUFFERP (parent))
631 return BUF_BEG (XBUFFER (parent));
632 return 0;
635 /* Find the interval containing text position POSITION in the text
636 represented by the interval tree TREE. POSITION is a buffer
637 position (starting from 1) or a string index (starting from 0).
638 If POSITION is at the end of the buffer or string,
639 return the interval containing the last character.
641 The `position' field, which is a cache of an interval's position,
642 is updated in the interval found. Other functions (e.g., next_interval)
643 will update this cache based on the result of find_interval. */
645 INTERVAL
646 find_interval (register INTERVAL tree, register ptrdiff_t position)
648 /* The distance from the left edge of the subtree at TREE
649 to POSITION. */
650 register ptrdiff_t relative_position;
652 if (!tree)
653 return NULL;
655 relative_position = position;
656 if (INTERVAL_HAS_OBJECT (tree))
658 Lisp_Object parent;
659 GET_INTERVAL_OBJECT (parent, tree);
660 if (BUFFERP (parent))
661 relative_position -= BUF_BEG (XBUFFER (parent));
664 eassert (relative_position <= TOTAL_LENGTH (tree));
666 tree = balance_possible_root_interval (tree);
668 while (1)
670 eassert (tree);
671 if (relative_position < LEFT_TOTAL_LENGTH (tree))
673 tree = tree->left;
675 else if (! NULL_RIGHT_CHILD (tree)
676 && relative_position >= (TOTAL_LENGTH (tree)
677 - RIGHT_TOTAL_LENGTH (tree)))
679 relative_position -= (TOTAL_LENGTH (tree)
680 - RIGHT_TOTAL_LENGTH (tree));
681 tree = tree->right;
683 else
685 tree->position
686 = (position - relative_position /* left edge of *tree. */
687 + LEFT_TOTAL_LENGTH (tree)); /* left edge of this interval. */
689 return tree;
694 /* Find the succeeding interval (lexicographically) to INTERVAL.
695 Sets the `position' field based on that of INTERVAL (see
696 find_interval). */
698 INTERVAL
699 next_interval (register INTERVAL interval)
701 register INTERVAL i = interval;
702 register ptrdiff_t next_position;
704 if (!i)
705 return NULL;
706 next_position = interval->position + LENGTH (interval);
708 if (! NULL_RIGHT_CHILD (i))
710 i = i->right;
711 while (! NULL_LEFT_CHILD (i))
712 i = i->left;
714 i->position = next_position;
715 return i;
718 while (! NULL_PARENT (i))
720 if (AM_LEFT_CHILD (i))
722 i = INTERVAL_PARENT (i);
723 i->position = next_position;
724 return i;
727 i = INTERVAL_PARENT (i);
730 return NULL;
733 /* Find the preceding interval (lexicographically) to INTERVAL.
734 Sets the `position' field based on that of INTERVAL (see
735 find_interval). */
737 INTERVAL
738 previous_interval (register INTERVAL interval)
740 register INTERVAL i;
742 if (!interval)
743 return NULL;
745 if (! NULL_LEFT_CHILD (interval))
747 i = interval->left;
748 while (! NULL_RIGHT_CHILD (i))
749 i = i->right;
751 i->position = interval->position - LENGTH (i);
752 return i;
755 i = interval;
756 while (! NULL_PARENT (i))
758 if (AM_RIGHT_CHILD (i))
760 i = INTERVAL_PARENT (i);
762 i->position = interval->position - LENGTH (i);
763 return i;
765 i = INTERVAL_PARENT (i);
768 return NULL;
771 /* Find the interval containing POS given some non-NULL INTERVAL
772 in the same tree. Note that we need to update interval->position
773 if we go down the tree.
774 To speed up the process, we assume that the ->position of
775 I and all its parents is already uptodate. */
776 INTERVAL
777 update_interval (register INTERVAL i, ptrdiff_t pos)
779 if (!i)
780 return NULL;
782 while (1)
784 if (pos < i->position)
786 /* Move left. */
787 if (pos >= i->position - TOTAL_LENGTH (i->left))
789 i->left->position = i->position - TOTAL_LENGTH (i->left)
790 + LEFT_TOTAL_LENGTH (i->left);
791 i = i->left; /* Move to the left child */
793 else if (NULL_PARENT (i))
794 error ("Point before start of properties");
795 else
796 i = INTERVAL_PARENT (i);
797 continue;
799 else if (pos >= INTERVAL_LAST_POS (i))
801 /* Move right. */
802 if (pos < INTERVAL_LAST_POS (i) + TOTAL_LENGTH (i->right))
804 i->right->position = INTERVAL_LAST_POS (i)
805 + LEFT_TOTAL_LENGTH (i->right);
806 i = i->right; /* Move to the right child */
808 else if (NULL_PARENT (i))
809 error ("Point %"pD"d after end of properties", pos);
810 else
811 i = INTERVAL_PARENT (i);
812 continue;
814 else
815 return i;
819 /* Effect an adjustment corresponding to the addition of LENGTH characters
820 of text. Do this by finding the interval containing POSITION in the
821 interval tree TREE, and then adjusting all of its ancestors by adding
822 LENGTH to them.
824 If POSITION is the first character of an interval, meaning that point
825 is actually between the two intervals, make the new text belong to
826 the interval which is "sticky".
828 If both intervals are "sticky", then make them belong to the left-most
829 interval. Another possibility would be to create a new interval for
830 this text, and make it have the merged properties of both ends. */
832 static INTERVAL
833 adjust_intervals_for_insertion (INTERVAL tree,
834 ptrdiff_t position, ptrdiff_t length)
836 INTERVAL i;
837 INTERVAL temp;
838 bool eobp = 0;
839 Lisp_Object parent;
840 ptrdiff_t offset;
842 eassert (TOTAL_LENGTH (tree) > 0);
844 GET_INTERVAL_OBJECT (parent, tree);
845 offset = (BUFFERP (parent) ? BUF_BEG (XBUFFER (parent)) : 0);
847 /* If inserting at point-max of a buffer, that position will be out
848 of range. Remember that buffer positions are 1-based. */
849 if (position >= TOTAL_LENGTH (tree) + offset)
851 position = TOTAL_LENGTH (tree) + offset;
852 eobp = 1;
855 i = find_interval (tree, position);
857 /* If in middle of an interval which is not sticky either way,
858 we must not just give its properties to the insertion.
859 So split this interval at the insertion point.
861 Originally, the if condition here was this:
862 (! (position == i->position || eobp)
863 && END_NONSTICKY_P (i)
864 && FRONT_NONSTICKY_P (i))
865 But, these macros are now unreliable because of introduction of
866 Vtext_property_default_nonsticky. So, we always check properties
867 one by one if POSITION is in middle of an interval. */
868 if (! (position == i->position || eobp))
870 Lisp_Object tail;
871 Lisp_Object front, rear;
873 tail = i->plist;
875 /* Properties font-sticky and rear-nonsticky override
876 Vtext_property_default_nonsticky. So, if they are t, we can
877 skip one by one checking of properties. */
878 rear = textget (i->plist, Qrear_nonsticky);
879 if (! CONSP (rear) && ! NILP (rear))
881 /* All properties are nonsticky. We split the interval. */
882 goto check_done;
884 front = textget (i->plist, Qfront_sticky);
885 if (! CONSP (front) && ! NILP (front))
887 /* All properties are sticky. We don't split the interval. */
888 tail = Qnil;
889 goto check_done;
892 /* Does any actual property pose an actual problem? We break
893 the loop if we find a nonsticky property. */
894 for (; CONSP (tail); tail = Fcdr (XCDR (tail)))
896 Lisp_Object prop, tmp;
897 prop = XCAR (tail);
899 /* Is this particular property front-sticky? */
900 if (CONSP (front) && ! NILP (Fmemq (prop, front)))
901 continue;
903 /* Is this particular property rear-nonsticky? */
904 if (CONSP (rear) && ! NILP (Fmemq (prop, rear)))
905 break;
907 /* Is this particular property recorded as sticky or
908 nonsticky in Vtext_property_default_nonsticky? */
909 tmp = Fassq (prop, Vtext_property_default_nonsticky);
910 if (CONSP (tmp))
912 if (NILP (tmp))
913 continue;
914 break;
917 /* By default, a text property is rear-sticky, thus we
918 continue the loop. */
921 check_done:
922 /* If any property is a real problem, split the interval. */
923 if (! NILP (tail))
925 temp = split_interval_right (i, position - i->position);
926 copy_properties (i, temp);
927 i = temp;
931 /* If we are positioned between intervals, check the stickiness of
932 both of them. We have to do this too, if we are at BEG or Z. */
933 if (position == i->position || eobp)
935 register INTERVAL prev;
937 if (position == BEG)
938 prev = 0;
939 else if (eobp)
941 prev = i;
942 i = 0;
944 else
945 prev = previous_interval (i);
947 /* Even if we are positioned between intervals, we default
948 to the left one if it exists. We extend it now and split
949 off a part later, if stickiness demands it. */
950 for (temp = prev ? prev : i; temp; temp = INTERVAL_PARENT_OR_NULL (temp))
952 temp->total_length += length;
953 eassert (TOTAL_LENGTH (temp) >= 0);
954 temp = balance_possible_root_interval (temp);
957 /* If at least one interval has sticky properties,
958 we check the stickiness property by property.
960 Originally, the if condition here was this:
961 (END_NONSTICKY_P (prev) || FRONT_STICKY_P (i))
962 But, these macros are now unreliable because of introduction
963 of Vtext_property_default_nonsticky. So, we always have to
964 check stickiness of properties one by one. If cache of
965 stickiness is implemented in the future, we may be able to
966 use those macros again. */
967 if (1)
969 Lisp_Object pleft, pright;
970 struct interval newi;
972 RESET_INTERVAL (&newi);
973 pleft = prev ? prev->plist : Qnil;
974 pright = i ? i->plist : Qnil;
975 set_interval_plist (&newi, merge_properties_sticky (pleft, pright));
977 if (! prev) /* i.e. position == BEG */
979 if (! intervals_equal (i, &newi))
981 i = split_interval_left (i, length);
982 set_interval_plist (i, newi.plist);
985 else if (! intervals_equal (prev, &newi))
987 prev = split_interval_right (prev, position - prev->position);
988 set_interval_plist (prev, newi.plist);
989 if (i && intervals_equal (prev, i))
990 merge_interval_right (prev);
993 /* We will need to update the cache here later. */
995 else if (! prev && ! NILP (i->plist))
997 /* Just split off a new interval at the left.
998 Since I wasn't front-sticky, the empty plist is ok. */
999 i = split_interval_left (i, length);
1003 /* Otherwise just extend the interval. */
1004 else
1006 for (temp = i; temp; temp = INTERVAL_PARENT_OR_NULL (temp))
1008 temp->total_length += length;
1009 eassert (TOTAL_LENGTH (temp) >= 0);
1010 temp = balance_possible_root_interval (temp);
1014 return tree;
1017 /* Any property might be front-sticky on the left, rear-sticky on the left,
1018 front-sticky on the right, or rear-sticky on the right; the 16 combinations
1019 can be arranged in a matrix with rows denoting the left conditions and
1020 columns denoting the right conditions:
1021 _ __ _
1022 _ FR FR FR FR
1023 FR__ 0 1 2 3
1024 _FR 4 5 6 7
1025 FR 8 9 A B
1026 FR C D E F
1028 left-props = '(front-sticky (p8 p9 pa pb pc pd pe pf)
1029 rear-nonsticky (p4 p5 p6 p7 p8 p9 pa pb)
1030 p0 L p1 L p2 L p3 L p4 L p5 L p6 L p7 L
1031 p8 L p9 L pa L pb L pc L pd L pe L pf L)
1032 right-props = '(front-sticky (p2 p3 p6 p7 pa pb pe pf)
1033 rear-nonsticky (p1 p2 p5 p6 p9 pa pd pe)
1034 p0 R p1 R p2 R p3 R p4 R p5 R p6 R p7 R
1035 p8 R p9 R pa R pb R pc R pd R pe R pf R)
1037 We inherit from whoever has a sticky side facing us. If both sides
1038 do (cases 2, 3, E, and F), then we inherit from whichever side has a
1039 non-nil value for the current property. If both sides do, then we take
1040 from the left.
1042 When we inherit a property, we get its stickiness as well as its value.
1043 So, when we merge the above two lists, we expect to get this:
1045 result = '(front-sticky (p6 p7 pa pb pc pd pe pf)
1046 rear-nonsticky (p6 pa)
1047 p0 L p1 L p2 L p3 L p6 R p7 R
1048 pa R pb R pc L pd L pe L pf L)
1050 The optimizable special cases are:
1051 left rear-nonsticky = nil, right front-sticky = nil (inherit left)
1052 left rear-nonsticky = t, right front-sticky = t (inherit right)
1053 left rear-nonsticky = t, right front-sticky = nil (inherit none)
1056 static Lisp_Object
1057 merge_properties_sticky (Lisp_Object pleft, Lisp_Object pright)
1059 Lisp_Object props, front, rear;
1060 Lisp_Object lfront, lrear, rfront, rrear;
1061 Lisp_Object tail1, tail2, sym, lval, rval, cat;
1062 bool use_left, use_right, lpresent;
1064 props = Qnil;
1065 front = Qnil;
1066 rear = Qnil;
1067 lfront = textget (pleft, Qfront_sticky);
1068 lrear = textget (pleft, Qrear_nonsticky);
1069 rfront = textget (pright, Qfront_sticky);
1070 rrear = textget (pright, Qrear_nonsticky);
1072 /* Go through each element of PRIGHT. */
1073 for (tail1 = pright; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
1075 Lisp_Object tmp;
1077 sym = XCAR (tail1);
1079 /* Sticky properties get special treatment. */
1080 if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky))
1081 continue;
1083 rval = Fcar (XCDR (tail1));
1084 for (tail2 = pleft; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
1085 if (EQ (sym, XCAR (tail2)))
1086 break;
1088 /* Indicate whether the property is explicitly defined on the left.
1089 (We know it is defined explicitly on the right
1090 because otherwise we don't get here.) */
1091 lpresent = ! NILP (tail2);
1092 lval = (NILP (tail2) ? Qnil : Fcar (Fcdr (tail2)));
1094 /* Even if lrear or rfront say nothing about the stickiness of
1095 SYM, Vtext_property_default_nonsticky may give default
1096 stickiness to SYM. */
1097 tmp = Fassq (sym, Vtext_property_default_nonsticky);
1098 use_left = (lpresent
1099 && ! (TMEM (sym, lrear)
1100 || (CONSP (tmp) && ! NILP (XCDR (tmp)))));
1101 use_right = (TMEM (sym, rfront)
1102 || (CONSP (tmp) && NILP (XCDR (tmp))));
1103 if (use_left && use_right)
1105 if (NILP (lval))
1106 use_left = 0;
1107 else if (NILP (rval))
1108 use_right = 0;
1110 if (use_left)
1112 /* We build props as (value sym ...) rather than (sym value ...)
1113 because we plan to nreverse it when we're done. */
1114 props = Fcons (lval, Fcons (sym, props));
1115 if (TMEM (sym, lfront))
1116 front = Fcons (sym, front);
1117 if (TMEM (sym, lrear))
1118 rear = Fcons (sym, rear);
1120 else if (use_right)
1122 props = Fcons (rval, Fcons (sym, props));
1123 if (TMEM (sym, rfront))
1124 front = Fcons (sym, front);
1125 if (TMEM (sym, rrear))
1126 rear = Fcons (sym, rear);
1130 /* Now go through each element of PLEFT. */
1131 for (tail2 = pleft; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
1133 Lisp_Object tmp;
1135 sym = XCAR (tail2);
1137 /* Sticky properties get special treatment. */
1138 if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky))
1139 continue;
1141 /* If sym is in PRIGHT, we've already considered it. */
1142 for (tail1 = pright; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
1143 if (EQ (sym, XCAR (tail1)))
1144 break;
1145 if (! NILP (tail1))
1146 continue;
1148 lval = Fcar (XCDR (tail2));
1150 /* Even if lrear or rfront say nothing about the stickiness of
1151 SYM, Vtext_property_default_nonsticky may give default
1152 stickiness to SYM. */
1153 tmp = Fassq (sym, Vtext_property_default_nonsticky);
1155 /* Since rval is known to be nil in this loop, the test simplifies. */
1156 if (! (TMEM (sym, lrear) || (CONSP (tmp) && ! NILP (XCDR (tmp)))))
1158 props = Fcons (lval, Fcons (sym, props));
1159 if (TMEM (sym, lfront))
1160 front = Fcons (sym, front);
1162 else if (TMEM (sym, rfront) || (CONSP (tmp) && NILP (XCDR (tmp))))
1164 /* The value is nil, but we still inherit the stickiness
1165 from the right. */
1166 front = Fcons (sym, front);
1167 if (TMEM (sym, rrear))
1168 rear = Fcons (sym, rear);
1171 props = Fnreverse (props);
1172 if (! NILP (rear))
1173 props = Fcons (Qrear_nonsticky, Fcons (Fnreverse (rear), props));
1175 cat = textget (props, Qcategory);
1176 if (! NILP (front)
1178 /* If we have inherited a front-stick category property that is t,
1179 we don't need to set up a detailed one. */
1180 ! (! NILP (cat) && SYMBOLP (cat)
1181 && EQ (Fget (cat, Qfront_sticky), Qt)))
1182 props = Fcons (Qfront_sticky, Fcons (Fnreverse (front), props));
1183 return props;
1187 /* Delete a node I from its interval tree by merging its subtrees
1188 into one subtree which is then returned. Caller is responsible for
1189 storing the resulting subtree into its parent. */
1191 static INTERVAL
1192 delete_node (register INTERVAL i)
1194 register INTERVAL migrate, this;
1195 register ptrdiff_t migrate_amt;
1197 if (!i->left)
1198 return i->right;
1199 if (!i->right)
1200 return i->left;
1202 migrate = i->left;
1203 migrate_amt = i->left->total_length;
1204 this = i->right;
1205 this->total_length += migrate_amt;
1206 while (this->left)
1208 this = this->left;
1209 this->total_length += migrate_amt;
1211 eassert (TOTAL_LENGTH (this) >= 0);
1212 set_interval_left (this, migrate);
1213 set_interval_parent (migrate, this);
1215 return i->right;
1218 /* Delete interval I from its tree by calling `delete_node'
1219 and properly connecting the resultant subtree.
1221 I is presumed to be empty; that is, no adjustments are made
1222 for the length of I. */
1224 static void
1225 delete_interval (register INTERVAL i)
1227 register INTERVAL parent;
1228 ptrdiff_t amt = LENGTH (i);
1230 eassert (amt == 0); /* Only used on zero-length intervals now. */
1232 if (ROOT_INTERVAL_P (i))
1234 Lisp_Object owner;
1235 GET_INTERVAL_OBJECT (owner, i);
1236 parent = delete_node (i);
1237 if (parent)
1238 set_interval_object (parent, owner);
1240 if (BUFFERP (owner))
1241 set_buffer_intervals (XBUFFER (owner), parent);
1242 else if (STRINGP (owner))
1243 set_string_intervals (owner, parent);
1244 else
1245 emacs_abort ();
1247 return;
1250 parent = INTERVAL_PARENT (i);
1251 if (AM_LEFT_CHILD (i))
1253 set_interval_left (parent, delete_node (i));
1254 if (parent->left)
1255 set_interval_parent (parent->left, parent);
1257 else
1259 set_interval_right (parent, delete_node (i));
1260 if (parent->right)
1261 set_interval_parent (parent->right, parent);
1265 /* Find the interval in TREE corresponding to the relative position
1266 FROM and delete as much as possible of AMOUNT from that interval.
1267 Return the amount actually deleted, and if the interval was
1268 zeroed-out, delete that interval node from the tree.
1270 Note that FROM is actually origin zero, aka relative to the
1271 leftmost edge of tree. This is appropriate since we call ourselves
1272 recursively on subtrees.
1274 Do this by recursing down TREE to the interval in question, and
1275 deleting the appropriate amount of text. */
1277 static ptrdiff_t
1278 interval_deletion_adjustment (register INTERVAL tree, register ptrdiff_t from,
1279 register ptrdiff_t amount)
1281 register ptrdiff_t relative_position = from;
1283 if (!tree)
1284 return 0;
1286 /* Left branch. */
1287 if (relative_position < LEFT_TOTAL_LENGTH (tree))
1289 ptrdiff_t subtract = interval_deletion_adjustment (tree->left,
1290 relative_position,
1291 amount);
1292 tree->total_length -= subtract;
1293 eassert (TOTAL_LENGTH (tree) >= 0);
1294 return subtract;
1296 /* Right branch. */
1297 else if (relative_position >= (TOTAL_LENGTH (tree)
1298 - RIGHT_TOTAL_LENGTH (tree)))
1300 ptrdiff_t subtract;
1302 relative_position -= (tree->total_length
1303 - RIGHT_TOTAL_LENGTH (tree));
1304 subtract = interval_deletion_adjustment (tree->right,
1305 relative_position,
1306 amount);
1307 tree->total_length -= subtract;
1308 eassert (TOTAL_LENGTH (tree) >= 0);
1309 return subtract;
1311 /* Here -- this node. */
1312 else
1314 /* How much can we delete from this interval? */
1315 ptrdiff_t my_amount = ((tree->total_length
1316 - RIGHT_TOTAL_LENGTH (tree))
1317 - relative_position);
1319 if (amount > my_amount)
1320 amount = my_amount;
1322 tree->total_length -= amount;
1323 eassert (TOTAL_LENGTH (tree) >= 0);
1324 if (LENGTH (tree) == 0)
1325 delete_interval (tree);
1327 return amount;
1330 /* Never reach here. */
1333 /* Effect the adjustments necessary to the interval tree of BUFFER to
1334 correspond to the deletion of LENGTH characters from that buffer
1335 text. The deletion is effected at position START (which is a
1336 buffer position, i.e. origin 1). */
1338 static void
1339 adjust_intervals_for_deletion (struct buffer *buffer,
1340 ptrdiff_t start, ptrdiff_t length)
1342 ptrdiff_t left_to_delete = length;
1343 INTERVAL tree = buffer_intervals (buffer);
1344 Lisp_Object parent;
1345 ptrdiff_t offset;
1347 GET_INTERVAL_OBJECT (parent, tree);
1348 offset = (BUFFERP (parent) ? BUF_BEG (XBUFFER (parent)) : 0);
1350 if (!tree)
1351 return;
1353 eassert (start <= offset + TOTAL_LENGTH (tree)
1354 && start + length <= offset + TOTAL_LENGTH (tree));
1356 if (length == TOTAL_LENGTH (tree))
1358 set_buffer_intervals (buffer, NULL);
1359 return;
1362 if (ONLY_INTERVAL_P (tree))
1364 tree->total_length -= length;
1365 eassert (TOTAL_LENGTH (tree) >= 0);
1366 return;
1369 if (start > offset + TOTAL_LENGTH (tree))
1370 start = offset + TOTAL_LENGTH (tree);
1371 while (left_to_delete > 0)
1373 left_to_delete -= interval_deletion_adjustment (tree, start - offset,
1374 left_to_delete);
1375 tree = buffer_intervals (buffer);
1376 if (left_to_delete == tree->total_length)
1378 set_buffer_intervals (buffer, NULL);
1379 return;
1384 /* Make the adjustments necessary to the interval tree of BUFFER to
1385 represent an addition or deletion of LENGTH characters starting
1386 at position START. Addition or deletion is indicated by the sign
1387 of LENGTH. */
1389 void
1390 offset_intervals (struct buffer *buffer, ptrdiff_t start, ptrdiff_t length)
1392 if (!buffer_intervals (buffer) || length == 0)
1393 return;
1395 if (length > 0)
1396 adjust_intervals_for_insertion (buffer_intervals (buffer),
1397 start, length);
1398 else
1399 adjust_intervals_for_deletion (buffer, start, -length);
1402 /* Merge interval I with its lexicographic successor. The resulting
1403 interval is returned, and has the properties of the original
1404 successor. The properties of I are lost. I is removed from the
1405 interval tree.
1407 IMPORTANT:
1408 The caller must verify that this is not the last (rightmost)
1409 interval. */
1411 static INTERVAL
1412 merge_interval_right (register INTERVAL i)
1414 register ptrdiff_t absorb = LENGTH (i);
1415 register INTERVAL successor;
1417 /* Find the succeeding interval. */
1418 if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb
1419 as we descend. */
1421 successor = i->right;
1422 while (! NULL_LEFT_CHILD (successor))
1424 successor->total_length += absorb;
1425 eassert (TOTAL_LENGTH (successor) >= 0);
1426 successor = successor->left;
1429 successor->total_length += absorb;
1430 eassert (TOTAL_LENGTH (successor) >= 0);
1431 delete_interval (i);
1432 return successor;
1435 /* Zero out this interval. */
1436 i->total_length -= absorb;
1437 eassert (TOTAL_LENGTH (i) >= 0);
1439 successor = i;
1440 while (! NULL_PARENT (successor)) /* It's above us. Subtract as
1441 we ascend. */
1443 if (AM_LEFT_CHILD (successor))
1445 successor = INTERVAL_PARENT (successor);
1446 delete_interval (i);
1447 return successor;
1450 successor = INTERVAL_PARENT (successor);
1451 successor->total_length -= absorb;
1452 eassert (TOTAL_LENGTH (successor) >= 0);
1455 /* This must be the rightmost or last interval and cannot
1456 be merged right. The caller should have known. */
1457 emacs_abort ();
1460 /* Merge interval I with its lexicographic predecessor. The resulting
1461 interval is returned, and has the properties of the original predecessor.
1462 The properties of I are lost. Interval node I is removed from the tree.
1464 IMPORTANT:
1465 The caller must verify that this is not the first (leftmost) interval. */
1467 INTERVAL
1468 merge_interval_left (register INTERVAL i)
1470 register ptrdiff_t absorb = LENGTH (i);
1471 register INTERVAL predecessor;
1473 /* Find the preceding interval. */
1474 if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down,
1475 adding ABSORB as we go. */
1477 predecessor = i->left;
1478 while (! NULL_RIGHT_CHILD (predecessor))
1480 predecessor->total_length += absorb;
1481 eassert (TOTAL_LENGTH (predecessor) >= 0);
1482 predecessor = predecessor->right;
1485 predecessor->total_length += absorb;
1486 eassert (TOTAL_LENGTH (predecessor) >= 0);
1487 delete_interval (i);
1488 return predecessor;
1491 /* Zero out this interval. */
1492 i->total_length -= absorb;
1493 eassert (TOTAL_LENGTH (i) >= 0);
1495 predecessor = i;
1496 while (! NULL_PARENT (predecessor)) /* It's above us. Go up,
1497 subtracting ABSORB. */
1499 if (AM_RIGHT_CHILD (predecessor))
1501 predecessor = INTERVAL_PARENT (predecessor);
1502 delete_interval (i);
1503 return predecessor;
1506 predecessor = INTERVAL_PARENT (predecessor);
1507 predecessor->total_length -= absorb;
1508 eassert (TOTAL_LENGTH (predecessor) >= 0);
1511 /* This must be the leftmost or first interval and cannot
1512 be merged left. The caller should have known. */
1513 emacs_abort ();
1516 /* Create a copy of SOURCE but with the default value of UP. */
1518 static INTERVAL
1519 reproduce_interval (INTERVAL source)
1521 register INTERVAL target = make_interval ();
1523 target->total_length = source->total_length;
1524 target->position = source->position;
1526 copy_properties (source, target);
1528 if (! NULL_LEFT_CHILD (source))
1529 set_interval_left (target, reproduce_tree (source->left, target));
1530 if (! NULL_RIGHT_CHILD (source))
1531 set_interval_right (target, reproduce_tree (source->right, target));
1533 return target;
1536 /* Make an exact copy of interval tree SOURCE which descends from
1537 PARENT. This is done by recursing through SOURCE, copying
1538 the current interval and its properties, and then adjusting
1539 the pointers of the copy. */
1541 static INTERVAL
1542 reproduce_tree (INTERVAL source, INTERVAL parent)
1544 INTERVAL target = reproduce_interval (source);
1545 set_interval_parent (target, parent);
1546 return target;
1549 static INTERVAL
1550 reproduce_tree_obj (INTERVAL source, Lisp_Object parent)
1552 INTERVAL target = reproduce_interval (source);
1553 set_interval_object (target, parent);
1554 return target;
1557 /* Insert the intervals of SOURCE into BUFFER at POSITION.
1558 LENGTH is the length of the text in SOURCE.
1560 The `position' field of the SOURCE intervals is assumed to be
1561 consistent with its parent; therefore, SOURCE must be an
1562 interval tree made with copy_interval or must be the whole
1563 tree of a buffer or a string.
1565 This is used in insdel.c when inserting Lisp_Strings into the
1566 buffer. The text corresponding to SOURCE is already in the buffer
1567 when this is called. The intervals of new tree are a copy of those
1568 belonging to the string being inserted; intervals are never
1569 shared.
1571 If the inserted text had no intervals associated, and we don't
1572 want to inherit the surrounding text's properties, this function
1573 simply returns -- offset_intervals should handle placing the
1574 text in the correct interval, depending on the sticky bits.
1576 If the inserted text had properties (intervals), then there are two
1577 cases -- either insertion happened in the middle of some interval,
1578 or between two intervals.
1580 If the text goes into the middle of an interval, then new intervals
1581 are created in the middle, and new text has the union of its properties
1582 and those of the text into which it was inserted.
1584 If the text goes between two intervals, then if neither interval
1585 had its appropriate sticky property set (front_sticky, rear_sticky),
1586 the new text has only its properties. If one of the sticky properties
1587 is set, then the new text "sticks" to that region and its properties
1588 depend on merging as above. If both the preceding and succeeding
1589 intervals to the new text are "sticky", then the new text retains
1590 only its properties, as if neither sticky property were set. Perhaps
1591 we should consider merging all three sets of properties onto the new
1592 text... */
1594 void
1595 graft_intervals_into_buffer (INTERVAL source, ptrdiff_t position,
1596 ptrdiff_t length, struct buffer *buffer,
1597 bool inherit)
1599 INTERVAL tree = buffer_intervals (buffer);
1600 INTERVAL under, over, this;
1601 ptrdiff_t over_used;
1603 /* If the new text has no properties, then with inheritance it
1604 becomes part of whatever interval it was inserted into.
1605 To prevent inheritance, we must clear out the properties
1606 of the newly inserted text. */
1607 if (!source)
1609 Lisp_Object buf;
1610 if (!inherit && tree && length > 0)
1612 XSETBUFFER (buf, buffer);
1613 set_text_properties_1 (make_number (position),
1614 make_number (position + length),
1615 Qnil, buf,
1616 find_interval (tree, position));
1618 /* Shouldn't be necessary. --Stef */
1619 buffer_balance_intervals (buffer);
1620 return;
1623 eassert (length == TOTAL_LENGTH (source));
1625 if ((BUF_Z (buffer) - BUF_BEG (buffer)) == length)
1627 /* The inserted text constitutes the whole buffer, so
1628 simply copy over the interval structure. */
1629 Lisp_Object buf;
1631 XSETBUFFER (buf, buffer);
1632 set_buffer_intervals (buffer, reproduce_tree_obj (source, buf));
1633 buffer_intervals (buffer)->position = BUF_BEG (buffer);
1634 eassert (buffer_intervals (buffer)->up_obj == 1);
1635 return;
1637 else if (!tree)
1639 /* Create an interval tree in which to place a copy
1640 of the intervals of the inserted string. */
1641 Lisp_Object buf;
1643 XSETBUFFER (buf, buffer);
1644 tree = create_root_interval (buf);
1646 /* Paranoia -- the text has already been added, so
1647 this buffer should be of non-zero length. */
1648 eassert (TOTAL_LENGTH (tree) > 0);
1650 this = under = find_interval (tree, position);
1651 eassert (under);
1652 over = find_interval (source, interval_start_pos (source));
1654 /* Here for insertion in the middle of an interval.
1655 Split off an equivalent interval to the right,
1656 then don't bother with it any more. */
1658 if (position > under->position)
1660 INTERVAL end_unchanged
1661 = split_interval_left (this, position - under->position);
1662 copy_properties (under, end_unchanged);
1663 under->position = position;
1665 else
1667 /* This call may have some effect because previous_interval may
1668 update `position' fields of intervals. Thus, don't ignore it
1669 for the moment. Someone please tell me the truth (K.Handa). */
1670 INTERVAL prev = previous_interval (under);
1671 (void) prev;
1672 #if 0
1673 /* But, this code surely has no effect. And, anyway,
1674 END_NONSTICKY_P is unreliable now. */
1675 if (prev && !END_NONSTICKY_P (prev))
1676 prev = 0;
1677 #endif /* 0 */
1680 /* Insertion is now at beginning of UNDER. */
1682 /* The inserted text "sticks" to the interval `under',
1683 which means it gets those properties.
1684 The properties of under are the result of
1685 adjust_intervals_for_insertion, so stickiness has
1686 already been taken care of. */
1688 /* OVER is the interval we are copying from next.
1689 OVER_USED says how many characters' worth of OVER
1690 have already been copied into target intervals.
1691 UNDER is the next interval in the target. */
1692 over_used = 0;
1693 while (over)
1695 /* If UNDER is longer than OVER, split it. */
1696 if (LENGTH (over) - over_used < LENGTH (under))
1698 this = split_interval_left (under, LENGTH (over) - over_used);
1699 copy_properties (under, this);
1701 else
1702 this = under;
1704 /* THIS is now the interval to copy or merge into.
1705 OVER covers all of it. */
1706 if (inherit)
1707 merge_properties (over, this);
1708 else
1709 copy_properties (over, this);
1711 /* If THIS and OVER end at the same place,
1712 advance OVER to a new source interval. */
1713 if (LENGTH (this) == LENGTH (over) - over_used)
1715 over = next_interval (over);
1716 over_used = 0;
1718 else
1719 /* Otherwise just record that more of OVER has been used. */
1720 over_used += LENGTH (this);
1722 /* Always advance to a new target interval. */
1723 under = next_interval (this);
1726 buffer_balance_intervals (buffer);
1729 /* Get the value of property PROP from PLIST,
1730 which is the plist of an interval.
1731 We check for direct properties, for categories with property PROP,
1732 and for PROP appearing on the default-text-properties list. */
1734 Lisp_Object
1735 textget (Lisp_Object plist, register Lisp_Object prop)
1737 return lookup_char_property (plist, prop, 1);
1740 Lisp_Object
1741 lookup_char_property (Lisp_Object plist, Lisp_Object prop, bool textprop)
1743 Lisp_Object tail, fallback = Qnil;
1745 for (tail = plist; CONSP (tail); tail = Fcdr (XCDR (tail)))
1747 register Lisp_Object tem;
1748 tem = XCAR (tail);
1749 if (EQ (prop, tem))
1750 return Fcar (XCDR (tail));
1751 if (EQ (tem, Qcategory))
1753 tem = Fcar (XCDR (tail));
1754 if (SYMBOLP (tem))
1755 fallback = Fget (tem, prop);
1759 if (! NILP (fallback))
1760 return fallback;
1761 /* Check for alternative properties */
1762 tail = Fassq (prop, Vchar_property_alias_alist);
1763 if (! NILP (tail))
1765 tail = XCDR (tail);
1766 for (; NILP (fallback) && CONSP (tail); tail = XCDR (tail))
1767 fallback = Fplist_get (plist, XCAR (tail));
1770 if (textprop && NILP (fallback) && CONSP (Vdefault_text_properties))
1771 fallback = Fplist_get (Vdefault_text_properties, prop);
1772 return fallback;
1776 /* Set point in BUFFER "temporarily" to CHARPOS, which corresponds to
1777 byte position BYTEPOS. */
1779 void
1780 temp_set_point_both (struct buffer *buffer,
1781 ptrdiff_t charpos, ptrdiff_t bytepos)
1783 /* In a single-byte buffer, the two positions must be equal. */
1784 eassert (BUF_ZV (buffer) != BUF_ZV_BYTE (buffer) || charpos == bytepos);
1786 eassert (charpos <= bytepos);
1787 eassert (charpos <= BUF_ZV (buffer) || BUF_BEGV (buffer) <= charpos);
1789 SET_BUF_PT_BOTH (buffer, charpos, bytepos);
1792 /* Set point "temporarily", without checking any text properties. */
1794 void
1795 temp_set_point (struct buffer *buffer, ptrdiff_t charpos)
1797 temp_set_point_both (buffer, charpos,
1798 buf_charpos_to_bytepos (buffer, charpos));
1801 /* Set point in BUFFER to CHARPOS. If the target position is
1802 before an intangible character, move to an ok place. */
1804 void
1805 set_point (ptrdiff_t charpos)
1807 set_point_both (charpos, buf_charpos_to_bytepos (current_buffer, charpos));
1810 /* Set PT from MARKER's clipped position. */
1812 void
1813 set_point_from_marker (Lisp_Object marker)
1815 if (XMARKER (marker)->buffer != current_buffer)
1816 signal_error ("Marker points into wrong buffer", marker);
1817 set_point_both
1818 (clip_to_bounds (BEGV, marker_position (marker), ZV),
1819 clip_to_bounds (BEGV_BYTE, marker_byte_position (marker), ZV_BYTE));
1822 /* If there's an invisible character at position POS + TEST_OFFS in the
1823 current buffer, and the invisible property has a `stickiness' such that
1824 inserting a character at position POS would inherit the property it,
1825 return POS + ADJ, otherwise return POS. If TEST_INTANG, intangibility
1826 is required as well as invisibility.
1828 TEST_OFFS should be either 0 or -1, and ADJ should be either 1 or -1.
1830 Note that `stickiness' is determined by overlay marker insertion types,
1831 if the invisible property comes from an overlay. */
1833 static ptrdiff_t
1834 adjust_for_invis_intang (ptrdiff_t pos, ptrdiff_t test_offs, ptrdiff_t adj,
1835 bool test_intang)
1837 Lisp_Object invis_propval, invis_overlay;
1838 Lisp_Object test_pos;
1840 if ((adj < 0 && pos + adj < BEGV) || (adj > 0 && pos + adj > ZV))
1841 /* POS + ADJ would be beyond the buffer bounds, so do no adjustment. */
1842 return pos;
1844 test_pos = make_number (pos + test_offs);
1846 invis_propval
1847 = get_char_property_and_overlay (test_pos, Qinvisible, Qnil,
1848 &invis_overlay);
1850 if ((!test_intang
1851 || ! NILP (Fget_char_property (test_pos, Qintangible, Qnil)))
1852 && TEXT_PROP_MEANS_INVISIBLE (invis_propval)
1853 /* This next test is true if the invisible property has a stickiness
1854 such that an insertion at POS would inherit it. */
1855 && (NILP (invis_overlay)
1856 /* Invisible property is from a text-property. */
1857 ? (text_property_stickiness (Qinvisible, make_number (pos), Qnil)
1858 == (test_offs == 0 ? 1 : -1))
1859 /* Invisible property is from an overlay. */
1860 : (test_offs == 0
1861 ? XMARKER (OVERLAY_START (invis_overlay))->insertion_type == 0
1862 : XMARKER (OVERLAY_END (invis_overlay))->insertion_type == 1)))
1863 pos += adj;
1865 return pos;
1868 /* Set point in BUFFER to CHARPOS, which corresponds to byte
1869 position BYTEPOS. If the target position is
1870 before an intangible character, move to an ok place. */
1872 void
1873 set_point_both (ptrdiff_t charpos, ptrdiff_t bytepos)
1875 register INTERVAL to, from, toprev, fromprev;
1876 ptrdiff_t buffer_point;
1877 ptrdiff_t old_position = PT;
1878 /* This ensures that we move forward past intangible text when the
1879 initial position is the same as the destination, in the rare
1880 instances where this is important, e.g. in line-move-finish
1881 (simple.el). */
1882 bool backwards = charpos < old_position;
1883 bool have_overlays;
1884 ptrdiff_t original_position;
1886 bset_point_before_scroll (current_buffer, Qnil);
1888 if (charpos == PT)
1889 return;
1891 /* In a single-byte buffer, the two positions must be equal. */
1892 eassert (ZV != ZV_BYTE || charpos == bytepos);
1894 /* Check this now, before checking if the buffer has any intervals.
1895 That way, we can catch conditions which break this sanity check
1896 whether or not there are intervals in the buffer. */
1897 eassert (charpos <= ZV && charpos >= BEGV);
1899 have_overlays = buffer_has_overlays ();
1901 /* If we have no text properties and overlays,
1902 then we can do it quickly. */
1903 if (!buffer_intervals (current_buffer) && ! have_overlays)
1905 temp_set_point_both (current_buffer, charpos, bytepos);
1906 return;
1909 /* Set TO to the interval containing the char after CHARPOS,
1910 and TOPREV to the interval containing the char before CHARPOS.
1911 Either one may be null. They may be equal. */
1912 to = find_interval (buffer_intervals (current_buffer), charpos);
1913 if (charpos == BEGV)
1914 toprev = 0;
1915 else if (to && to->position == charpos)
1916 toprev = previous_interval (to);
1917 else
1918 toprev = to;
1920 buffer_point = (PT == ZV ? ZV - 1 : PT);
1922 /* Set FROM to the interval containing the char after PT,
1923 and FROMPREV to the interval containing the char before PT.
1924 Either one may be null. They may be equal. */
1925 /* We could cache this and save time. */
1926 from = find_interval (buffer_intervals (current_buffer), buffer_point);
1927 if (buffer_point == BEGV)
1928 fromprev = 0;
1929 else if (from && from->position == PT)
1930 fromprev = previous_interval (from);
1931 else if (buffer_point != PT)
1932 fromprev = from, from = 0;
1933 else
1934 fromprev = from;
1936 /* Moving within an interval. */
1937 if (to == from && toprev == fromprev && INTERVAL_VISIBLE_P (to)
1938 && ! have_overlays)
1940 temp_set_point_both (current_buffer, charpos, bytepos);
1941 return;
1944 original_position = charpos;
1946 /* If the new position is between two intangible characters
1947 with the same intangible property value,
1948 move forward or backward until a change in that property. */
1949 if (NILP (Vinhibit_point_motion_hooks)
1950 && ((to && toprev)
1951 || have_overlays)
1952 /* Intangibility never stops us from positioning at the beginning
1953 or end of the buffer, so don't bother checking in that case. */
1954 && charpos != BEGV && charpos != ZV)
1956 Lisp_Object pos;
1957 Lisp_Object intangible_propval;
1959 if (backwards)
1961 /* If the preceding character is both intangible and invisible,
1962 and the invisible property is `rear-sticky', perturb it so
1963 that the search starts one character earlier -- this ensures
1964 that point can never move to the end of an invisible/
1965 intangible/rear-sticky region. */
1966 charpos = adjust_for_invis_intang (charpos, -1, -1, 1);
1968 XSETINT (pos, charpos);
1970 /* If following char is intangible,
1971 skip back over all chars with matching intangible property. */
1973 intangible_propval = Fget_char_property (pos, Qintangible, Qnil);
1975 if (! NILP (intangible_propval))
1977 while (XINT (pos) > BEGV
1978 && EQ (Fget_char_property (make_number (XINT (pos) - 1),
1979 Qintangible, Qnil),
1980 intangible_propval))
1981 pos = Fprevious_char_property_change (pos, Qnil);
1983 /* Set CHARPOS from POS, and if the final intangible character
1984 that we skipped over is also invisible, and the invisible
1985 property is `front-sticky', perturb it to be one character
1986 earlier -- this ensures that point can never move to the
1987 beginning of an invisible/intangible/front-sticky region. */
1988 charpos = adjust_for_invis_intang (XINT (pos), 0, -1, 0);
1991 else
1993 /* If the following character is both intangible and invisible,
1994 and the invisible property is `front-sticky', perturb it so
1995 that the search starts one character later -- this ensures
1996 that point can never move to the beginning of an
1997 invisible/intangible/front-sticky region. */
1998 charpos = adjust_for_invis_intang (charpos, 0, 1, 1);
2000 XSETINT (pos, charpos);
2002 /* If preceding char is intangible,
2003 skip forward over all chars with matching intangible property. */
2005 intangible_propval = Fget_char_property (make_number (charpos - 1),
2006 Qintangible, Qnil);
2008 if (! NILP (intangible_propval))
2010 while (XINT (pos) < ZV
2011 && EQ (Fget_char_property (pos, Qintangible, Qnil),
2012 intangible_propval))
2013 pos = Fnext_char_property_change (pos, Qnil);
2015 /* Set CHARPOS from POS, and if the final intangible character
2016 that we skipped over is also invisible, and the invisible
2017 property is `rear-sticky', perturb it to be one character
2018 later -- this ensures that point can never move to the
2019 end of an invisible/intangible/rear-sticky region. */
2020 charpos = adjust_for_invis_intang (XINT (pos), -1, 1, 0);
2024 bytepos = buf_charpos_to_bytepos (current_buffer, charpos);
2027 if (charpos != original_position)
2029 /* Set TO to the interval containing the char after CHARPOS,
2030 and TOPREV to the interval containing the char before CHARPOS.
2031 Either one may be null. They may be equal. */
2032 to = find_interval (buffer_intervals (current_buffer), charpos);
2033 if (charpos == BEGV)
2034 toprev = 0;
2035 else if (to && to->position == charpos)
2036 toprev = previous_interval (to);
2037 else
2038 toprev = to;
2041 /* Here TO is the interval after the stopping point
2042 and TOPREV is the interval before the stopping point.
2043 One or the other may be null. */
2045 temp_set_point_both (current_buffer, charpos, bytepos);
2047 /* We run point-left and point-entered hooks here, if the
2048 two intervals are not equivalent. These hooks take
2049 (old_point, new_point) as arguments. */
2050 if (NILP (Vinhibit_point_motion_hooks)
2051 && (! intervals_equal (from, to)
2052 || ! intervals_equal (fromprev, toprev)))
2054 Lisp_Object leave_after, leave_before, enter_after, enter_before;
2056 if (fromprev)
2057 leave_before = textget (fromprev->plist, Qpoint_left);
2058 else
2059 leave_before = Qnil;
2061 if (from)
2062 leave_after = textget (from->plist, Qpoint_left);
2063 else
2064 leave_after = Qnil;
2066 if (toprev)
2067 enter_before = textget (toprev->plist, Qpoint_entered);
2068 else
2069 enter_before = Qnil;
2071 if (to)
2072 enter_after = textget (to->plist, Qpoint_entered);
2073 else
2074 enter_after = Qnil;
2076 if (! EQ (leave_before, enter_before) && !NILP (leave_before))
2077 call2 (leave_before, make_number (old_position),
2078 make_number (charpos));
2079 if (! EQ (leave_after, enter_after) && !NILP (leave_after))
2080 call2 (leave_after, make_number (old_position),
2081 make_number (charpos));
2083 if (! EQ (enter_before, leave_before) && !NILP (enter_before))
2084 call2 (enter_before, make_number (old_position),
2085 make_number (charpos));
2086 if (! EQ (enter_after, leave_after) && !NILP (enter_after))
2087 call2 (enter_after, make_number (old_position),
2088 make_number (charpos));
2092 /* Move point to POSITION, unless POSITION is inside an intangible
2093 segment that reaches all the way to point. */
2095 void
2096 move_if_not_intangible (ptrdiff_t position)
2098 Lisp_Object pos;
2099 Lisp_Object intangible_propval;
2101 XSETINT (pos, position);
2103 if (! NILP (Vinhibit_point_motion_hooks))
2104 /* If intangible is inhibited, always move point to POSITION. */
2106 else if (PT < position && XINT (pos) < ZV)
2108 /* We want to move forward, so check the text before POSITION. */
2110 intangible_propval = Fget_char_property (pos,
2111 Qintangible, Qnil);
2113 /* If following char is intangible,
2114 skip back over all chars with matching intangible property. */
2115 if (! NILP (intangible_propval))
2116 while (XINT (pos) > BEGV
2117 && EQ (Fget_char_property (make_number (XINT (pos) - 1),
2118 Qintangible, Qnil),
2119 intangible_propval))
2120 pos = Fprevious_char_property_change (pos, Qnil);
2122 else if (XINT (pos) > BEGV)
2124 /* We want to move backward, so check the text after POSITION. */
2126 intangible_propval = Fget_char_property (make_number (XINT (pos) - 1),
2127 Qintangible, Qnil);
2129 /* If following char is intangible,
2130 skip forward over all chars with matching intangible property. */
2131 if (! NILP (intangible_propval))
2132 while (XINT (pos) < ZV
2133 && EQ (Fget_char_property (pos, Qintangible, Qnil),
2134 intangible_propval))
2135 pos = Fnext_char_property_change (pos, Qnil);
2138 else if (position < BEGV)
2139 position = BEGV;
2140 else if (position > ZV)
2141 position = ZV;
2143 /* If the whole stretch between PT and POSITION isn't intangible,
2144 try moving to POSITION (which means we actually move farther
2145 if POSITION is inside of intangible text). */
2147 if (XINT (pos) != PT)
2148 SET_PT (position);
2151 /* If text at position POS has property PROP, set *VAL to the property
2152 value, *START and *END to the beginning and end of a region that
2153 has the same property, and return true. Otherwise return false.
2155 OBJECT is the string or buffer to look for the property in;
2156 nil means the current buffer. */
2158 bool
2159 get_property_and_range (ptrdiff_t pos, Lisp_Object prop, Lisp_Object *val,
2160 ptrdiff_t *start, ptrdiff_t *end, Lisp_Object object)
2162 INTERVAL i, prev, next;
2164 if (NILP (object))
2165 i = find_interval (buffer_intervals (current_buffer), pos);
2166 else if (BUFFERP (object))
2167 i = find_interval (buffer_intervals (XBUFFER (object)), pos);
2168 else if (STRINGP (object))
2169 i = find_interval (string_intervals (object), pos);
2170 else
2171 emacs_abort ();
2173 if (!i || (i->position + LENGTH (i) <= pos))
2174 return 0;
2175 *val = textget (i->plist, prop);
2176 if (NILP (*val))
2177 return 0;
2179 next = i; /* remember it in advance */
2180 prev = previous_interval (i);
2181 while (prev
2182 && EQ (*val, textget (prev->plist, prop)))
2183 i = prev, prev = previous_interval (prev);
2184 *start = i->position;
2186 next = next_interval (i);
2187 while (next && EQ (*val, textget (next->plist, prop)))
2188 i = next, next = next_interval (next);
2189 *end = i->position + LENGTH (i);
2191 return 1;
2194 /* Return the proper local keymap TYPE for position POSITION in
2195 BUFFER; TYPE should be one of `keymap' or `local-map'. Use the map
2196 specified by the PROP property, if any. Otherwise, if TYPE is
2197 `local-map' use BUFFER's local map. */
2199 Lisp_Object
2200 get_local_map (ptrdiff_t position, struct buffer *buffer, Lisp_Object type)
2202 Lisp_Object prop, lispy_position, lispy_buffer;
2203 ptrdiff_t old_begv, old_zv, old_begv_byte, old_zv_byte;
2205 position = clip_to_bounds (BUF_BEGV (buffer), position, BUF_ZV (buffer));
2207 /* Ignore narrowing, so that a local map continues to be valid even if
2208 the visible region contains no characters and hence no properties. */
2209 old_begv = BUF_BEGV (buffer);
2210 old_zv = BUF_ZV (buffer);
2211 old_begv_byte = BUF_BEGV_BYTE (buffer);
2212 old_zv_byte = BUF_ZV_BYTE (buffer);
2214 SET_BUF_BEGV_BOTH (buffer, BUF_BEG (buffer), BUF_BEG_BYTE (buffer));
2215 SET_BUF_ZV_BOTH (buffer, BUF_Z (buffer), BUF_Z_BYTE (buffer));
2217 XSETFASTINT (lispy_position, position);
2218 XSETBUFFER (lispy_buffer, buffer);
2219 /* First check if the CHAR has any property. This is because when
2220 we click with the mouse, the mouse pointer is really pointing
2221 to the CHAR after POS. */
2222 prop = Fget_char_property (lispy_position, type, lispy_buffer);
2223 /* If not, look at the POS's properties. This is necessary because when
2224 editing a field with a `local-map' property, we want insertion at the end
2225 to obey the `local-map' property. */
2226 if (NILP (prop))
2227 prop = Fget_pos_property (lispy_position, type, lispy_buffer);
2229 SET_BUF_BEGV_BOTH (buffer, old_begv, old_begv_byte);
2230 SET_BUF_ZV_BOTH (buffer, old_zv, old_zv_byte);
2232 /* Use the local map only if it is valid. */
2233 prop = get_keymap (prop, 0, 0);
2234 if (CONSP (prop))
2235 return prop;
2237 if (EQ (type, Qkeymap))
2238 return Qnil;
2239 else
2240 return BVAR (buffer, keymap);
2243 /* Produce an interval tree reflecting the intervals in
2244 TREE from START to START + LENGTH.
2245 The new interval tree has no parent and has a starting-position of 0. */
2247 INTERVAL
2248 copy_intervals (INTERVAL tree, ptrdiff_t start, ptrdiff_t length)
2250 register INTERVAL i, new, t;
2251 register ptrdiff_t got, prevlen;
2253 if (!tree || length <= 0)
2254 return NULL;
2256 i = find_interval (tree, start);
2257 eassert (i && LENGTH (i) > 0);
2259 /* If there is only one interval and it's the default, return nil. */
2260 if ((start - i->position + 1 + length) < LENGTH (i)
2261 && DEFAULT_INTERVAL_P (i))
2262 return NULL;
2264 new = make_interval ();
2265 new->position = 0;
2266 got = (LENGTH (i) - (start - i->position));
2267 new->total_length = length;
2268 eassert (TOTAL_LENGTH (new) >= 0);
2269 copy_properties (i, new);
2271 t = new;
2272 prevlen = got;
2273 while (got < length)
2275 i = next_interval (i);
2276 t = split_interval_right (t, prevlen);
2277 copy_properties (i, t);
2278 prevlen = LENGTH (i);
2279 got += prevlen;
2282 return balance_an_interval (new);
2285 /* Give STRING the properties of BUFFER from POSITION to LENGTH. */
2287 void
2288 copy_intervals_to_string (Lisp_Object string, struct buffer *buffer,
2289 ptrdiff_t position, ptrdiff_t length)
2291 INTERVAL interval_copy = copy_intervals (buffer_intervals (buffer),
2292 position, length);
2293 if (!interval_copy)
2294 return;
2296 set_interval_object (interval_copy, string);
2297 set_string_intervals (string, interval_copy);
2300 /* Return true if strings S1 and S2 have identical properties.
2301 Assume they have identical characters. */
2303 bool
2304 compare_string_intervals (Lisp_Object s1, Lisp_Object s2)
2306 INTERVAL i1, i2;
2307 ptrdiff_t pos = 0;
2308 ptrdiff_t end = SCHARS (s1);
2310 i1 = find_interval (string_intervals (s1), 0);
2311 i2 = find_interval (string_intervals (s2), 0);
2313 while (pos < end)
2315 /* Determine how far we can go before we reach the end of I1 or I2. */
2316 ptrdiff_t len1 = (i1 != 0 ? INTERVAL_LAST_POS (i1) : end) - pos;
2317 ptrdiff_t len2 = (i2 != 0 ? INTERVAL_LAST_POS (i2) : end) - pos;
2318 ptrdiff_t distance = min (len1, len2);
2320 /* If we ever find a mismatch between the strings,
2321 they differ. */
2322 if (! intervals_equal (i1, i2))
2323 return 0;
2325 /* Advance POS till the end of the shorter interval,
2326 and advance one or both interval pointers for the new position. */
2327 pos += distance;
2328 if (len1 == distance)
2329 i1 = next_interval (i1);
2330 if (len2 == distance)
2331 i2 = next_interval (i2);
2333 return 1;
2336 /* Recursively adjust interval I in the current buffer
2337 for setting enable_multibyte_characters to MULTI_FLAG.
2338 The range of interval I is START ... END in characters,
2339 START_BYTE ... END_BYTE in bytes. */
2341 static void
2342 set_intervals_multibyte_1 (INTERVAL i, bool multi_flag,
2343 ptrdiff_t start, ptrdiff_t start_byte,
2344 ptrdiff_t end, ptrdiff_t end_byte)
2346 /* Fix the length of this interval. */
2347 if (multi_flag)
2348 i->total_length = end - start;
2349 else
2350 i->total_length = end_byte - start_byte;
2351 eassert (TOTAL_LENGTH (i) >= 0);
2353 if (TOTAL_LENGTH (i) == 0)
2355 delete_interval (i);
2356 return;
2359 /* Recursively fix the length of the subintervals. */
2360 if (i->left)
2362 ptrdiff_t left_end, left_end_byte;
2364 if (multi_flag)
2366 ptrdiff_t temp;
2367 left_end_byte = start_byte + LEFT_TOTAL_LENGTH (i);
2368 left_end = BYTE_TO_CHAR (left_end_byte);
2370 temp = CHAR_TO_BYTE (left_end);
2372 /* If LEFT_END_BYTE is in the middle of a character,
2373 adjust it and LEFT_END to a char boundary. */
2374 if (left_end_byte > temp)
2376 left_end_byte = temp;
2378 if (left_end_byte < temp)
2380 left_end--;
2381 left_end_byte = CHAR_TO_BYTE (left_end);
2384 else
2386 left_end = start + LEFT_TOTAL_LENGTH (i);
2387 left_end_byte = CHAR_TO_BYTE (left_end);
2390 set_intervals_multibyte_1 (i->left, multi_flag, start, start_byte,
2391 left_end, left_end_byte);
2393 if (i->right)
2395 ptrdiff_t right_start_byte, right_start;
2397 if (multi_flag)
2399 ptrdiff_t temp;
2401 right_start_byte = end_byte - RIGHT_TOTAL_LENGTH (i);
2402 right_start = BYTE_TO_CHAR (right_start_byte);
2404 /* If RIGHT_START_BYTE is in the middle of a character,
2405 adjust it and RIGHT_START to a char boundary. */
2406 temp = CHAR_TO_BYTE (right_start);
2408 if (right_start_byte < temp)
2410 right_start_byte = temp;
2412 if (right_start_byte > temp)
2414 right_start++;
2415 right_start_byte = CHAR_TO_BYTE (right_start);
2418 else
2420 right_start = end - RIGHT_TOTAL_LENGTH (i);
2421 right_start_byte = CHAR_TO_BYTE (right_start);
2424 set_intervals_multibyte_1 (i->right, multi_flag,
2425 right_start, right_start_byte,
2426 end, end_byte);
2429 /* Rounding to char boundaries can theoretically ake this interval
2430 spurious. If so, delete one child, and copy its property list
2431 to this interval. */
2432 if (LEFT_TOTAL_LENGTH (i) + RIGHT_TOTAL_LENGTH (i) >= TOTAL_LENGTH (i))
2434 if ((i)->left)
2436 set_interval_plist (i, i->left->plist);
2437 (i)->left->total_length = 0;
2438 delete_interval ((i)->left);
2440 else
2442 set_interval_plist (i, i->right->plist);
2443 (i)->right->total_length = 0;
2444 delete_interval ((i)->right);
2449 /* Update the intervals of the current buffer
2450 to fit the contents as multibyte (if MULTI_FLAG)
2451 or to fit them as non-multibyte (if not MULTI_FLAG). */
2453 void
2454 set_intervals_multibyte (bool multi_flag)
2456 INTERVAL i = buffer_intervals (current_buffer);
2458 if (i)
2459 set_intervals_multibyte_1 (i, multi_flag, BEG, BEG_BYTE, Z, Z_BYTE);