Inline functions to examine and change buffer overlays.
[bpt/emacs.git] / src / intervals.c
1 /* Code for doing intervals.
2 Copyright (C) 1993-1995, 1997-1998, 2001-2012 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
19
20 /* NOTES:
21
22 Have to ensure that we can't put symbol nil on a plist, or some
23 functions may work incorrectly.
24
25 An idea: Have the owner of the tree keep count of splits and/or
26 insertion lengths (in intervals), and balance after every N.
27
28 Need to call *_left_hook when buffer is killed.
29
30 Scan for zero-length, or 0-length to see notes about handling
31 zero length interval-markers.
32
33 There are comments around about freeing intervals. It might be
34 faster to explicitly free them (put them on the free list) than
35 to GC them.
36
37 */
38
39
40 #include <config.h>
41 #include <setjmp.h>
42 #include <intprops.h>
43 #include "lisp.h"
44 #include "intervals.h"
45 #include "character.h"
46 #include "buffer.h"
47 #include "puresize.h"
48 #include "keyboard.h"
49 #include "keymap.h"
50
51 /* Test for membership, allowing for t (actually any non-cons) to mean the
52 universal set. */
53
54 #define TMEM(sym, set) (CONSP (set) ? ! NILP (Fmemq (sym, set)) : ! NILP (set))
55
56 static Lisp_Object merge_properties_sticky (Lisp_Object, Lisp_Object);
57 static INTERVAL merge_interval_right (INTERVAL);
58 static INTERVAL reproduce_tree (INTERVAL, INTERVAL);
59 static INTERVAL reproduce_tree_obj (INTERVAL, Lisp_Object);
60 \f
61 /* Utility functions for intervals. */
62
63
64 /* Create the root interval of some object, a buffer or string. */
65
66 INTERVAL
67 create_root_interval (Lisp_Object parent)
68 {
69 INTERVAL new;
70
71 CHECK_IMPURE (parent);
72
73 new = make_interval ();
74
75 if (BUFFERP (parent))
76 {
77 new->total_length = (BUF_Z (XBUFFER (parent))
78 - BUF_BEG (XBUFFER (parent)));
79 eassert (0 <= TOTAL_LENGTH (new));
80 buffer_set_intervals (XBUFFER (parent), new);
81 new->position = BEG;
82 }
83 else if (STRINGP (parent))
84 {
85 new->total_length = SCHARS (parent);
86 eassert (0 <= TOTAL_LENGTH (new));
87 string_set_intervals (parent, new);
88 new->position = 0;
89 }
90
91 interval_set_object (new, parent);
92
93 return new;
94 }
95
96 /* Make the interval TARGET have exactly the properties of SOURCE */
97
98 void
99 copy_properties (register INTERVAL source, register INTERVAL target)
100 {
101 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
102 return;
103
104 COPY_INTERVAL_CACHE (source, target);
105 interval_set_plist (target, Fcopy_sequence (source->plist));
106 }
107
108 /* Merge the properties of interval SOURCE into the properties
109 of interval TARGET. That is to say, each property in SOURCE
110 is added to TARGET if TARGET has no such property as yet. */
111
112 static void
113 merge_properties (register INTERVAL source, register INTERVAL target)
114 {
115 register Lisp_Object o, sym, val;
116
117 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
118 return;
119
120 MERGE_INTERVAL_CACHE (source, target);
121
122 o = source->plist;
123 while (CONSP (o))
124 {
125 sym = XCAR (o);
126 o = XCDR (o);
127 CHECK_CONS (o);
128
129 val = target->plist;
130 while (CONSP (val) && !EQ (XCAR (val), sym))
131 {
132 val = XCDR (val);
133 if (!CONSP (val))
134 break;
135 val = XCDR (val);
136 }
137
138 if (NILP (val))
139 {
140 val = XCAR (o);
141 interval_set_plist (target, Fcons (sym, Fcons (val, target->plist)));
142 }
143 o = XCDR (o);
144 }
145 }
146
147 /* Return 1 if the two intervals have the same properties,
148 0 otherwise. */
149
150 int
151 intervals_equal (INTERVAL i0, INTERVAL i1)
152 {
153 register Lisp_Object i0_cdr, i0_sym;
154 register Lisp_Object i1_cdr, i1_val;
155
156 if (DEFAULT_INTERVAL_P (i0) && DEFAULT_INTERVAL_P (i1))
157 return 1;
158
159 if (DEFAULT_INTERVAL_P (i0) || DEFAULT_INTERVAL_P (i1))
160 return 0;
161
162 i0_cdr = i0->plist;
163 i1_cdr = i1->plist;
164 while (CONSP (i0_cdr) && CONSP (i1_cdr))
165 {
166 i0_sym = XCAR (i0_cdr);
167 i0_cdr = XCDR (i0_cdr);
168 if (!CONSP (i0_cdr))
169 return 0; /* abort (); */
170 i1_val = i1->plist;
171 while (CONSP (i1_val) && !EQ (XCAR (i1_val), i0_sym))
172 {
173 i1_val = XCDR (i1_val);
174 if (!CONSP (i1_val))
175 return 0; /* abort (); */
176 i1_val = XCDR (i1_val);
177 }
178
179 /* i0 has something i1 doesn't. */
180 if (EQ (i1_val, Qnil))
181 return 0;
182
183 /* i0 and i1 both have sym, but it has different values in each. */
184 if (!CONSP (i1_val)
185 || (i1_val = XCDR (i1_val), !CONSP (i1_val))
186 || !EQ (XCAR (i1_val), XCAR (i0_cdr)))
187 return 0;
188
189 i0_cdr = XCDR (i0_cdr);
190
191 i1_cdr = XCDR (i1_cdr);
192 if (!CONSP (i1_cdr))
193 return 0; /* abort (); */
194 i1_cdr = XCDR (i1_cdr);
195 }
196
197 /* Lengths of the two plists were equal. */
198 return (NILP (i0_cdr) && NILP (i1_cdr));
199 }
200 \f
201
202 /* Traverse an interval tree TREE, performing FUNCTION on each node.
203 No guarantee is made about the order of traversal.
204 Pass FUNCTION two args: an interval, and ARG. */
205
206 void
207 traverse_intervals_noorder (INTERVAL tree, void (*function) (INTERVAL, Lisp_Object), Lisp_Object arg)
208 {
209 /* Minimize stack usage. */
210 while (tree)
211 {
212 (*function) (tree, arg);
213 if (!tree->right)
214 tree = tree->left;
215 else
216 {
217 traverse_intervals_noorder (tree->left, function, arg);
218 tree = tree->right;
219 }
220 }
221 }
222
223 /* Traverse an interval tree TREE, performing FUNCTION on each node.
224 Pass FUNCTION two args: an interval, and ARG. */
225
226 void
227 traverse_intervals (INTERVAL tree, ptrdiff_t position,
228 void (*function) (INTERVAL, Lisp_Object), Lisp_Object arg)
229 {
230 while (tree)
231 {
232 traverse_intervals (tree->left, position, function, arg);
233 position += LEFT_TOTAL_LENGTH (tree);
234 tree->position = position;
235 (*function) (tree, arg);
236 position += LENGTH (tree); tree = tree->right;
237 }
238 }
239 \f
240 #if 0
241
242 static int icount;
243 static int idepth;
244 static int zero_length;
245
246 /* These functions are temporary, for debugging purposes only. */
247
248 INTERVAL search_interval, found_interval;
249
250 void
251 check_for_interval (INTERVAL i)
252 {
253 if (i == search_interval)
254 {
255 found_interval = i;
256 icount++;
257 }
258 }
259
260 INTERVAL
261 search_for_interval (INTERVAL i, INTERVAL tree)
262 {
263 icount = 0;
264 search_interval = i;
265 found_interval = NULL;
266 traverse_intervals_noorder (tree, &check_for_interval, Qnil);
267 return found_interval;
268 }
269
270 static void
271 inc_interval_count (INTERVAL i)
272 {
273 icount++;
274 if (LENGTH (i) == 0)
275 zero_length++;
276 if (depth > idepth)
277 idepth = depth;
278 }
279
280 int
281 count_intervals (INTERVAL i)
282 {
283 icount = 0;
284 idepth = 0;
285 zero_length = 0;
286 traverse_intervals_noorder (i, &inc_interval_count, Qnil);
287
288 return icount;
289 }
290
291 static INTERVAL
292 root_interval (INTERVAL interval)
293 {
294 register INTERVAL i = interval;
295
296 while (! ROOT_INTERVAL_P (i))
297 i = INTERVAL_PARENT (i);
298
299 return i;
300 }
301 #endif
302 \f
303 /* Assuming that a left child exists, perform the following operation:
304
305 A B
306 / \ / \
307 B => A
308 / \ / \
309 c c
310 */
311
312 static inline INTERVAL
313 rotate_right (INTERVAL interval)
314 {
315 INTERVAL i;
316 INTERVAL B = interval->left;
317 ptrdiff_t old_total = interval->total_length;
318
319 /* Deal with any Parent of A; make it point to B. */
320 if (! ROOT_INTERVAL_P (interval))
321 {
322 if (AM_LEFT_CHILD (interval))
323 interval_set_left (INTERVAL_PARENT (interval), B);
324 else
325 interval_set_right (INTERVAL_PARENT (interval), B);
326 }
327 interval_copy_parent (B, interval);
328
329 /* Make B the parent of A */
330 i = B->right;
331 interval_set_right (B, interval);
332 interval_set_parent (interval, B);
333
334 /* Make A point to c */
335 interval_set_left (interval, i);
336 if (i)
337 interval_set_parent (i, interval);
338
339 /* A's total length is decreased by the length of B and its left child. */
340 interval->total_length -= B->total_length - LEFT_TOTAL_LENGTH (interval);
341 eassert (0 <= TOTAL_LENGTH (interval));
342
343 /* B must have the same total length of A. */
344 B->total_length = old_total;
345 eassert (0 <= TOTAL_LENGTH (B));
346
347 return B;
348 }
349
350 /* Assuming that a right child exists, perform the following operation:
351
352 A B
353 / \ / \
354 B => A
355 / \ / \
356 c c
357 */
358
359 static inline INTERVAL
360 rotate_left (INTERVAL interval)
361 {
362 INTERVAL i;
363 INTERVAL B = interval->right;
364 ptrdiff_t old_total = interval->total_length;
365
366 /* Deal with any parent of A; make it point to B. */
367 if (! ROOT_INTERVAL_P (interval))
368 {
369 if (AM_LEFT_CHILD (interval))
370 interval_set_left (INTERVAL_PARENT (interval), B);
371 else
372 interval_set_right (INTERVAL_PARENT (interval), B);
373 }
374 interval_copy_parent (B, interval);
375
376 /* Make B the parent of A */
377 i = B->left;
378 interval_set_left (B, interval);
379 interval_set_parent (interval, B);
380
381 /* Make A point to c */
382 interval_set_right (interval, i);
383 if (i)
384 interval_set_parent (i, interval);
385
386 /* A's total length is decreased by the length of B and its right child. */
387 interval->total_length -= B->total_length - RIGHT_TOTAL_LENGTH (interval);
388 eassert (0 <= TOTAL_LENGTH (interval));
389
390 /* B must have the same total length of A. */
391 B->total_length = old_total;
392 eassert (0 <= TOTAL_LENGTH (B));
393
394 return B;
395 }
396 \f
397 /* Balance an interval tree with the assumption that the subtrees
398 themselves are already balanced. */
399
400 static INTERVAL
401 balance_an_interval (INTERVAL i)
402 {
403 register ptrdiff_t old_diff, new_diff;
404
405 while (1)
406 {
407 old_diff = LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i);
408 if (old_diff > 0)
409 {
410 /* Since the left child is longer, there must be one. */
411 new_diff = i->total_length - i->left->total_length
412 + RIGHT_TOTAL_LENGTH (i->left) - LEFT_TOTAL_LENGTH (i->left);
413 if (eabs (new_diff) >= old_diff)
414 break;
415 i = rotate_right (i);
416 balance_an_interval (i->right);
417 }
418 else if (old_diff < 0)
419 {
420 /* Since the right child is longer, there must be one. */
421 new_diff = i->total_length - i->right->total_length
422 + LEFT_TOTAL_LENGTH (i->right) - RIGHT_TOTAL_LENGTH (i->right);
423 if (eabs (new_diff) >= -old_diff)
424 break;
425 i = rotate_left (i);
426 balance_an_interval (i->left);
427 }
428 else
429 break;
430 }
431 return i;
432 }
433
434 /* Balance INTERVAL, potentially stuffing it back into its parent
435 Lisp Object. */
436
437 static inline INTERVAL
438 balance_possible_root_interval (register INTERVAL interval)
439 {
440 Lisp_Object parent;
441 int have_parent = 0;
442
443 if (!INTERVAL_HAS_OBJECT (interval) && !INTERVAL_HAS_PARENT (interval))
444 return interval;
445
446 if (INTERVAL_HAS_OBJECT (interval))
447 {
448 have_parent = 1;
449 GET_INTERVAL_OBJECT (parent, interval);
450 }
451 interval = balance_an_interval (interval);
452
453 if (have_parent)
454 {
455 if (BUFFERP (parent))
456 buffer_set_intervals (XBUFFER (parent), interval);
457 else if (STRINGP (parent))
458 string_set_intervals (parent, interval);
459 }
460
461 return interval;
462 }
463
464 /* Balance the interval tree TREE. Balancing is by weight
465 (the amount of text). */
466
467 static INTERVAL
468 balance_intervals_internal (register INTERVAL tree)
469 {
470 /* Balance within each side. */
471 if (tree->left)
472 balance_intervals_internal (tree->left);
473 if (tree->right)
474 balance_intervals_internal (tree->right);
475 return balance_an_interval (tree);
476 }
477
478 /* Advertised interface to balance intervals. */
479
480 INTERVAL
481 balance_intervals (INTERVAL tree)
482 {
483 return tree ? balance_intervals_internal (tree) : NULL;
484 }
485
486 /* Rebalance text properties of B. */
487
488 static void
489 buffer_balance_intervals (struct buffer *b)
490 {
491 INTERVAL i;
492
493 eassert (b != NULL);
494 i = buffer_get_intervals (b);
495 if (i)
496 buffer_set_intervals (b, balance_an_interval (i));
497 }
498
499 /* Split INTERVAL into two pieces, starting the second piece at
500 character position OFFSET (counting from 0), relative to INTERVAL.
501 INTERVAL becomes the left-hand piece, and the right-hand piece
502 (second, lexicographically) is returned.
503
504 The size and position fields of the two intervals are set based upon
505 those of the original interval. The property list of the new interval
506 is reset, thus it is up to the caller to do the right thing with the
507 result.
508
509 Note that this does not change the position of INTERVAL; if it is a root,
510 it is still a root after this operation. */
511
512 INTERVAL
513 split_interval_right (INTERVAL interval, ptrdiff_t offset)
514 {
515 INTERVAL new = make_interval ();
516 ptrdiff_t position = interval->position;
517 ptrdiff_t new_length = LENGTH (interval) - offset;
518
519 new->position = position + offset;
520 interval_set_parent (new, interval);
521
522 if (NULL_RIGHT_CHILD (interval))
523 {
524 interval_set_right (interval, new);
525 new->total_length = new_length;
526 eassert (0 <= TOTAL_LENGTH (new));
527 }
528 else
529 {
530 /* Insert the new node between INTERVAL and its right child. */
531 interval_set_right (new, interval->right);
532 interval_set_parent (interval->right, new);
533 interval_set_right (interval, new);
534 new->total_length = new_length + new->right->total_length;
535 eassert (0 <= TOTAL_LENGTH (new));
536 balance_an_interval (new);
537 }
538
539 balance_possible_root_interval (interval);
540
541 return new;
542 }
543
544 /* Split INTERVAL into two pieces, starting the second piece at
545 character position OFFSET (counting from 0), relative to INTERVAL.
546 INTERVAL becomes the right-hand piece, and the left-hand piece
547 (first, lexicographically) is returned.
548
549 The size and position fields of the two intervals are set based upon
550 those of the original interval. The property list of the new interval
551 is reset, thus it is up to the caller to do the right thing with the
552 result.
553
554 Note that this does not change the position of INTERVAL; if it is a root,
555 it is still a root after this operation. */
556
557 INTERVAL
558 split_interval_left (INTERVAL interval, ptrdiff_t offset)
559 {
560 INTERVAL new = make_interval ();
561 ptrdiff_t new_length = offset;
562
563 new->position = interval->position;
564 interval->position = interval->position + offset;
565 interval_set_parent (new, interval);
566
567 if (NULL_LEFT_CHILD (interval))
568 {
569 interval_set_left (interval, new);
570 new->total_length = new_length;
571 eassert (0 <= TOTAL_LENGTH (new));
572 }
573 else
574 {
575 /* Insert the new node between INTERVAL and its left child. */
576 interval_set_left (new, interval->left);
577 interval_set_parent (new->left, new);
578 interval_set_left (interval, new);
579 new->total_length = new_length + new->left->total_length;
580 eassert (0 <= TOTAL_LENGTH (new));
581 balance_an_interval (new);
582 }
583
584 balance_possible_root_interval (interval);
585
586 return new;
587 }
588 \f
589 /* Return the proper position for the first character
590 described by the interval tree SOURCE.
591 This is 1 if the parent is a buffer,
592 0 if the parent is a string or if there is no parent.
593
594 Don't use this function on an interval which is the child
595 of another interval! */
596
597 static int
598 interval_start_pos (INTERVAL source)
599 {
600 Lisp_Object parent;
601
602 if (!source)
603 return 0;
604
605 if (! INTERVAL_HAS_OBJECT (source))
606 return 0;
607 GET_INTERVAL_OBJECT (parent, source);
608 if (BUFFERP (parent))
609 return BUF_BEG (XBUFFER (parent));
610 return 0;
611 }
612
613 /* Find the interval containing text position POSITION in the text
614 represented by the interval tree TREE. POSITION is a buffer
615 position (starting from 1) or a string index (starting from 0).
616 If POSITION is at the end of the buffer or string,
617 return the interval containing the last character.
618
619 The `position' field, which is a cache of an interval's position,
620 is updated in the interval found. Other functions (e.g., next_interval)
621 will update this cache based on the result of find_interval. */
622
623 INTERVAL
624 find_interval (register INTERVAL tree, register ptrdiff_t position)
625 {
626 /* The distance from the left edge of the subtree at TREE
627 to POSITION. */
628 register ptrdiff_t relative_position;
629
630 if (!tree)
631 return NULL;
632
633 relative_position = position;
634 if (INTERVAL_HAS_OBJECT (tree))
635 {
636 Lisp_Object parent;
637 GET_INTERVAL_OBJECT (parent, tree);
638 if (BUFFERP (parent))
639 relative_position -= BUF_BEG (XBUFFER (parent));
640 }
641
642 eassert (relative_position <= TOTAL_LENGTH (tree));
643
644 if (!handling_signal)
645 tree = balance_possible_root_interval (tree);
646
647 while (1)
648 {
649 if (relative_position < LEFT_TOTAL_LENGTH (tree))
650 {
651 tree = tree->left;
652 }
653 else if (! NULL_RIGHT_CHILD (tree)
654 && relative_position >= (TOTAL_LENGTH (tree)
655 - RIGHT_TOTAL_LENGTH (tree)))
656 {
657 relative_position -= (TOTAL_LENGTH (tree)
658 - RIGHT_TOTAL_LENGTH (tree));
659 tree = tree->right;
660 }
661 else
662 {
663 tree->position
664 = (position - relative_position /* left edge of *tree. */
665 + LEFT_TOTAL_LENGTH (tree)); /* left edge of this interval. */
666
667 return tree;
668 }
669 }
670 }
671 \f
672 /* Find the succeeding interval (lexicographically) to INTERVAL.
673 Sets the `position' field based on that of INTERVAL (see
674 find_interval). */
675
676 INTERVAL
677 next_interval (register INTERVAL interval)
678 {
679 register INTERVAL i = interval;
680 register ptrdiff_t next_position;
681
682 if (!i)
683 return NULL;
684 next_position = interval->position + LENGTH (interval);
685
686 if (! NULL_RIGHT_CHILD (i))
687 {
688 i = i->right;
689 while (! NULL_LEFT_CHILD (i))
690 i = i->left;
691
692 i->position = next_position;
693 return i;
694 }
695
696 while (! NULL_PARENT (i))
697 {
698 if (AM_LEFT_CHILD (i))
699 {
700 i = INTERVAL_PARENT (i);
701 i->position = next_position;
702 return i;
703 }
704
705 i = INTERVAL_PARENT (i);
706 }
707
708 return NULL;
709 }
710
711 /* Find the preceding interval (lexicographically) to INTERVAL.
712 Sets the `position' field based on that of INTERVAL (see
713 find_interval). */
714
715 INTERVAL
716 previous_interval (register INTERVAL interval)
717 {
718 register INTERVAL i;
719
720 if (!interval)
721 return NULL;
722
723 if (! NULL_LEFT_CHILD (interval))
724 {
725 i = interval->left;
726 while (! NULL_RIGHT_CHILD (i))
727 i = i->right;
728
729 i->position = interval->position - LENGTH (i);
730 return i;
731 }
732
733 i = interval;
734 while (! NULL_PARENT (i))
735 {
736 if (AM_RIGHT_CHILD (i))
737 {
738 i = INTERVAL_PARENT (i);
739
740 i->position = interval->position - LENGTH (i);
741 return i;
742 }
743 i = INTERVAL_PARENT (i);
744 }
745
746 return NULL;
747 }
748
749 /* Find the interval containing POS given some non-NULL INTERVAL
750 in the same tree. Note that we need to update interval->position
751 if we go down the tree.
752 To speed up the process, we assume that the ->position of
753 I and all its parents is already uptodate. */
754 INTERVAL
755 update_interval (register INTERVAL i, ptrdiff_t pos)
756 {
757 if (!i)
758 return NULL;
759
760 while (1)
761 {
762 if (pos < i->position)
763 {
764 /* Move left. */
765 if (pos >= i->position - TOTAL_LENGTH (i->left))
766 {
767 i->left->position = i->position - TOTAL_LENGTH (i->left)
768 + LEFT_TOTAL_LENGTH (i->left);
769 i = i->left; /* Move to the left child */
770 }
771 else if (NULL_PARENT (i))
772 error ("Point before start of properties");
773 else
774 i = INTERVAL_PARENT (i);
775 continue;
776 }
777 else if (pos >= INTERVAL_LAST_POS (i))
778 {
779 /* Move right. */
780 if (pos < INTERVAL_LAST_POS (i) + TOTAL_LENGTH (i->right))
781 {
782 i->right->position = INTERVAL_LAST_POS (i)
783 + LEFT_TOTAL_LENGTH (i->right);
784 i = i->right; /* Move to the right child */
785 }
786 else if (NULL_PARENT (i))
787 error ("Point %"pD"d after end of properties", pos);
788 else
789 i = INTERVAL_PARENT (i);
790 continue;
791 }
792 else
793 return i;
794 }
795 }
796
797 /* Effect an adjustment corresponding to the addition of LENGTH characters
798 of text. Do this by finding the interval containing POSITION in the
799 interval tree TREE, and then adjusting all of its ancestors by adding
800 LENGTH to them.
801
802 If POSITION is the first character of an interval, meaning that point
803 is actually between the two intervals, make the new text belong to
804 the interval which is "sticky".
805
806 If both intervals are "sticky", then make them belong to the left-most
807 interval. Another possibility would be to create a new interval for
808 this text, and make it have the merged properties of both ends. */
809
810 static INTERVAL
811 adjust_intervals_for_insertion (INTERVAL tree,
812 ptrdiff_t position, ptrdiff_t length)
813 {
814 register INTERVAL i;
815 register INTERVAL temp;
816 int eobp = 0;
817 Lisp_Object parent;
818 ptrdiff_t offset;
819
820 eassert (TOTAL_LENGTH (tree) > 0);
821
822 GET_INTERVAL_OBJECT (parent, tree);
823 offset = (BUFFERP (parent) ? BUF_BEG (XBUFFER (parent)) : 0);
824
825 /* If inserting at point-max of a buffer, that position will be out
826 of range. Remember that buffer positions are 1-based. */
827 if (position >= TOTAL_LENGTH (tree) + offset)
828 {
829 position = TOTAL_LENGTH (tree) + offset;
830 eobp = 1;
831 }
832
833 i = find_interval (tree, position);
834
835 /* If in middle of an interval which is not sticky either way,
836 we must not just give its properties to the insertion.
837 So split this interval at the insertion point.
838
839 Originally, the if condition here was this:
840 (! (position == i->position || eobp)
841 && END_NONSTICKY_P (i)
842 && FRONT_NONSTICKY_P (i))
843 But, these macros are now unreliable because of introduction of
844 Vtext_property_default_nonsticky. So, we always check properties
845 one by one if POSITION is in middle of an interval. */
846 if (! (position == i->position || eobp))
847 {
848 Lisp_Object tail;
849 Lisp_Object front, rear;
850
851 tail = i->plist;
852
853 /* Properties font-sticky and rear-nonsticky override
854 Vtext_property_default_nonsticky. So, if they are t, we can
855 skip one by one checking of properties. */
856 rear = textget (i->plist, Qrear_nonsticky);
857 if (! CONSP (rear) && ! NILP (rear))
858 {
859 /* All properties are nonsticky. We split the interval. */
860 goto check_done;
861 }
862 front = textget (i->plist, Qfront_sticky);
863 if (! CONSP (front) && ! NILP (front))
864 {
865 /* All properties are sticky. We don't split the interval. */
866 tail = Qnil;
867 goto check_done;
868 }
869
870 /* Does any actual property pose an actual problem? We break
871 the loop if we find a nonsticky property. */
872 for (; CONSP (tail); tail = Fcdr (XCDR (tail)))
873 {
874 Lisp_Object prop, tmp;
875 prop = XCAR (tail);
876
877 /* Is this particular property front-sticky? */
878 if (CONSP (front) && ! NILP (Fmemq (prop, front)))
879 continue;
880
881 /* Is this particular property rear-nonsticky? */
882 if (CONSP (rear) && ! NILP (Fmemq (prop, rear)))
883 break;
884
885 /* Is this particular property recorded as sticky or
886 nonsticky in Vtext_property_default_nonsticky? */
887 tmp = Fassq (prop, Vtext_property_default_nonsticky);
888 if (CONSP (tmp))
889 {
890 if (NILP (tmp))
891 continue;
892 break;
893 }
894
895 /* By default, a text property is rear-sticky, thus we
896 continue the loop. */
897 }
898
899 check_done:
900 /* If any property is a real problem, split the interval. */
901 if (! NILP (tail))
902 {
903 temp = split_interval_right (i, position - i->position);
904 copy_properties (i, temp);
905 i = temp;
906 }
907 }
908
909 /* If we are positioned between intervals, check the stickiness of
910 both of them. We have to do this too, if we are at BEG or Z. */
911 if (position == i->position || eobp)
912 {
913 register INTERVAL prev;
914
915 if (position == BEG)
916 prev = 0;
917 else if (eobp)
918 {
919 prev = i;
920 i = 0;
921 }
922 else
923 prev = previous_interval (i);
924
925 /* Even if we are positioned between intervals, we default
926 to the left one if it exists. We extend it now and split
927 off a part later, if stickiness demands it. */
928 for (temp = prev ? prev : i; temp; temp = INTERVAL_PARENT_OR_NULL (temp))
929 {
930 temp->total_length += length;
931 eassert (0 <= TOTAL_LENGTH (temp));
932 temp = balance_possible_root_interval (temp);
933 }
934
935 /* If at least one interval has sticky properties,
936 we check the stickiness property by property.
937
938 Originally, the if condition here was this:
939 (END_NONSTICKY_P (prev) || FRONT_STICKY_P (i))
940 But, these macros are now unreliable because of introduction
941 of Vtext_property_default_nonsticky. So, we always have to
942 check stickiness of properties one by one. If cache of
943 stickiness is implemented in the future, we may be able to
944 use those macros again. */
945 if (1)
946 {
947 Lisp_Object pleft, pright;
948 struct interval newi;
949
950 RESET_INTERVAL (&newi);
951 pleft = prev ? prev->plist : Qnil;
952 pright = i ? i->plist : Qnil;
953 interval_set_plist (&newi, merge_properties_sticky (pleft, pright));
954
955 if (! prev) /* i.e. position == BEG */
956 {
957 if (! intervals_equal (i, &newi))
958 {
959 i = split_interval_left (i, length);
960 interval_set_plist (i, newi.plist);
961 }
962 }
963 else if (! intervals_equal (prev, &newi))
964 {
965 prev = split_interval_right (prev, position - prev->position);
966 interval_set_plist (prev, newi.plist);
967 if (i && intervals_equal (prev, i))
968 merge_interval_right (prev);
969 }
970
971 /* We will need to update the cache here later. */
972 }
973 else if (! prev && ! NILP (i->plist))
974 {
975 /* Just split off a new interval at the left.
976 Since I wasn't front-sticky, the empty plist is ok. */
977 i = split_interval_left (i, length);
978 }
979 }
980
981 /* Otherwise just extend the interval. */
982 else
983 {
984 for (temp = i; temp; temp = INTERVAL_PARENT_OR_NULL (temp))
985 {
986 temp->total_length += length;
987 eassert (0 <= TOTAL_LENGTH (temp));
988 temp = balance_possible_root_interval (temp);
989 }
990 }
991
992 return tree;
993 }
994
995 /* Any property might be front-sticky on the left, rear-sticky on the left,
996 front-sticky on the right, or rear-sticky on the right; the 16 combinations
997 can be arranged in a matrix with rows denoting the left conditions and
998 columns denoting the right conditions:
999 _ __ _
1000 _ FR FR FR FR
1001 FR__ 0 1 2 3
1002 _FR 4 5 6 7
1003 FR 8 9 A B
1004 FR C D E F
1005
1006 left-props = '(front-sticky (p8 p9 pa pb pc pd pe pf)
1007 rear-nonsticky (p4 p5 p6 p7 p8 p9 pa pb)
1008 p0 L p1 L p2 L p3 L p4 L p5 L p6 L p7 L
1009 p8 L p9 L pa L pb L pc L pd L pe L pf L)
1010 right-props = '(front-sticky (p2 p3 p6 p7 pa pb pe pf)
1011 rear-nonsticky (p1 p2 p5 p6 p9 pa pd pe)
1012 p0 R p1 R p2 R p3 R p4 R p5 R p6 R p7 R
1013 p8 R p9 R pa R pb R pc R pd R pe R pf R)
1014
1015 We inherit from whoever has a sticky side facing us. If both sides
1016 do (cases 2, 3, E, and F), then we inherit from whichever side has a
1017 non-nil value for the current property. If both sides do, then we take
1018 from the left.
1019
1020 When we inherit a property, we get its stickiness as well as its value.
1021 So, when we merge the above two lists, we expect to get this:
1022
1023 result = '(front-sticky (p6 p7 pa pb pc pd pe pf)
1024 rear-nonsticky (p6 pa)
1025 p0 L p1 L p2 L p3 L p6 R p7 R
1026 pa R pb R pc L pd L pe L pf L)
1027
1028 The optimizable special cases are:
1029 left rear-nonsticky = nil, right front-sticky = nil (inherit left)
1030 left rear-nonsticky = t, right front-sticky = t (inherit right)
1031 left rear-nonsticky = t, right front-sticky = nil (inherit none)
1032 */
1033
1034 static Lisp_Object
1035 merge_properties_sticky (Lisp_Object pleft, Lisp_Object pright)
1036 {
1037 register Lisp_Object props, front, rear;
1038 Lisp_Object lfront, lrear, rfront, rrear;
1039 register Lisp_Object tail1, tail2, sym, lval, rval, cat;
1040 int use_left, use_right;
1041 int lpresent;
1042
1043 props = Qnil;
1044 front = Qnil;
1045 rear = Qnil;
1046 lfront = textget (pleft, Qfront_sticky);
1047 lrear = textget (pleft, Qrear_nonsticky);
1048 rfront = textget (pright, Qfront_sticky);
1049 rrear = textget (pright, Qrear_nonsticky);
1050
1051 /* Go through each element of PRIGHT. */
1052 for (tail1 = pright; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
1053 {
1054 Lisp_Object tmp;
1055
1056 sym = XCAR (tail1);
1057
1058 /* Sticky properties get special treatment. */
1059 if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky))
1060 continue;
1061
1062 rval = Fcar (XCDR (tail1));
1063 for (tail2 = pleft; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
1064 if (EQ (sym, XCAR (tail2)))
1065 break;
1066
1067 /* Indicate whether the property is explicitly defined on the left.
1068 (We know it is defined explicitly on the right
1069 because otherwise we don't get here.) */
1070 lpresent = ! NILP (tail2);
1071 lval = (NILP (tail2) ? Qnil : Fcar (Fcdr (tail2)));
1072
1073 /* Even if lrear or rfront say nothing about the stickiness of
1074 SYM, Vtext_property_default_nonsticky may give default
1075 stickiness to SYM. */
1076 tmp = Fassq (sym, Vtext_property_default_nonsticky);
1077 use_left = (lpresent
1078 && ! (TMEM (sym, lrear)
1079 || (CONSP (tmp) && ! NILP (XCDR (tmp)))));
1080 use_right = (TMEM (sym, rfront)
1081 || (CONSP (tmp) && NILP (XCDR (tmp))));
1082 if (use_left && use_right)
1083 {
1084 if (NILP (lval))
1085 use_left = 0;
1086 else if (NILP (rval))
1087 use_right = 0;
1088 }
1089 if (use_left)
1090 {
1091 /* We build props as (value sym ...) rather than (sym value ...)
1092 because we plan to nreverse it when we're done. */
1093 props = Fcons (lval, Fcons (sym, props));
1094 if (TMEM (sym, lfront))
1095 front = Fcons (sym, front);
1096 if (TMEM (sym, lrear))
1097 rear = Fcons (sym, rear);
1098 }
1099 else if (use_right)
1100 {
1101 props = Fcons (rval, Fcons (sym, props));
1102 if (TMEM (sym, rfront))
1103 front = Fcons (sym, front);
1104 if (TMEM (sym, rrear))
1105 rear = Fcons (sym, rear);
1106 }
1107 }
1108
1109 /* Now go through each element of PLEFT. */
1110 for (tail2 = pleft; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
1111 {
1112 Lisp_Object tmp;
1113
1114 sym = XCAR (tail2);
1115
1116 /* Sticky properties get special treatment. */
1117 if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky))
1118 continue;
1119
1120 /* If sym is in PRIGHT, we've already considered it. */
1121 for (tail1 = pright; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
1122 if (EQ (sym, XCAR (tail1)))
1123 break;
1124 if (! NILP (tail1))
1125 continue;
1126
1127 lval = Fcar (XCDR (tail2));
1128
1129 /* Even if lrear or rfront say nothing about the stickiness of
1130 SYM, Vtext_property_default_nonsticky may give default
1131 stickiness to SYM. */
1132 tmp = Fassq (sym, Vtext_property_default_nonsticky);
1133
1134 /* Since rval is known to be nil in this loop, the test simplifies. */
1135 if (! (TMEM (sym, lrear) || (CONSP (tmp) && ! NILP (XCDR (tmp)))))
1136 {
1137 props = Fcons (lval, Fcons (sym, props));
1138 if (TMEM (sym, lfront))
1139 front = Fcons (sym, front);
1140 }
1141 else if (TMEM (sym, rfront) || (CONSP (tmp) && NILP (XCDR (tmp))))
1142 {
1143 /* The value is nil, but we still inherit the stickiness
1144 from the right. */
1145 front = Fcons (sym, front);
1146 if (TMEM (sym, rrear))
1147 rear = Fcons (sym, rear);
1148 }
1149 }
1150 props = Fnreverse (props);
1151 if (! NILP (rear))
1152 props = Fcons (Qrear_nonsticky, Fcons (Fnreverse (rear), props));
1153
1154 cat = textget (props, Qcategory);
1155 if (! NILP (front)
1156 &&
1157 /* If we have inherited a front-stick category property that is t,
1158 we don't need to set up a detailed one. */
1159 ! (! NILP (cat) && SYMBOLP (cat)
1160 && EQ (Fget (cat, Qfront_sticky), Qt)))
1161 props = Fcons (Qfront_sticky, Fcons (Fnreverse (front), props));
1162 return props;
1163 }
1164
1165 \f
1166 /* Delete a node I from its interval tree by merging its subtrees
1167 into one subtree which is then returned. Caller is responsible for
1168 storing the resulting subtree into its parent. */
1169
1170 static INTERVAL
1171 delete_node (register INTERVAL i)
1172 {
1173 register INTERVAL migrate, this;
1174 register ptrdiff_t migrate_amt;
1175
1176 if (!i->left)
1177 return i->right;
1178 if (!i->right)
1179 return i->left;
1180
1181 migrate = i->left;
1182 migrate_amt = i->left->total_length;
1183 this = i->right;
1184 this->total_length += migrate_amt;
1185 while (this->left)
1186 {
1187 this = this->left;
1188 this->total_length += migrate_amt;
1189 }
1190 eassert (0 <= TOTAL_LENGTH (this));
1191 interval_set_left (this, migrate);
1192 interval_set_parent (migrate, this);
1193
1194 return i->right;
1195 }
1196
1197 /* Delete interval I from its tree by calling `delete_node'
1198 and properly connecting the resultant subtree.
1199
1200 I is presumed to be empty; that is, no adjustments are made
1201 for the length of I. */
1202
1203 static void
1204 delete_interval (register INTERVAL i)
1205 {
1206 register INTERVAL parent;
1207 ptrdiff_t amt = LENGTH (i);
1208
1209 eassert (amt == 0); /* Only used on zero-length intervals now. */
1210
1211 if (ROOT_INTERVAL_P (i))
1212 {
1213 Lisp_Object owner;
1214 GET_INTERVAL_OBJECT (owner, i);
1215 parent = delete_node (i);
1216 if (parent)
1217 interval_set_object (parent, owner);
1218
1219 if (BUFFERP (owner))
1220 buffer_set_intervals (XBUFFER (owner), parent);
1221 else if (STRINGP (owner))
1222 string_set_intervals (owner, parent);
1223 else
1224 abort ();
1225
1226 return;
1227 }
1228
1229 parent = INTERVAL_PARENT (i);
1230 if (AM_LEFT_CHILD (i))
1231 {
1232 interval_set_left (parent, delete_node (i));
1233 if (parent->left)
1234 interval_set_parent (parent->left, parent);
1235 }
1236 else
1237 {
1238 interval_set_right (parent, delete_node (i));
1239 if (parent->right)
1240 interval_set_parent (parent->right, parent);
1241 }
1242 }
1243 \f
1244 /* Find the interval in TREE corresponding to the relative position
1245 FROM and delete as much as possible of AMOUNT from that interval.
1246 Return the amount actually deleted, and if the interval was
1247 zeroed-out, delete that interval node from the tree.
1248
1249 Note that FROM is actually origin zero, aka relative to the
1250 leftmost edge of tree. This is appropriate since we call ourselves
1251 recursively on subtrees.
1252
1253 Do this by recursing down TREE to the interval in question, and
1254 deleting the appropriate amount of text. */
1255
1256 static ptrdiff_t
1257 interval_deletion_adjustment (register INTERVAL tree, register ptrdiff_t from,
1258 register ptrdiff_t amount)
1259 {
1260 register ptrdiff_t relative_position = from;
1261
1262 if (!tree)
1263 return 0;
1264
1265 /* Left branch. */
1266 if (relative_position < LEFT_TOTAL_LENGTH (tree))
1267 {
1268 ptrdiff_t subtract = interval_deletion_adjustment (tree->left,
1269 relative_position,
1270 amount);
1271 tree->total_length -= subtract;
1272 eassert (0 <= TOTAL_LENGTH (tree));
1273 return subtract;
1274 }
1275 /* Right branch. */
1276 else if (relative_position >= (TOTAL_LENGTH (tree)
1277 - RIGHT_TOTAL_LENGTH (tree)))
1278 {
1279 ptrdiff_t subtract;
1280
1281 relative_position -= (tree->total_length
1282 - RIGHT_TOTAL_LENGTH (tree));
1283 subtract = interval_deletion_adjustment (tree->right,
1284 relative_position,
1285 amount);
1286 tree->total_length -= subtract;
1287 eassert (0 <= TOTAL_LENGTH (tree));
1288 return subtract;
1289 }
1290 /* Here -- this node. */
1291 else
1292 {
1293 /* How much can we delete from this interval? */
1294 ptrdiff_t my_amount = ((tree->total_length
1295 - RIGHT_TOTAL_LENGTH (tree))
1296 - relative_position);
1297
1298 if (amount > my_amount)
1299 amount = my_amount;
1300
1301 tree->total_length -= amount;
1302 eassert (0 <= TOTAL_LENGTH (tree));
1303 if (LENGTH (tree) == 0)
1304 delete_interval (tree);
1305
1306 return amount;
1307 }
1308
1309 /* Never reach here. */
1310 }
1311
1312 /* Effect the adjustments necessary to the interval tree of BUFFER to
1313 correspond to the deletion of LENGTH characters from that buffer
1314 text. The deletion is effected at position START (which is a
1315 buffer position, i.e. origin 1). */
1316
1317 static void
1318 adjust_intervals_for_deletion (struct buffer *buffer,
1319 ptrdiff_t start, ptrdiff_t length)
1320 {
1321 register ptrdiff_t left_to_delete = length;
1322 register INTERVAL tree = buffer_get_intervals (buffer);
1323 Lisp_Object parent;
1324 ptrdiff_t offset;
1325
1326 GET_INTERVAL_OBJECT (parent, tree);
1327 offset = (BUFFERP (parent) ? BUF_BEG (XBUFFER (parent)) : 0);
1328
1329 if (!tree)
1330 return;
1331
1332 eassert (start <= offset + TOTAL_LENGTH (tree)
1333 && start + length <= offset + TOTAL_LENGTH (tree));
1334
1335 if (length == TOTAL_LENGTH (tree))
1336 {
1337 buffer_set_intervals (buffer, NULL);
1338 return;
1339 }
1340
1341 if (ONLY_INTERVAL_P (tree))
1342 {
1343 tree->total_length -= length;
1344 eassert (0 <= TOTAL_LENGTH (tree));
1345 return;
1346 }
1347
1348 if (start > offset + TOTAL_LENGTH (tree))
1349 start = offset + TOTAL_LENGTH (tree);
1350 while (left_to_delete > 0)
1351 {
1352 left_to_delete -= interval_deletion_adjustment (tree, start - offset,
1353 left_to_delete);
1354 tree = buffer_get_intervals (buffer);
1355 if (left_to_delete == tree->total_length)
1356 {
1357 buffer_set_intervals (buffer, NULL);
1358 return;
1359 }
1360 }
1361 }
1362 \f
1363 /* Make the adjustments necessary to the interval tree of BUFFER to
1364 represent an addition or deletion of LENGTH characters starting
1365 at position START. Addition or deletion is indicated by the sign
1366 of LENGTH.
1367
1368 The two inline functions (one static) pacify Sun C 5.8, a pre-C99
1369 compiler that does not allow calling a static function (here,
1370 adjust_intervals_for_deletion) from a non-static inline function. */
1371
1372 void
1373 offset_intervals (struct buffer *buffer, ptrdiff_t start, ptrdiff_t length)
1374 {
1375 if (!buffer_get_intervals (buffer) || length == 0)
1376 return;
1377
1378 if (length > 0)
1379 adjust_intervals_for_insertion (buffer_get_intervals (buffer),
1380 start, length);
1381 else
1382 {
1383 IF_LINT (if (length < - TYPE_MAXIMUM (ptrdiff_t)) abort ();)
1384 adjust_intervals_for_deletion (buffer, start, -length);
1385 }
1386 }
1387 \f
1388 /* Merge interval I with its lexicographic successor. The resulting
1389 interval is returned, and has the properties of the original
1390 successor. The properties of I are lost. I is removed from the
1391 interval tree.
1392
1393 IMPORTANT:
1394 The caller must verify that this is not the last (rightmost)
1395 interval. */
1396
1397 static INTERVAL
1398 merge_interval_right (register INTERVAL i)
1399 {
1400 register ptrdiff_t absorb = LENGTH (i);
1401 register INTERVAL successor;
1402
1403 /* Find the succeeding interval. */
1404 if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb
1405 as we descend. */
1406 {
1407 successor = i->right;
1408 while (! NULL_LEFT_CHILD (successor))
1409 {
1410 successor->total_length += absorb;
1411 eassert (0 <= TOTAL_LENGTH (successor));
1412 successor = successor->left;
1413 }
1414
1415 successor->total_length += absorb;
1416 eassert (0 <= TOTAL_LENGTH (successor));
1417 delete_interval (i);
1418 return successor;
1419 }
1420
1421 /* Zero out this interval. */
1422 i->total_length -= absorb;
1423 eassert (0 <= TOTAL_LENGTH (i));
1424
1425 successor = i;
1426 while (! NULL_PARENT (successor)) /* It's above us. Subtract as
1427 we ascend. */
1428 {
1429 if (AM_LEFT_CHILD (successor))
1430 {
1431 successor = INTERVAL_PARENT (successor);
1432 delete_interval (i);
1433 return successor;
1434 }
1435
1436 successor = INTERVAL_PARENT (successor);
1437 successor->total_length -= absorb;
1438 eassert (0 <= TOTAL_LENGTH (successor));
1439 }
1440
1441 /* This must be the rightmost or last interval and cannot
1442 be merged right. The caller should have known. */
1443 abort ();
1444 }
1445 \f
1446 /* Merge interval I with its lexicographic predecessor. The resulting
1447 interval is returned, and has the properties of the original predecessor.
1448 The properties of I are lost. Interval node I is removed from the tree.
1449
1450 IMPORTANT:
1451 The caller must verify that this is not the first (leftmost) interval. */
1452
1453 INTERVAL
1454 merge_interval_left (register INTERVAL i)
1455 {
1456 register ptrdiff_t absorb = LENGTH (i);
1457 register INTERVAL predecessor;
1458
1459 /* Find the preceding interval. */
1460 if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down,
1461 adding ABSORB as we go. */
1462 {
1463 predecessor = i->left;
1464 while (! NULL_RIGHT_CHILD (predecessor))
1465 {
1466 predecessor->total_length += absorb;
1467 eassert (0 <= TOTAL_LENGTH (predecessor));
1468 predecessor = predecessor->right;
1469 }
1470
1471 predecessor->total_length += absorb;
1472 eassert (0 <= TOTAL_LENGTH (predecessor));
1473 delete_interval (i);
1474 return predecessor;
1475 }
1476
1477 /* Zero out this interval. */
1478 i->total_length -= absorb;
1479 eassert (0 <= TOTAL_LENGTH (i));
1480
1481 predecessor = i;
1482 while (! NULL_PARENT (predecessor)) /* It's above us. Go up,
1483 subtracting ABSORB. */
1484 {
1485 if (AM_RIGHT_CHILD (predecessor))
1486 {
1487 predecessor = INTERVAL_PARENT (predecessor);
1488 delete_interval (i);
1489 return predecessor;
1490 }
1491
1492 predecessor = INTERVAL_PARENT (predecessor);
1493 predecessor->total_length -= absorb;
1494 eassert (0 <= TOTAL_LENGTH (predecessor));
1495 }
1496
1497 /* This must be the leftmost or first interval and cannot
1498 be merged left. The caller should have known. */
1499 abort ();
1500 }
1501 \f
1502 /* Make an exact copy of interval tree SOURCE which descends from
1503 PARENT. This is done by recursing through SOURCE, copying
1504 the current interval and its properties, and then adjusting
1505 the pointers of the copy. */
1506
1507 static INTERVAL
1508 reproduce_tree (INTERVAL source, INTERVAL parent)
1509 {
1510 register INTERVAL t = make_interval ();
1511
1512 memcpy (t, source, sizeof *t);
1513 copy_properties (source, t);
1514 interval_set_parent (t, parent);
1515 if (! NULL_LEFT_CHILD (source))
1516 interval_set_left (t, reproduce_tree (source->left, t));
1517 if (! NULL_RIGHT_CHILD (source))
1518 interval_set_right (t, reproduce_tree (source->right, t));
1519
1520 return t;
1521 }
1522
1523 static INTERVAL
1524 reproduce_tree_obj (INTERVAL source, Lisp_Object parent)
1525 {
1526 register INTERVAL t = make_interval ();
1527
1528 memcpy (t, source, sizeof *t);
1529 copy_properties (source, t);
1530 interval_set_object (t, parent);
1531 if (! NULL_LEFT_CHILD (source))
1532 interval_set_left (t, reproduce_tree (source->left, t));
1533 if (! NULL_RIGHT_CHILD (source))
1534 interval_set_right (t, reproduce_tree (source->right, t));
1535
1536 return t;
1537 }
1538 \f
1539 /* Insert the intervals of SOURCE into BUFFER at POSITION.
1540 LENGTH is the length of the text in SOURCE.
1541
1542 The `position' field of the SOURCE intervals is assumed to be
1543 consistent with its parent; therefore, SOURCE must be an
1544 interval tree made with copy_interval or must be the whole
1545 tree of a buffer or a string.
1546
1547 This is used in insdel.c when inserting Lisp_Strings into the
1548 buffer. The text corresponding to SOURCE is already in the buffer
1549 when this is called. The intervals of new tree are a copy of those
1550 belonging to the string being inserted; intervals are never
1551 shared.
1552
1553 If the inserted text had no intervals associated, and we don't
1554 want to inherit the surrounding text's properties, this function
1555 simply returns -- offset_intervals should handle placing the
1556 text in the correct interval, depending on the sticky bits.
1557
1558 If the inserted text had properties (intervals), then there are two
1559 cases -- either insertion happened in the middle of some interval,
1560 or between two intervals.
1561
1562 If the text goes into the middle of an interval, then new
1563 intervals are created in the middle with only the properties of
1564 the new text, *unless* the macro MERGE_INSERTIONS is true, in
1565 which case the new text has the union of its properties and those
1566 of the text into which it was inserted.
1567
1568 If the text goes between two intervals, then if neither interval
1569 had its appropriate sticky property set (front_sticky, rear_sticky),
1570 the new text has only its properties. If one of the sticky properties
1571 is set, then the new text "sticks" to that region and its properties
1572 depend on merging as above. If both the preceding and succeeding
1573 intervals to the new text are "sticky", then the new text retains
1574 only its properties, as if neither sticky property were set. Perhaps
1575 we should consider merging all three sets of properties onto the new
1576 text... */
1577
1578 void
1579 graft_intervals_into_buffer (INTERVAL source, ptrdiff_t position,
1580 ptrdiff_t length, struct buffer *buffer,
1581 int inherit)
1582 {
1583 register INTERVAL under, over, this;
1584 register INTERVAL tree;
1585 ptrdiff_t over_used;
1586
1587 tree = buffer_get_intervals (buffer);
1588
1589 /* If the new text has no properties, then with inheritance it
1590 becomes part of whatever interval it was inserted into.
1591 To prevent inheritance, we must clear out the properties
1592 of the newly inserted text. */
1593 if (!source)
1594 {
1595 Lisp_Object buf;
1596 if (!inherit && tree && length > 0)
1597 {
1598 XSETBUFFER (buf, buffer);
1599 set_text_properties_1 (make_number (position),
1600 make_number (position + length),
1601 Qnil, buf, 0);
1602 }
1603 /* Shouldn't be necessary. --Stef */
1604 buffer_balance_intervals (buffer);
1605 return;
1606 }
1607
1608 eassert (length == TOTAL_LENGTH (source));
1609
1610 if ((BUF_Z (buffer) - BUF_BEG (buffer)) == length)
1611 {
1612 /* The inserted text constitutes the whole buffer, so
1613 simply copy over the interval structure. */
1614 Lisp_Object buf;
1615
1616 XSETBUFFER (buf, buffer);
1617 buffer_set_intervals (buffer, reproduce_tree_obj (source, buf));
1618 buffer_get_intervals (buffer)->position = BUF_BEG (buffer);
1619 eassert (buffer_get_intervals (buffer)->up_obj == 1);
1620 return;
1621 }
1622 else if (!tree)
1623 {
1624 /* Create an interval tree in which to place a copy
1625 of the intervals of the inserted string. */
1626 Lisp_Object buf;
1627
1628 XSETBUFFER (buf, buffer);
1629 tree = create_root_interval (buf);
1630 }
1631 /* Paranoia -- the text has already been added, so
1632 this buffer should be of non-zero length. */
1633 eassert (TOTAL_LENGTH (tree) > 0);
1634
1635 this = under = find_interval (tree, position);
1636 eassert (under);
1637 over = find_interval (source, interval_start_pos (source));
1638
1639 /* Here for insertion in the middle of an interval.
1640 Split off an equivalent interval to the right,
1641 then don't bother with it any more. */
1642
1643 if (position > under->position)
1644 {
1645 INTERVAL end_unchanged
1646 = split_interval_left (this, position - under->position);
1647 copy_properties (under, end_unchanged);
1648 under->position = position;
1649 }
1650 else
1651 {
1652 /* This call may have some effect because previous_interval may
1653 update `position' fields of intervals. Thus, don't ignore it
1654 for the moment. Someone please tell me the truth (K.Handa). */
1655 INTERVAL prev = previous_interval (under);
1656 (void) prev;
1657 #if 0
1658 /* But, this code surely has no effect. And, anyway,
1659 END_NONSTICKY_P is unreliable now. */
1660 if (prev && !END_NONSTICKY_P (prev))
1661 prev = 0;
1662 #endif /* 0 */
1663 }
1664
1665 /* Insertion is now at beginning of UNDER. */
1666
1667 /* The inserted text "sticks" to the interval `under',
1668 which means it gets those properties.
1669 The properties of under are the result of
1670 adjust_intervals_for_insertion, so stickiness has
1671 already been taken care of. */
1672
1673 /* OVER is the interval we are copying from next.
1674 OVER_USED says how many characters' worth of OVER
1675 have already been copied into target intervals.
1676 UNDER is the next interval in the target. */
1677 over_used = 0;
1678 while (over)
1679 {
1680 /* If UNDER is longer than OVER, split it. */
1681 if (LENGTH (over) - over_used < LENGTH (under))
1682 {
1683 this = split_interval_left (under, LENGTH (over) - over_used);
1684 copy_properties (under, this);
1685 }
1686 else
1687 this = under;
1688
1689 /* THIS is now the interval to copy or merge into.
1690 OVER covers all of it. */
1691 if (inherit)
1692 merge_properties (over, this);
1693 else
1694 copy_properties (over, this);
1695
1696 /* If THIS and OVER end at the same place,
1697 advance OVER to a new source interval. */
1698 if (LENGTH (this) == LENGTH (over) - over_used)
1699 {
1700 over = next_interval (over);
1701 over_used = 0;
1702 }
1703 else
1704 /* Otherwise just record that more of OVER has been used. */
1705 over_used += LENGTH (this);
1706
1707 /* Always advance to a new target interval. */
1708 under = next_interval (this);
1709 }
1710
1711 buffer_balance_intervals (buffer);
1712 }
1713
1714 /* Get the value of property PROP from PLIST,
1715 which is the plist of an interval.
1716 We check for direct properties, for categories with property PROP,
1717 and for PROP appearing on the default-text-properties list. */
1718
1719 Lisp_Object
1720 textget (Lisp_Object plist, register Lisp_Object prop)
1721 {
1722 return lookup_char_property (plist, prop, 1);
1723 }
1724
1725 Lisp_Object
1726 lookup_char_property (Lisp_Object plist, register Lisp_Object prop, int textprop)
1727 {
1728 register Lisp_Object tail, fallback = Qnil;
1729
1730 for (tail = plist; CONSP (tail); tail = Fcdr (XCDR (tail)))
1731 {
1732 register Lisp_Object tem;
1733 tem = XCAR (tail);
1734 if (EQ (prop, tem))
1735 return Fcar (XCDR (tail));
1736 if (EQ (tem, Qcategory))
1737 {
1738 tem = Fcar (XCDR (tail));
1739 if (SYMBOLP (tem))
1740 fallback = Fget (tem, prop);
1741 }
1742 }
1743
1744 if (! NILP (fallback))
1745 return fallback;
1746 /* Check for alternative properties */
1747 tail = Fassq (prop, Vchar_property_alias_alist);
1748 if (! NILP (tail))
1749 {
1750 tail = XCDR (tail);
1751 for (; NILP (fallback) && CONSP (tail); tail = XCDR (tail))
1752 fallback = Fplist_get (plist, XCAR (tail));
1753 }
1754
1755 if (textprop && NILP (fallback) && CONSP (Vdefault_text_properties))
1756 fallback = Fplist_get (Vdefault_text_properties, prop);
1757 return fallback;
1758 }
1759
1760 \f
1761 /* Set point in BUFFER "temporarily" to CHARPOS, which corresponds to
1762 byte position BYTEPOS. */
1763
1764 void
1765 temp_set_point_both (struct buffer *buffer,
1766 ptrdiff_t charpos, ptrdiff_t bytepos)
1767 {
1768 /* In a single-byte buffer, the two positions must be equal. */
1769 if (BUF_ZV (buffer) == BUF_ZV_BYTE (buffer))
1770 eassert (charpos == bytepos);
1771
1772 eassert (charpos <= bytepos);
1773 eassert (charpos <= BUF_ZV (buffer) || BUF_BEGV (buffer) <= charpos);
1774
1775 SET_BUF_PT_BOTH (buffer, charpos, bytepos);
1776 }
1777
1778 /* Set point "temporarily", without checking any text properties. */
1779
1780 void
1781 temp_set_point (struct buffer *buffer, ptrdiff_t charpos)
1782 {
1783 temp_set_point_both (buffer, charpos,
1784 buf_charpos_to_bytepos (buffer, charpos));
1785 }
1786
1787 /* Set point in BUFFER to CHARPOS. If the target position is
1788 before an intangible character, move to an ok place. */
1789
1790 void
1791 set_point (ptrdiff_t charpos)
1792 {
1793 set_point_both (charpos, buf_charpos_to_bytepos (current_buffer, charpos));
1794 }
1795
1796 /* If there's an invisible character at position POS + TEST_OFFS in the
1797 current buffer, and the invisible property has a `stickiness' such that
1798 inserting a character at position POS would inherit the property it,
1799 return POS + ADJ, otherwise return POS. If TEST_INTANG is non-zero,
1800 then intangibility is required as well as invisibility.
1801
1802 TEST_OFFS should be either 0 or -1, and ADJ should be either 1 or -1.
1803
1804 Note that `stickiness' is determined by overlay marker insertion types,
1805 if the invisible property comes from an overlay. */
1806
1807 static ptrdiff_t
1808 adjust_for_invis_intang (ptrdiff_t pos, ptrdiff_t test_offs, ptrdiff_t adj,
1809 int test_intang)
1810 {
1811 Lisp_Object invis_propval, invis_overlay;
1812 Lisp_Object test_pos;
1813
1814 if ((adj < 0 && pos + adj < BEGV) || (adj > 0 && pos + adj > ZV))
1815 /* POS + ADJ would be beyond the buffer bounds, so do no adjustment. */
1816 return pos;
1817
1818 test_pos = make_number (pos + test_offs);
1819
1820 invis_propval
1821 = get_char_property_and_overlay (test_pos, Qinvisible, Qnil,
1822 &invis_overlay);
1823
1824 if ((!test_intang
1825 || ! NILP (Fget_char_property (test_pos, Qintangible, Qnil)))
1826 && TEXT_PROP_MEANS_INVISIBLE (invis_propval)
1827 /* This next test is true if the invisible property has a stickiness
1828 such that an insertion at POS would inherit it. */
1829 && (NILP (invis_overlay)
1830 /* Invisible property is from a text-property. */
1831 ? (text_property_stickiness (Qinvisible, make_number (pos), Qnil)
1832 == (test_offs == 0 ? 1 : -1))
1833 /* Invisible property is from an overlay. */
1834 : (test_offs == 0
1835 ? XMARKER (OVERLAY_START (invis_overlay))->insertion_type == 0
1836 : XMARKER (OVERLAY_END (invis_overlay))->insertion_type == 1)))
1837 pos += adj;
1838
1839 return pos;
1840 }
1841
1842 /* Set point in BUFFER to CHARPOS, which corresponds to byte
1843 position BYTEPOS. If the target position is
1844 before an intangible character, move to an ok place. */
1845
1846 void
1847 set_point_both (ptrdiff_t charpos, ptrdiff_t bytepos)
1848 {
1849 register INTERVAL to, from, toprev, fromprev;
1850 ptrdiff_t buffer_point;
1851 ptrdiff_t old_position = PT;
1852 /* This ensures that we move forward past intangible text when the
1853 initial position is the same as the destination, in the rare
1854 instances where this is important, e.g. in line-move-finish
1855 (simple.el). */
1856 int backwards = (charpos < old_position ? 1 : 0);
1857 int have_overlays;
1858 ptrdiff_t original_position;
1859
1860 BVAR (current_buffer, point_before_scroll) = Qnil;
1861
1862 if (charpos == PT)
1863 return;
1864
1865 /* In a single-byte buffer, the two positions must be equal. */
1866 eassert (ZV != ZV_BYTE || charpos == bytepos);
1867
1868 /* Check this now, before checking if the buffer has any intervals.
1869 That way, we can catch conditions which break this sanity check
1870 whether or not there are intervals in the buffer. */
1871 eassert (charpos <= ZV && charpos >= BEGV);
1872
1873 have_overlays = buffer_has_overlays ();
1874
1875 /* If we have no text properties and overlays,
1876 then we can do it quickly. */
1877 if (!buffer_get_intervals (current_buffer) && ! have_overlays)
1878 {
1879 temp_set_point_both (current_buffer, charpos, bytepos);
1880 return;
1881 }
1882
1883 /* Set TO to the interval containing the char after CHARPOS,
1884 and TOPREV to the interval containing the char before CHARPOS.
1885 Either one may be null. They may be equal. */
1886 to = find_interval (buffer_get_intervals (current_buffer), charpos);
1887 if (charpos == BEGV)
1888 toprev = 0;
1889 else if (to && to->position == charpos)
1890 toprev = previous_interval (to);
1891 else
1892 toprev = to;
1893
1894 buffer_point = (PT == ZV ? ZV - 1 : PT);
1895
1896 /* Set FROM to the interval containing the char after PT,
1897 and FROMPREV to the interval containing the char before PT.
1898 Either one may be null. They may be equal. */
1899 /* We could cache this and save time. */
1900 from = find_interval (buffer_get_intervals (current_buffer), buffer_point);
1901 if (buffer_point == BEGV)
1902 fromprev = 0;
1903 else if (from && from->position == PT)
1904 fromprev = previous_interval (from);
1905 else if (buffer_point != PT)
1906 fromprev = from, from = 0;
1907 else
1908 fromprev = from;
1909
1910 /* Moving within an interval. */
1911 if (to == from && toprev == fromprev && INTERVAL_VISIBLE_P (to)
1912 && ! have_overlays)
1913 {
1914 temp_set_point_both (current_buffer, charpos, bytepos);
1915 return;
1916 }
1917
1918 original_position = charpos;
1919
1920 /* If the new position is between two intangible characters
1921 with the same intangible property value,
1922 move forward or backward until a change in that property. */
1923 if (NILP (Vinhibit_point_motion_hooks)
1924 && ((to && toprev)
1925 || have_overlays)
1926 /* Intangibility never stops us from positioning at the beginning
1927 or end of the buffer, so don't bother checking in that case. */
1928 && charpos != BEGV && charpos != ZV)
1929 {
1930 Lisp_Object pos;
1931 Lisp_Object intangible_propval;
1932
1933 if (backwards)
1934 {
1935 /* If the preceding character is both intangible and invisible,
1936 and the invisible property is `rear-sticky', perturb it so
1937 that the search starts one character earlier -- this ensures
1938 that point can never move to the end of an invisible/
1939 intangible/rear-sticky region. */
1940 charpos = adjust_for_invis_intang (charpos, -1, -1, 1);
1941
1942 XSETINT (pos, charpos);
1943
1944 /* If following char is intangible,
1945 skip back over all chars with matching intangible property. */
1946
1947 intangible_propval = Fget_char_property (pos, Qintangible, Qnil);
1948
1949 if (! NILP (intangible_propval))
1950 {
1951 while (XINT (pos) > BEGV
1952 && EQ (Fget_char_property (make_number (XINT (pos) - 1),
1953 Qintangible, Qnil),
1954 intangible_propval))
1955 pos = Fprevious_char_property_change (pos, Qnil);
1956
1957 /* Set CHARPOS from POS, and if the final intangible character
1958 that we skipped over is also invisible, and the invisible
1959 property is `front-sticky', perturb it to be one character
1960 earlier -- this ensures that point can never move to the
1961 beginning of an invisible/intangible/front-sticky region. */
1962 charpos = adjust_for_invis_intang (XINT (pos), 0, -1, 0);
1963 }
1964 }
1965 else
1966 {
1967 /* If the following character is both intangible and invisible,
1968 and the invisible property is `front-sticky', perturb it so
1969 that the search starts one character later -- this ensures
1970 that point can never move to the beginning of an
1971 invisible/intangible/front-sticky region. */
1972 charpos = adjust_for_invis_intang (charpos, 0, 1, 1);
1973
1974 XSETINT (pos, charpos);
1975
1976 /* If preceding char is intangible,
1977 skip forward over all chars with matching intangible property. */
1978
1979 intangible_propval = Fget_char_property (make_number (charpos - 1),
1980 Qintangible, Qnil);
1981
1982 if (! NILP (intangible_propval))
1983 {
1984 while (XINT (pos) < ZV
1985 && EQ (Fget_char_property (pos, Qintangible, Qnil),
1986 intangible_propval))
1987 pos = Fnext_char_property_change (pos, Qnil);
1988
1989 /* Set CHARPOS from POS, and if the final intangible character
1990 that we skipped over is also invisible, and the invisible
1991 property is `rear-sticky', perturb it to be one character
1992 later -- this ensures that point can never move to the
1993 end of an invisible/intangible/rear-sticky region. */
1994 charpos = adjust_for_invis_intang (XINT (pos), -1, 1, 0);
1995 }
1996 }
1997
1998 bytepos = buf_charpos_to_bytepos (current_buffer, charpos);
1999 }
2000
2001 if (charpos != original_position)
2002 {
2003 /* Set TO to the interval containing the char after CHARPOS,
2004 and TOPREV to the interval containing the char before CHARPOS.
2005 Either one may be null. They may be equal. */
2006 to = find_interval (buffer_get_intervals (current_buffer), charpos);
2007 if (charpos == BEGV)
2008 toprev = 0;
2009 else if (to && to->position == charpos)
2010 toprev = previous_interval (to);
2011 else
2012 toprev = to;
2013 }
2014
2015 /* Here TO is the interval after the stopping point
2016 and TOPREV is the interval before the stopping point.
2017 One or the other may be null. */
2018
2019 temp_set_point_both (current_buffer, charpos, bytepos);
2020
2021 /* We run point-left and point-entered hooks here, if the
2022 two intervals are not equivalent. These hooks take
2023 (old_point, new_point) as arguments. */
2024 if (NILP (Vinhibit_point_motion_hooks)
2025 && (! intervals_equal (from, to)
2026 || ! intervals_equal (fromprev, toprev)))
2027 {
2028 Lisp_Object leave_after, leave_before, enter_after, enter_before;
2029
2030 if (fromprev)
2031 leave_before = textget (fromprev->plist, Qpoint_left);
2032 else
2033 leave_before = Qnil;
2034
2035 if (from)
2036 leave_after = textget (from->plist, Qpoint_left);
2037 else
2038 leave_after = Qnil;
2039
2040 if (toprev)
2041 enter_before = textget (toprev->plist, Qpoint_entered);
2042 else
2043 enter_before = Qnil;
2044
2045 if (to)
2046 enter_after = textget (to->plist, Qpoint_entered);
2047 else
2048 enter_after = Qnil;
2049
2050 if (! EQ (leave_before, enter_before) && !NILP (leave_before))
2051 call2 (leave_before, make_number (old_position),
2052 make_number (charpos));
2053 if (! EQ (leave_after, enter_after) && !NILP (leave_after))
2054 call2 (leave_after, make_number (old_position),
2055 make_number (charpos));
2056
2057 if (! EQ (enter_before, leave_before) && !NILP (enter_before))
2058 call2 (enter_before, make_number (old_position),
2059 make_number (charpos));
2060 if (! EQ (enter_after, leave_after) && !NILP (enter_after))
2061 call2 (enter_after, make_number (old_position),
2062 make_number (charpos));
2063 }
2064 }
2065 \f
2066 /* Move point to POSITION, unless POSITION is inside an intangible
2067 segment that reaches all the way to point. */
2068
2069 void
2070 move_if_not_intangible (ptrdiff_t position)
2071 {
2072 Lisp_Object pos;
2073 Lisp_Object intangible_propval;
2074
2075 XSETINT (pos, position);
2076
2077 if (! NILP (Vinhibit_point_motion_hooks))
2078 /* If intangible is inhibited, always move point to POSITION. */
2079 ;
2080 else if (PT < position && XINT (pos) < ZV)
2081 {
2082 /* We want to move forward, so check the text before POSITION. */
2083
2084 intangible_propval = Fget_char_property (pos,
2085 Qintangible, Qnil);
2086
2087 /* If following char is intangible,
2088 skip back over all chars with matching intangible property. */
2089 if (! NILP (intangible_propval))
2090 while (XINT (pos) > BEGV
2091 && EQ (Fget_char_property (make_number (XINT (pos) - 1),
2092 Qintangible, Qnil),
2093 intangible_propval))
2094 pos = Fprevious_char_property_change (pos, Qnil);
2095 }
2096 else if (XINT (pos) > BEGV)
2097 {
2098 /* We want to move backward, so check the text after POSITION. */
2099
2100 intangible_propval = Fget_char_property (make_number (XINT (pos) - 1),
2101 Qintangible, Qnil);
2102
2103 /* If following char is intangible,
2104 skip forward over all chars with matching intangible property. */
2105 if (! NILP (intangible_propval))
2106 while (XINT (pos) < ZV
2107 && EQ (Fget_char_property (pos, Qintangible, Qnil),
2108 intangible_propval))
2109 pos = Fnext_char_property_change (pos, Qnil);
2110
2111 }
2112 else if (position < BEGV)
2113 position = BEGV;
2114 else if (position > ZV)
2115 position = ZV;
2116
2117 /* If the whole stretch between PT and POSITION isn't intangible,
2118 try moving to POSITION (which means we actually move farther
2119 if POSITION is inside of intangible text). */
2120
2121 if (XINT (pos) != PT)
2122 SET_PT (position);
2123 }
2124 \f
2125 /* If text at position POS has property PROP, set *VAL to the property
2126 value, *START and *END to the beginning and end of a region that
2127 has the same property, and return 1. Otherwise return 0.
2128
2129 OBJECT is the string or buffer to look for the property in;
2130 nil means the current buffer. */
2131
2132 int
2133 get_property_and_range (ptrdiff_t pos, Lisp_Object prop, Lisp_Object *val,
2134 ptrdiff_t *start, ptrdiff_t *end, Lisp_Object object)
2135 {
2136 INTERVAL i, prev, next;
2137
2138 if (NILP (object))
2139 i = find_interval (buffer_get_intervals (current_buffer), pos);
2140 else if (BUFFERP (object))
2141 i = find_interval (buffer_get_intervals (XBUFFER (object)), pos);
2142 else if (STRINGP (object))
2143 i = find_interval (string_get_intervals (object), pos);
2144 else
2145 abort ();
2146
2147 if (!i || (i->position + LENGTH (i) <= pos))
2148 return 0;
2149 *val = textget (i->plist, prop);
2150 if (NILP (*val))
2151 return 0;
2152
2153 next = i; /* remember it in advance */
2154 prev = previous_interval (i);
2155 while (prev
2156 && EQ (*val, textget (prev->plist, prop)))
2157 i = prev, prev = previous_interval (prev);
2158 *start = i->position;
2159
2160 next = next_interval (i);
2161 while (next && EQ (*val, textget (next->plist, prop)))
2162 i = next, next = next_interval (next);
2163 *end = i->position + LENGTH (i);
2164
2165 return 1;
2166 }
2167 \f
2168 /* Return the proper local keymap TYPE for position POSITION in
2169 BUFFER; TYPE should be one of `keymap' or `local-map'. Use the map
2170 specified by the PROP property, if any. Otherwise, if TYPE is
2171 `local-map' use BUFFER's local map.
2172
2173 POSITION must be in the accessible part of BUFFER. */
2174
2175 Lisp_Object
2176 get_local_map (register ptrdiff_t position, register struct buffer *buffer,
2177 Lisp_Object type)
2178 {
2179 Lisp_Object prop, lispy_position, lispy_buffer;
2180 ptrdiff_t old_begv, old_zv, old_begv_byte, old_zv_byte;
2181
2182 /* Perhaps we should just change `position' to the limit. */
2183 if (position > BUF_ZV (buffer) || position < BUF_BEGV (buffer))
2184 abort ();
2185
2186 /* Ignore narrowing, so that a local map continues to be valid even if
2187 the visible region contains no characters and hence no properties. */
2188 old_begv = BUF_BEGV (buffer);
2189 old_zv = BUF_ZV (buffer);
2190 old_begv_byte = BUF_BEGV_BYTE (buffer);
2191 old_zv_byte = BUF_ZV_BYTE (buffer);
2192
2193 SET_BUF_BEGV_BOTH (buffer, BUF_BEG (buffer), BUF_BEG_BYTE (buffer));
2194 SET_BUF_ZV_BOTH (buffer, BUF_Z (buffer), BUF_Z_BYTE (buffer));
2195
2196 XSETFASTINT (lispy_position, position);
2197 XSETBUFFER (lispy_buffer, buffer);
2198 /* First check if the CHAR has any property. This is because when
2199 we click with the mouse, the mouse pointer is really pointing
2200 to the CHAR after POS. */
2201 prop = Fget_char_property (lispy_position, type, lispy_buffer);
2202 /* If not, look at the POS's properties. This is necessary because when
2203 editing a field with a `local-map' property, we want insertion at the end
2204 to obey the `local-map' property. */
2205 if (NILP (prop))
2206 prop = get_pos_property (lispy_position, type, lispy_buffer);
2207
2208 SET_BUF_BEGV_BOTH (buffer, old_begv, old_begv_byte);
2209 SET_BUF_ZV_BOTH (buffer, old_zv, old_zv_byte);
2210
2211 /* Use the local map only if it is valid. */
2212 prop = get_keymap (prop, 0, 0);
2213 if (CONSP (prop))
2214 return prop;
2215
2216 if (EQ (type, Qkeymap))
2217 return Qnil;
2218 else
2219 return BVAR (buffer, keymap);
2220 }
2221 \f
2222 /* Produce an interval tree reflecting the intervals in
2223 TREE from START to START + LENGTH.
2224 The new interval tree has no parent and has a starting-position of 0. */
2225
2226 INTERVAL
2227 copy_intervals (INTERVAL tree, ptrdiff_t start, ptrdiff_t length)
2228 {
2229 register INTERVAL i, new, t;
2230 register ptrdiff_t got, prevlen;
2231
2232 if (!tree || length <= 0)
2233 return NULL;
2234
2235 i = find_interval (tree, start);
2236 eassert (i && LENGTH (i) > 0);
2237
2238 /* If there is only one interval and it's the default, return nil. */
2239 if ((start - i->position + 1 + length) < LENGTH (i)
2240 && DEFAULT_INTERVAL_P (i))
2241 return NULL;
2242
2243 new = make_interval ();
2244 new->position = 0;
2245 got = (LENGTH (i) - (start - i->position));
2246 new->total_length = length;
2247 eassert (0 <= TOTAL_LENGTH (new));
2248 copy_properties (i, new);
2249
2250 t = new;
2251 prevlen = got;
2252 while (got < length)
2253 {
2254 i = next_interval (i);
2255 t = split_interval_right (t, prevlen);
2256 copy_properties (i, t);
2257 prevlen = LENGTH (i);
2258 got += prevlen;
2259 }
2260
2261 return balance_an_interval (new);
2262 }
2263
2264 /* Give STRING the properties of BUFFER from POSITION to LENGTH. */
2265
2266 void
2267 copy_intervals_to_string (Lisp_Object string, struct buffer *buffer,
2268 ptrdiff_t position, ptrdiff_t length)
2269 {
2270 INTERVAL interval_copy = copy_intervals (buffer_get_intervals (buffer),
2271 position, length);
2272 if (!interval_copy)
2273 return;
2274
2275 interval_set_object (interval_copy, string);
2276 string_set_intervals (string, interval_copy);
2277 }
2278 \f
2279 /* Return 1 if strings S1 and S2 have identical properties; 0 otherwise.
2280 Assume they have identical characters. */
2281
2282 int
2283 compare_string_intervals (Lisp_Object s1, Lisp_Object s2)
2284 {
2285 INTERVAL i1, i2;
2286 ptrdiff_t pos = 0;
2287 ptrdiff_t end = SCHARS (s1);
2288
2289 i1 = find_interval (string_get_intervals (s1), 0);
2290 i2 = find_interval (string_get_intervals (s2), 0);
2291
2292 while (pos < end)
2293 {
2294 /* Determine how far we can go before we reach the end of I1 or I2. */
2295 ptrdiff_t len1 = (i1 != 0 ? INTERVAL_LAST_POS (i1) : end) - pos;
2296 ptrdiff_t len2 = (i2 != 0 ? INTERVAL_LAST_POS (i2) : end) - pos;
2297 ptrdiff_t distance = min (len1, len2);
2298
2299 /* If we ever find a mismatch between the strings,
2300 they differ. */
2301 if (! intervals_equal (i1, i2))
2302 return 0;
2303
2304 /* Advance POS till the end of the shorter interval,
2305 and advance one or both interval pointers for the new position. */
2306 pos += distance;
2307 if (len1 == distance)
2308 i1 = next_interval (i1);
2309 if (len2 == distance)
2310 i2 = next_interval (i2);
2311 }
2312 return 1;
2313 }
2314 \f
2315 /* Recursively adjust interval I in the current buffer
2316 for setting enable_multibyte_characters to MULTI_FLAG.
2317 The range of interval I is START ... END in characters,
2318 START_BYTE ... END_BYTE in bytes. */
2319
2320 static void
2321 set_intervals_multibyte_1 (INTERVAL i, int multi_flag,
2322 ptrdiff_t start, ptrdiff_t start_byte,
2323 ptrdiff_t end, ptrdiff_t end_byte)
2324 {
2325 /* Fix the length of this interval. */
2326 if (multi_flag)
2327 i->total_length = end - start;
2328 else
2329 i->total_length = end_byte - start_byte;
2330 eassert (0 <= TOTAL_LENGTH (i));
2331
2332 if (TOTAL_LENGTH (i) == 0)
2333 {
2334 delete_interval (i);
2335 return;
2336 }
2337
2338 /* Recursively fix the length of the subintervals. */
2339 if (i->left)
2340 {
2341 ptrdiff_t left_end, left_end_byte;
2342
2343 if (multi_flag)
2344 {
2345 ptrdiff_t temp;
2346 left_end_byte = start_byte + LEFT_TOTAL_LENGTH (i);
2347 left_end = BYTE_TO_CHAR (left_end_byte);
2348
2349 temp = CHAR_TO_BYTE (left_end);
2350
2351 /* If LEFT_END_BYTE is in the middle of a character,
2352 adjust it and LEFT_END to a char boundary. */
2353 if (left_end_byte > temp)
2354 {
2355 left_end_byte = temp;
2356 }
2357 if (left_end_byte < temp)
2358 {
2359 left_end--;
2360 left_end_byte = CHAR_TO_BYTE (left_end);
2361 }
2362 }
2363 else
2364 {
2365 left_end = start + LEFT_TOTAL_LENGTH (i);
2366 left_end_byte = CHAR_TO_BYTE (left_end);
2367 }
2368
2369 set_intervals_multibyte_1 (i->left, multi_flag, start, start_byte,
2370 left_end, left_end_byte);
2371 }
2372 if (i->right)
2373 {
2374 ptrdiff_t right_start_byte, right_start;
2375
2376 if (multi_flag)
2377 {
2378 ptrdiff_t temp;
2379
2380 right_start_byte = end_byte - RIGHT_TOTAL_LENGTH (i);
2381 right_start = BYTE_TO_CHAR (right_start_byte);
2382
2383 /* If RIGHT_START_BYTE is in the middle of a character,
2384 adjust it and RIGHT_START to a char boundary. */
2385 temp = CHAR_TO_BYTE (right_start);
2386
2387 if (right_start_byte < temp)
2388 {
2389 right_start_byte = temp;
2390 }
2391 if (right_start_byte > temp)
2392 {
2393 right_start++;
2394 right_start_byte = CHAR_TO_BYTE (right_start);
2395 }
2396 }
2397 else
2398 {
2399 right_start = end - RIGHT_TOTAL_LENGTH (i);
2400 right_start_byte = CHAR_TO_BYTE (right_start);
2401 }
2402
2403 set_intervals_multibyte_1 (i->right, multi_flag,
2404 right_start, right_start_byte,
2405 end, end_byte);
2406 }
2407
2408 /* Rounding to char boundaries can theoretically ake this interval
2409 spurious. If so, delete one child, and copy its property list
2410 to this interval. */
2411 if (LEFT_TOTAL_LENGTH (i) + RIGHT_TOTAL_LENGTH (i) >= TOTAL_LENGTH (i))
2412 {
2413 if ((i)->left)
2414 {
2415 interval_set_plist (i, i->left->plist);
2416 (i)->left->total_length = 0;
2417 delete_interval ((i)->left);
2418 }
2419 else
2420 {
2421 interval_set_plist (i, i->right->plist);
2422 (i)->right->total_length = 0;
2423 delete_interval ((i)->right);
2424 }
2425 }
2426 }
2427
2428 /* Update the intervals of the current buffer
2429 to fit the contents as multibyte (if MULTI_FLAG is 1)
2430 or to fit them as non-multibyte (if MULTI_FLAG is 0). */
2431
2432 void
2433 set_intervals_multibyte (int multi_flag)
2434 {
2435 INTERVAL i = buffer_get_intervals (current_buffer);
2436
2437 if (i)
2438 set_intervals_multibyte_1 (i, multi_flag, BEG, BEG_BYTE, Z, Z_BYTE);
2439 }