]> code.delx.au - gnu-emacs/blob - src/intervals.c
(set_point): If Vinhibit_point_motion_hooks, ignore intangible properties.
[gnu-emacs] / src / intervals.c
1 /* Code for doing intervals.
2 Copyright (C) 1993, 1994 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 2, or (at your option)
9 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; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21 /* NOTES:
22
23 Have to ensure that we can't put symbol nil on a plist, or some
24 functions may work incorrectly.
25
26 An idea: Have the owner of the tree keep count of splits and/or
27 insertion lengths (in intervals), and balance after every N.
28
29 Need to call *_left_hook when buffer is killed.
30
31 Scan for zero-length, or 0-length to see notes about handling
32 zero length interval-markers.
33
34 There are comments around about freeing intervals. It might be
35 faster to explicitly free them (put them on the free list) than
36 to GC them.
37
38 */
39
40
41 #include <config.h>
42 #include "lisp.h"
43 #include "intervals.h"
44 #include "buffer.h"
45 #include "puresize.h"
46 #include "keyboard.h"
47
48 /* The rest of the file is within this conditional. */
49 #ifdef USE_TEXT_PROPERTIES
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 Lisp_Object merge_properties_sticky ();
57 \f
58 /* Utility functions for intervals. */
59
60
61 /* Create the root interval of some object, a buffer or string. */
62
63 INTERVAL
64 create_root_interval (parent)
65 Lisp_Object parent;
66 {
67 INTERVAL new;
68
69 CHECK_IMPURE (parent);
70
71 new = make_interval ();
72
73 if (XTYPE (parent) == Lisp_Buffer)
74 {
75 new->total_length = (BUF_Z (XBUFFER (parent))
76 - BUF_BEG (XBUFFER (parent)));
77 XBUFFER (parent)->intervals = new;
78 }
79 else if (XTYPE (parent) == Lisp_String)
80 {
81 new->total_length = XSTRING (parent)->size;
82 XSTRING (parent)->intervals = new;
83 }
84
85 new->parent = (INTERVAL) parent;
86 new->position = 1;
87
88 return new;
89 }
90
91 /* Make the interval TARGET have exactly the properties of SOURCE */
92
93 void
94 copy_properties (source, target)
95 register INTERVAL source, target;
96 {
97 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
98 return;
99
100 COPY_INTERVAL_CACHE (source, target);
101 target->plist = Fcopy_sequence (source->plist);
102 }
103
104 /* Merge the properties of interval SOURCE into the properties
105 of interval TARGET. That is to say, each property in SOURCE
106 is added to TARGET if TARGET has no such property as yet. */
107
108 static void
109 merge_properties (source, target)
110 register INTERVAL source, target;
111 {
112 register Lisp_Object o, sym, val;
113
114 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
115 return;
116
117 MERGE_INTERVAL_CACHE (source, target);
118
119 o = source->plist;
120 while (! EQ (o, Qnil))
121 {
122 sym = Fcar (o);
123 val = Fmemq (sym, target->plist);
124
125 if (NILP (val))
126 {
127 o = Fcdr (o);
128 val = Fcar (o);
129 target->plist = Fcons (sym, Fcons (val, target->plist));
130 o = Fcdr (o);
131 }
132 else
133 o = Fcdr (Fcdr (o));
134 }
135 }
136
137 /* Return 1 if the two intervals have the same properties,
138 0 otherwise. */
139
140 int
141 intervals_equal (i0, i1)
142 INTERVAL i0, i1;
143 {
144 register Lisp_Object i0_cdr, i0_sym, i1_val;
145 register i1_len;
146
147 if (DEFAULT_INTERVAL_P (i0) && DEFAULT_INTERVAL_P (i1))
148 return 1;
149
150 if (DEFAULT_INTERVAL_P (i0) || DEFAULT_INTERVAL_P (i1))
151 return 0;
152
153 i1_len = XFASTINT (Flength (i1->plist));
154 if (i1_len & 0x1) /* Paranoia -- plists are always even */
155 abort ();
156 i1_len /= 2;
157 i0_cdr = i0->plist;
158 while (!NILP (i0_cdr))
159 {
160 /* Lengths of the two plists were unequal. */
161 if (i1_len == 0)
162 return 0;
163
164 i0_sym = Fcar (i0_cdr);
165 i1_val = Fmemq (i0_sym, i1->plist);
166
167 /* i0 has something i1 doesn't. */
168 if (EQ (i1_val, Qnil))
169 return 0;
170
171 /* i0 and i1 both have sym, but it has different values in each. */
172 i0_cdr = Fcdr (i0_cdr);
173 if (! EQ (Fcar (Fcdr (i1_val)), Fcar (i0_cdr)))
174 return 0;
175
176 i0_cdr = Fcdr (i0_cdr);
177 i1_len--;
178 }
179
180 /* Lengths of the two plists were unequal. */
181 if (i1_len > 0)
182 return 0;
183
184 return 1;
185 }
186 \f
187 static int icount;
188 static int idepth;
189 static int zero_length;
190
191 /* Traverse an interval tree TREE, performing FUNCTION on each node.
192 Pass FUNCTION two args: an interval, and ARG. */
193
194 void
195 traverse_intervals (tree, position, depth, function, arg)
196 INTERVAL tree;
197 int position, depth;
198 void (* function) ();
199 Lisp_Object arg;
200 {
201 if (NULL_INTERVAL_P (tree))
202 return;
203
204 traverse_intervals (tree->left, position, depth + 1, function, arg);
205 position += LEFT_TOTAL_LENGTH (tree);
206 tree->position = position;
207 (*function) (tree, arg);
208 position += LENGTH (tree);
209 traverse_intervals (tree->right, position, depth + 1, function, arg);
210 }
211 \f
212 #if 0
213 /* These functions are temporary, for debugging purposes only. */
214
215 INTERVAL search_interval, found_interval;
216
217 void
218 check_for_interval (i)
219 register INTERVAL i;
220 {
221 if (i == search_interval)
222 {
223 found_interval = i;
224 icount++;
225 }
226 }
227
228 INTERVAL
229 search_for_interval (i, tree)
230 register INTERVAL i, tree;
231 {
232 icount = 0;
233 search_interval = i;
234 found_interval = NULL_INTERVAL;
235 traverse_intervals (tree, 1, 0, &check_for_interval, Qnil);
236 return found_interval;
237 }
238
239 static void
240 inc_interval_count (i)
241 INTERVAL i;
242 {
243 icount++;
244 if (LENGTH (i) == 0)
245 zero_length++;
246 if (depth > idepth)
247 idepth = depth;
248 }
249
250 int
251 count_intervals (i)
252 register INTERVAL i;
253 {
254 icount = 0;
255 idepth = 0;
256 zero_length = 0;
257 traverse_intervals (i, 1, 0, &inc_interval_count, Qnil);
258
259 return icount;
260 }
261
262 static INTERVAL
263 root_interval (interval)
264 INTERVAL interval;
265 {
266 register INTERVAL i = interval;
267
268 while (! ROOT_INTERVAL_P (i))
269 i = i->parent;
270
271 return i;
272 }
273 #endif
274 \f
275 /* Assuming that a left child exists, perform the following operation:
276
277 A B
278 / \ / \
279 B => A
280 / \ / \
281 c c
282 */
283
284 static INTERVAL
285 rotate_right (interval)
286 INTERVAL interval;
287 {
288 INTERVAL i;
289 INTERVAL B = interval->left;
290 int old_total = interval->total_length;
291
292 /* Deal with any Parent of A; make it point to B. */
293 if (! ROOT_INTERVAL_P (interval))
294 if (AM_LEFT_CHILD (interval))
295 interval->parent->left = B;
296 else
297 interval->parent->right = B;
298 B->parent = interval->parent;
299
300 /* Make B the parent of A */
301 i = B->right;
302 B->right = interval;
303 interval->parent = B;
304
305 /* Make A point to c */
306 interval->left = i;
307 if (! NULL_INTERVAL_P (i))
308 i->parent = interval;
309
310 /* A's total length is decreased by the length of B and its left child. */
311 interval->total_length -= B->total_length - LEFT_TOTAL_LENGTH (interval);
312
313 /* B must have the same total length of A. */
314 B->total_length = old_total;
315
316 return B;
317 }
318
319 /* Assuming that a right child exists, perform the following operation:
320
321 A B
322 / \ / \
323 B => A
324 / \ / \
325 c c
326 */
327
328 static INTERVAL
329 rotate_left (interval)
330 INTERVAL interval;
331 {
332 INTERVAL i;
333 INTERVAL B = interval->right;
334 int old_total = interval->total_length;
335
336 /* Deal with any parent of A; make it point to B. */
337 if (! ROOT_INTERVAL_P (interval))
338 if (AM_LEFT_CHILD (interval))
339 interval->parent->left = B;
340 else
341 interval->parent->right = B;
342 B->parent = interval->parent;
343
344 /* Make B the parent of A */
345 i = B->left;
346 B->left = interval;
347 interval->parent = B;
348
349 /* Make A point to c */
350 interval->right = i;
351 if (! NULL_INTERVAL_P (i))
352 i->parent = interval;
353
354 /* A's total length is decreased by the length of B and its right child. */
355 interval->total_length -= B->total_length - RIGHT_TOTAL_LENGTH (interval);
356
357 /* B must have the same total length of A. */
358 B->total_length = old_total;
359
360 return B;
361 }
362 \f
363 /* Balance an interval tree with the assumption that the subtrees
364 themselves are already balanced. */
365
366 static INTERVAL
367 balance_an_interval (i)
368 INTERVAL i;
369 {
370 register int old_diff, new_diff;
371
372 while (1)
373 {
374 old_diff = LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i);
375 if (old_diff > 0)
376 {
377 new_diff = i->total_length - i->left->total_length
378 + RIGHT_TOTAL_LENGTH (i->left) - LEFT_TOTAL_LENGTH (i->left);
379 if (abs (new_diff) >= old_diff)
380 break;
381 i = rotate_right (i);
382 balance_an_interval (i->right);
383 }
384 else if (old_diff < 0)
385 {
386 new_diff = i->total_length - i->right->total_length
387 + LEFT_TOTAL_LENGTH (i->right) - RIGHT_TOTAL_LENGTH (i->right);
388 if (abs (new_diff) >= -old_diff)
389 break;
390 i = rotate_left (i);
391 balance_an_interval (i->left);
392 }
393 else
394 break;
395 }
396 return i;
397 }
398
399 /* Balance INTERVAL, potentially stuffing it back into its parent
400 Lisp Object. */
401
402 static INLINE INTERVAL
403 balance_possible_root_interval (interval)
404 register INTERVAL interval;
405 {
406 Lisp_Object parent;
407
408 if (interval->parent == NULL_INTERVAL)
409 return interval;
410
411 parent = (Lisp_Object) (interval->parent);
412 interval = balance_an_interval (interval);
413
414 if (XTYPE (parent) == Lisp_Buffer)
415 XBUFFER (parent)->intervals = interval;
416 else if (XTYPE (parent) == Lisp_String)
417 XSTRING (parent)->intervals = interval;
418
419 return interval;
420 }
421
422 /* Balance the interval tree TREE. Balancing is by weight
423 (the amount of text). */
424
425 static INTERVAL
426 balance_intervals_internal (tree)
427 register INTERVAL tree;
428 {
429 /* Balance within each side. */
430 if (tree->left)
431 balance_intervals (tree->left);
432 if (tree->right)
433 balance_intervals (tree->right);
434 return balance_an_interval (tree);
435 }
436
437 /* Advertised interface to balance intervals. */
438
439 INTERVAL
440 balance_intervals (tree)
441 INTERVAL tree;
442 {
443 if (tree == NULL_INTERVAL)
444 return NULL_INTERVAL;
445
446 return balance_intervals_internal (tree);
447 }
448 \f
449 /* Split INTERVAL into two pieces, starting the second piece at
450 character position OFFSET (counting from 0), relative to INTERVAL.
451 INTERVAL becomes the left-hand piece, and the right-hand piece
452 (second, lexicographically) is returned.
453
454 The size and position fields of the two intervals are set based upon
455 those of the original interval. The property list of the new interval
456 is reset, thus it is up to the caller to do the right thing with the
457 result.
458
459 Note that this does not change the position of INTERVAL; if it is a root,
460 it is still a root after this operation. */
461
462 INTERVAL
463 split_interval_right (interval, offset)
464 INTERVAL interval;
465 int offset;
466 {
467 INTERVAL new = make_interval ();
468 int position = interval->position;
469 int new_length = LENGTH (interval) - offset;
470
471 new->position = position + offset;
472 new->parent = interval;
473
474 if (NULL_RIGHT_CHILD (interval))
475 {
476 interval->right = new;
477 new->total_length = new_length;
478
479 return new;
480 }
481
482 /* Insert the new node between INTERVAL and its right child. */
483 new->right = interval->right;
484 interval->right->parent = new;
485 interval->right = new;
486 new->total_length = new_length + new->right->total_length;
487
488 balance_an_interval (new);
489 balance_possible_root_interval (interval);
490
491 return new;
492 }
493
494 /* Split INTERVAL into two pieces, starting the second piece at
495 character position OFFSET (counting from 0), relative to INTERVAL.
496 INTERVAL becomes the right-hand piece, and the left-hand piece
497 (first, lexicographically) is returned.
498
499 The size and position fields of the two intervals are set based upon
500 those of the original interval. The property list of the new interval
501 is reset, thus it is up to the caller to do the right thing with the
502 result.
503
504 Note that this does not change the position of INTERVAL; if it is a root,
505 it is still a root after this operation. */
506
507 INTERVAL
508 split_interval_left (interval, offset)
509 INTERVAL interval;
510 int offset;
511 {
512 INTERVAL new = make_interval ();
513 int position = interval->position;
514 int new_length = offset;
515
516 new->position = interval->position;
517 interval->position = interval->position + offset;
518 new->parent = interval;
519
520 if (NULL_LEFT_CHILD (interval))
521 {
522 interval->left = new;
523 new->total_length = new_length;
524
525 return new;
526 }
527
528 /* Insert the new node between INTERVAL and its left child. */
529 new->left = interval->left;
530 new->left->parent = new;
531 interval->left = new;
532 new->total_length = new_length + new->left->total_length;
533
534 balance_an_interval (new);
535 balance_possible_root_interval (interval);
536
537 return new;
538 }
539 \f
540 /* Find the interval containing text position POSITION in the text
541 represented by the interval tree TREE. POSITION is a buffer
542 position; the earliest position is 1. If POSITION is at the end of
543 the buffer, return the interval containing the last character.
544
545 The `position' field, which is a cache of an interval's position,
546 is updated in the interval found. Other functions (e.g., next_interval)
547 will update this cache based on the result of find_interval. */
548
549 INLINE INTERVAL
550 find_interval (tree, position)
551 register INTERVAL tree;
552 register int position;
553 {
554 /* The distance from the left edge of the subtree at TREE
555 to POSITION. */
556 register int relative_position = position - BEG;
557
558 if (NULL_INTERVAL_P (tree))
559 return NULL_INTERVAL;
560
561 if (relative_position > TOTAL_LENGTH (tree))
562 abort (); /* Paranoia */
563
564 tree = balance_possible_root_interval (tree);
565
566 while (1)
567 {
568 if (relative_position < LEFT_TOTAL_LENGTH (tree))
569 {
570 tree = tree->left;
571 }
572 else if (! NULL_RIGHT_CHILD (tree)
573 && relative_position >= (TOTAL_LENGTH (tree)
574 - RIGHT_TOTAL_LENGTH (tree)))
575 {
576 relative_position -= (TOTAL_LENGTH (tree)
577 - RIGHT_TOTAL_LENGTH (tree));
578 tree = tree->right;
579 }
580 else
581 {
582 tree->position =
583 (position - relative_position /* the left edge of *tree */
584 + LEFT_TOTAL_LENGTH (tree)); /* the left edge of this interval */
585
586 return tree;
587 }
588 }
589 }
590 \f
591 /* Find the succeeding interval (lexicographically) to INTERVAL.
592 Sets the `position' field based on that of INTERVAL (see
593 find_interval). */
594
595 INTERVAL
596 next_interval (interval)
597 register INTERVAL interval;
598 {
599 register INTERVAL i = interval;
600 register int next_position;
601
602 if (NULL_INTERVAL_P (i))
603 return NULL_INTERVAL;
604 next_position = interval->position + LENGTH (interval);
605
606 if (! NULL_RIGHT_CHILD (i))
607 {
608 i = i->right;
609 while (! NULL_LEFT_CHILD (i))
610 i = i->left;
611
612 i->position = next_position;
613 return i;
614 }
615
616 while (! NULL_PARENT (i))
617 {
618 if (AM_LEFT_CHILD (i))
619 {
620 i = i->parent;
621 i->position = next_position;
622 return i;
623 }
624
625 i = i->parent;
626 }
627
628 return NULL_INTERVAL;
629 }
630
631 /* Find the preceding interval (lexicographically) to INTERVAL.
632 Sets the `position' field based on that of INTERVAL (see
633 find_interval). */
634
635 INTERVAL
636 previous_interval (interval)
637 register INTERVAL interval;
638 {
639 register INTERVAL i;
640 register position_of_previous;
641
642 if (NULL_INTERVAL_P (interval))
643 return NULL_INTERVAL;
644
645 if (! NULL_LEFT_CHILD (interval))
646 {
647 i = interval->left;
648 while (! NULL_RIGHT_CHILD (i))
649 i = i->right;
650
651 i->position = interval->position - LENGTH (i);
652 return i;
653 }
654
655 i = interval;
656 while (! NULL_PARENT (i))
657 {
658 if (AM_RIGHT_CHILD (i))
659 {
660 i = i->parent;
661
662 i->position = interval->position - LENGTH (i);
663 return i;
664 }
665 i = i->parent;
666 }
667
668 return NULL_INTERVAL;
669 }
670 \f
671 #if 0
672 /* Traverse a path down the interval tree TREE to the interval
673 containing POSITION, adjusting all nodes on the path for
674 an addition of LENGTH characters. Insertion between two intervals
675 (i.e., point == i->position, where i is second interval) means
676 text goes into second interval.
677
678 Modifications are needed to handle the hungry bits -- after simply
679 finding the interval at position (don't add length going down),
680 if it's the beginning of the interval, get the previous interval
681 and check the hugry bits of both. Then add the length going back up
682 to the root. */
683
684 static INTERVAL
685 adjust_intervals_for_insertion (tree, position, length)
686 INTERVAL tree;
687 int position, length;
688 {
689 register int relative_position;
690 register INTERVAL this;
691
692 if (TOTAL_LENGTH (tree) == 0) /* Paranoia */
693 abort ();
694
695 /* If inserting at point-max of a buffer, that position
696 will be out of range */
697 if (position > TOTAL_LENGTH (tree))
698 position = TOTAL_LENGTH (tree);
699 relative_position = position;
700 this = tree;
701
702 while (1)
703 {
704 if (relative_position <= LEFT_TOTAL_LENGTH (this))
705 {
706 this->total_length += length;
707 this = this->left;
708 }
709 else if (relative_position > (TOTAL_LENGTH (this)
710 - RIGHT_TOTAL_LENGTH (this)))
711 {
712 relative_position -= (TOTAL_LENGTH (this)
713 - RIGHT_TOTAL_LENGTH (this));
714 this->total_length += length;
715 this = this->right;
716 }
717 else
718 {
719 /* If we are to use zero-length intervals as buffer pointers,
720 then this code will have to change. */
721 this->total_length += length;
722 this->position = LEFT_TOTAL_LENGTH (this)
723 + position - relative_position + 1;
724 return tree;
725 }
726 }
727 }
728 #endif
729
730 /* Effect an adjustment corresponding to the addition of LENGTH characters
731 of text. Do this by finding the interval containing POSITION in the
732 interval tree TREE, and then adjusting all of its ancestors by adding
733 LENGTH to them.
734
735 If POSITION is the first character of an interval, meaning that point
736 is actually between the two intervals, make the new text belong to
737 the interval which is "sticky".
738
739 If both intervals are "sticky", then make them belong to the left-most
740 interval. Another possibility would be to create a new interval for
741 this text, and make it have the merged properties of both ends. */
742
743 static INTERVAL
744 adjust_intervals_for_insertion (tree, position, length)
745 INTERVAL tree;
746 int position, length;
747 {
748 register INTERVAL i;
749 register INTERVAL temp;
750 int eobp = 0;
751
752 if (TOTAL_LENGTH (tree) == 0) /* Paranoia */
753 abort ();
754
755 /* If inserting at point-max of a buffer, that position will be out
756 of range. Remember that buffer positions are 1-based. */
757 if (position >= BEG + TOTAL_LENGTH (tree)){
758 position = BEG + TOTAL_LENGTH (tree);
759 eobp = 1;
760 }
761
762 i = find_interval (tree, position);
763
764 /* If in middle of an interval which is not sticky either way,
765 we must not just give its properties to the insertion.
766 So split this interval at the insertion point. */
767 if (! (position == i->position || eobp)
768 && END_NONSTICKY_P (i)
769 && ! FRONT_STICKY_P (i))
770 {
771 temp = split_interval_right (i, position - i->position);
772 copy_properties (i, temp);
773 i = temp;
774 }
775
776 /* If we are positioned between intervals, check the stickiness of
777 both of them. We have to do this too, if we are at BEG or Z. */
778 if (position == i->position || eobp)
779 {
780 register INTERVAL prev;
781
782 if (position == BEG)
783 prev = 0;
784 else if (eobp)
785 {
786 prev = i;
787 i = 0;
788 }
789 else
790 prev = previous_interval (i);
791
792 /* Even if we are positioned between intervals, we default
793 to the left one if it exists. We extend it now and split
794 off a part later, if stickyness demands it. */
795 for (temp = prev ? prev : i;! NULL_INTERVAL_P (temp); temp = temp->parent)
796 {
797 temp->total_length += length;
798 temp = balance_possible_root_interval (temp);
799 }
800
801 /* If at least one interval has sticky properties,
802 we check the stickyness property by property. */
803 if (END_NONSTICKY_P (prev) || FRONT_STICKY_P (i))
804 {
805 Lisp_Object pleft, pright;
806 struct interval newi;
807
808 pleft = NULL_INTERVAL_P (prev) ? Qnil : prev->plist;
809 pright = NULL_INTERVAL_P (i) ? Qnil : i->plist;
810 newi.plist = merge_properties_sticky (pleft, pright);
811
812 if(! prev) /* i.e. position == BEG */
813 {
814 if (! intervals_equal (i, &newi))
815 {
816 i = split_interval_left (i, length);
817 i->plist = newi.plist;
818 }
819 }
820 else if (! intervals_equal (prev, &newi))
821 {
822 prev = split_interval_right (prev,
823 position - prev->position);
824 prev->plist = newi.plist;
825 if (! NULL_INTERVAL_P (i)
826 && intervals_equal (prev, i))
827 merge_interval_right (prev);
828 }
829
830 /* We will need to update the cache here later. */
831 }
832 else if (! prev && ! NILP (i->plist))
833 {
834 /* Just split off a new interval at the left.
835 Since I wasn't front-sticky, the empty plist is ok. */
836 i = split_interval_left (i, length);
837 }
838 }
839
840 /* Otherwise just extend the interval. */
841 else
842 {
843 for (temp = i; ! NULL_INTERVAL_P (temp); temp = temp->parent)
844 {
845 temp->total_length += length;
846 temp = balance_possible_root_interval (temp);
847 }
848 }
849
850 return tree;
851 }
852
853 /* Any property might be front-sticky on the left, rear-sticky on the left,
854 front-sticky on the right, or rear-sticky on the right; the 16 combinations
855 can be arranged in a matrix with rows denoting the left conditions and
856 columns denoting the right conditions:
857 _ __ _
858 _ FR FR FR FR
859 FR__ 0 1 2 3
860 _FR 4 5 6 7
861 FR 8 9 A B
862 FR C D E F
863
864 left-props = '(front-sticky (p8 p9 pa pb pc pd pe pf)
865 rear-nonsticky (p4 p5 p6 p7 p8 p9 pa pb)
866 p0 L p1 L p2 L p3 L p4 L p5 L p6 L p7 L
867 p8 L p9 L pa L pb L pc L pd L pe L pf L)
868 right-props = '(front-sticky (p2 p3 p6 p7 pa pb pe pf)
869 rear-nonsticky (p1 p2 p5 p6 p9 pa pd pe)
870 p0 R p1 R p2 R p3 R p4 R p5 R p6 R p7 R
871 p8 R p9 R pa R pb R pc R pd R pe R pf R)
872
873 We inherit from whoever has a sticky side facing us. If both sides
874 do (cases 2, 3, E, and F), then we inherit from whichever side has a
875 non-nil value for the current property. If both sides do, then we take
876 from the left.
877
878 When we inherit a property, we get its stickiness as well as its value.
879 So, when we merge the above two lists, we expect to get this:
880
881 result = '(front-sticky (p6 p7 pa pb pc pd pe pf)
882 rear-nonsticky (p6 pa)
883 p0 L p1 L p2 L p3 L p6 R p7 R
884 pa R pb R pc L pd L pe L pf L)
885
886 The optimizable special cases are:
887 left rear-nonsticky = nil, right front-sticky = nil (inherit left)
888 left rear-nonsticky = t, right front-sticky = t (inherit right)
889 left rear-nonsticky = t, right front-sticky = nil (inherit none)
890 */
891
892 Lisp_Object
893 merge_properties_sticky (pleft, pright)
894 Lisp_Object pleft, pright;
895 {
896 register Lisp_Object props, front, rear;
897 Lisp_Object lfront, lrear, rfront, rrear;
898 register Lisp_Object tail1, tail2, sym, lval, rval;
899 int use_left, use_right;
900
901 props = Qnil;
902 front = Qnil;
903 rear = Qnil;
904 lfront = textget (pleft, Qfront_sticky);
905 lrear = textget (pleft, Qrear_nonsticky);
906 rfront = textget (pright, Qfront_sticky);
907 rrear = textget (pright, Qrear_nonsticky);
908
909 /* Go through each element of PRIGHT. */
910 for (tail1 = pright; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1)))
911 {
912 sym = Fcar (tail1);
913
914 /* Sticky properties get special treatment. */
915 if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky))
916 continue;
917
918 rval = Fcar (Fcdr (tail1));
919 for (tail2 = pleft; ! NILP (tail2); tail2 = Fcdr (Fcdr (tail2)))
920 if (EQ (sym, Fcar (tail2)))
921 break;
922 lval = (NILP (tail2) ? Qnil : Fcar( Fcdr (tail2)));
923
924 use_left = ! TMEM (sym, lrear);
925 use_right = TMEM (sym, rfront);
926 if (use_left && use_right)
927 {
928 use_left = ! NILP (lval);
929 use_right = ! NILP (rval);
930 }
931 if (use_left)
932 {
933 /* We build props as (value sym ...) rather than (sym value ...)
934 because we plan to nreverse it when we're done. */
935 if (! NILP (lval))
936 props = Fcons (lval, Fcons (sym, props));
937 if (TMEM (sym, lfront))
938 front = Fcons (sym, front);
939 if (TMEM (sym, lrear))
940 rear = Fcons (sym, rear);
941 }
942 else if (use_right)
943 {
944 if (! NILP (rval))
945 props = Fcons (rval, Fcons (sym, props));
946 if (TMEM (sym, rfront))
947 front = Fcons (sym, front);
948 if (TMEM (sym, rrear))
949 rear = Fcons (sym, rear);
950 }
951 }
952
953 /* Now go through each element of PLEFT. */
954 for (tail2 = pleft; ! NILP (tail2); tail2 = Fcdr (Fcdr (tail2)))
955 {
956 sym = Fcar (tail2);
957
958 /* Sticky properties get special treatment. */
959 if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky))
960 continue;
961
962 /* If sym is in PRIGHT, we've already considered it. */
963 for (tail1 = pright; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1)))
964 if (EQ (sym, Fcar (tail1)))
965 break;
966 if (! NILP (tail1))
967 continue;
968
969 lval = Fcar (Fcdr (tail2));
970
971 /* Since rval is known to be nil in this loop, the test simplifies. */
972 if (! TMEM (sym, lrear))
973 {
974 if (! NILP (lval))
975 props = Fcons (lval, Fcons (sym, props));
976 if (TMEM (sym, lfront))
977 front = Fcons (sym, front);
978 }
979 else if (TMEM (sym, rfront))
980 {
981 /* The value is nil, but we still inherit the stickiness
982 from the right. */
983 front = Fcons (sym, front);
984 if (TMEM (sym, rrear))
985 rear = Fcons (sym, rear);
986 }
987 }
988 props = Fnreverse (props);
989 if (! NILP (rear))
990 props = Fcons (Qrear_nonsticky, Fcons (Fnreverse (rear), props));
991 if (! NILP (front))
992 props = Fcons (Qfront_sticky, Fcons (Fnreverse (front), props));
993 return props;
994 }
995
996 \f
997 /* Delete an node I from its interval tree by merging its subtrees
998 into one subtree which is then returned. Caller is responsible for
999 storing the resulting subtree into its parent. */
1000
1001 static INTERVAL
1002 delete_node (i)
1003 register INTERVAL i;
1004 {
1005 register INTERVAL migrate, this;
1006 register int migrate_amt;
1007
1008 if (NULL_INTERVAL_P (i->left))
1009 return i->right;
1010 if (NULL_INTERVAL_P (i->right))
1011 return i->left;
1012
1013 migrate = i->left;
1014 migrate_amt = i->left->total_length;
1015 this = i->right;
1016 this->total_length += migrate_amt;
1017 while (! NULL_INTERVAL_P (this->left))
1018 {
1019 this = this->left;
1020 this->total_length += migrate_amt;
1021 }
1022 this->left = migrate;
1023 migrate->parent = this;
1024
1025 return i->right;
1026 }
1027
1028 /* Delete interval I from its tree by calling `delete_node'
1029 and properly connecting the resultant subtree.
1030
1031 I is presumed to be empty; that is, no adjustments are made
1032 for the length of I. */
1033
1034 void
1035 delete_interval (i)
1036 register INTERVAL i;
1037 {
1038 register INTERVAL parent;
1039 int amt = LENGTH (i);
1040
1041 if (amt > 0) /* Only used on zero-length intervals now. */
1042 abort ();
1043
1044 if (ROOT_INTERVAL_P (i))
1045 {
1046 Lisp_Object owner;
1047 owner = (Lisp_Object) i->parent;
1048 parent = delete_node (i);
1049 if (! NULL_INTERVAL_P (parent))
1050 parent->parent = (INTERVAL) owner;
1051
1052 if (XTYPE (owner) == Lisp_Buffer)
1053 XBUFFER (owner)->intervals = parent;
1054 else if (XTYPE (owner) == Lisp_String)
1055 XSTRING (owner)->intervals = parent;
1056 else
1057 abort ();
1058
1059 return;
1060 }
1061
1062 parent = i->parent;
1063 if (AM_LEFT_CHILD (i))
1064 {
1065 parent->left = delete_node (i);
1066 if (! NULL_INTERVAL_P (parent->left))
1067 parent->left->parent = parent;
1068 }
1069 else
1070 {
1071 parent->right = delete_node (i);
1072 if (! NULL_INTERVAL_P (parent->right))
1073 parent->right->parent = parent;
1074 }
1075 }
1076 \f
1077 /* Find the interval in TREE corresponding to the relative position
1078 FROM and delete as much as possible of AMOUNT from that interval.
1079 Return the amount actually deleted, and if the interval was
1080 zeroed-out, delete that interval node from the tree.
1081
1082 Note that FROM is actually origin zero, aka relative to the
1083 leftmost edge of tree. This is appropriate since we call ourselves
1084 recursively on subtrees.
1085
1086 Do this by recursing down TREE to the interval in question, and
1087 deleting the appropriate amount of text. */
1088
1089 static int
1090 interval_deletion_adjustment (tree, from, amount)
1091 register INTERVAL tree;
1092 register int from, amount;
1093 {
1094 register int relative_position = from;
1095
1096 if (NULL_INTERVAL_P (tree))
1097 return 0;
1098
1099 /* Left branch */
1100 if (relative_position < LEFT_TOTAL_LENGTH (tree))
1101 {
1102 int subtract = interval_deletion_adjustment (tree->left,
1103 relative_position,
1104 amount);
1105 tree->total_length -= subtract;
1106 return subtract;
1107 }
1108 /* Right branch */
1109 else if (relative_position >= (TOTAL_LENGTH (tree)
1110 - RIGHT_TOTAL_LENGTH (tree)))
1111 {
1112 int subtract;
1113
1114 relative_position -= (tree->total_length
1115 - RIGHT_TOTAL_LENGTH (tree));
1116 subtract = interval_deletion_adjustment (tree->right,
1117 relative_position,
1118 amount);
1119 tree->total_length -= subtract;
1120 return subtract;
1121 }
1122 /* Here -- this node. */
1123 else
1124 {
1125 /* How much can we delete from this interval? */
1126 int my_amount = ((tree->total_length
1127 - RIGHT_TOTAL_LENGTH (tree))
1128 - relative_position);
1129
1130 if (amount > my_amount)
1131 amount = my_amount;
1132
1133 tree->total_length -= amount;
1134 if (LENGTH (tree) == 0)
1135 delete_interval (tree);
1136
1137 return amount;
1138 }
1139
1140 /* Never reach here. */
1141 }
1142
1143 /* Effect the adjustments necessary to the interval tree of BUFFER to
1144 correspond to the deletion of LENGTH characters from that buffer
1145 text. The deletion is effected at position START (which is a
1146 buffer position, i.e. origin 1). */
1147
1148 static void
1149 adjust_intervals_for_deletion (buffer, start, length)
1150 struct buffer *buffer;
1151 int start, length;
1152 {
1153 register int left_to_delete = length;
1154 register INTERVAL tree = buffer->intervals;
1155 register int deleted;
1156
1157 if (NULL_INTERVAL_P (tree))
1158 return;
1159
1160 if (start > BEG + TOTAL_LENGTH (tree)
1161 || start + length > BEG + TOTAL_LENGTH (tree))
1162 abort ();
1163
1164 if (length == TOTAL_LENGTH (tree))
1165 {
1166 buffer->intervals = NULL_INTERVAL;
1167 return;
1168 }
1169
1170 if (ONLY_INTERVAL_P (tree))
1171 {
1172 tree->total_length -= length;
1173 return;
1174 }
1175
1176 if (start > BEG + TOTAL_LENGTH (tree))
1177 start = BEG + TOTAL_LENGTH (tree);
1178 while (left_to_delete > 0)
1179 {
1180 left_to_delete -= interval_deletion_adjustment (tree, start - 1,
1181 left_to_delete);
1182 tree = buffer->intervals;
1183 if (left_to_delete == tree->total_length)
1184 {
1185 buffer->intervals = NULL_INTERVAL;
1186 return;
1187 }
1188 }
1189 }
1190 \f
1191 /* Make the adjustments necessary to the interval tree of BUFFER to
1192 represent an addition or deletion of LENGTH characters starting
1193 at position START. Addition or deletion is indicated by the sign
1194 of LENGTH. */
1195
1196 INLINE void
1197 offset_intervals (buffer, start, length)
1198 struct buffer *buffer;
1199 int start, length;
1200 {
1201 if (NULL_INTERVAL_P (buffer->intervals) || length == 0)
1202 return;
1203
1204 if (length > 0)
1205 adjust_intervals_for_insertion (buffer->intervals, start, length);
1206 else
1207 adjust_intervals_for_deletion (buffer, start, -length);
1208 }
1209 \f
1210 /* Merge interval I with its lexicographic successor. The resulting
1211 interval is returned, and has the properties of the original
1212 successor. The properties of I are lost. I is removed from the
1213 interval tree.
1214
1215 IMPORTANT:
1216 The caller must verify that this is not the last (rightmost)
1217 interval. */
1218
1219 INTERVAL
1220 merge_interval_right (i)
1221 register INTERVAL i;
1222 {
1223 register int absorb = LENGTH (i);
1224 register INTERVAL successor;
1225
1226 /* Zero out this interval. */
1227 i->total_length -= absorb;
1228
1229 /* Find the succeeding interval. */
1230 if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb
1231 as we descend. */
1232 {
1233 successor = i->right;
1234 while (! NULL_LEFT_CHILD (successor))
1235 {
1236 successor->total_length += absorb;
1237 successor = successor->left;
1238 }
1239
1240 successor->total_length += absorb;
1241 delete_interval (i);
1242 return successor;
1243 }
1244
1245 successor = i;
1246 while (! NULL_PARENT (successor)) /* It's above us. Subtract as
1247 we ascend. */
1248 {
1249 if (AM_LEFT_CHILD (successor))
1250 {
1251 successor = successor->parent;
1252 delete_interval (i);
1253 return successor;
1254 }
1255
1256 successor = successor->parent;
1257 successor->total_length -= absorb;
1258 }
1259
1260 /* This must be the rightmost or last interval and cannot
1261 be merged right. The caller should have known. */
1262 abort ();
1263 }
1264 \f
1265 /* Merge interval I with its lexicographic predecessor. The resulting
1266 interval is returned, and has the properties of the original predecessor.
1267 The properties of I are lost. Interval node I is removed from the tree.
1268
1269 IMPORTANT:
1270 The caller must verify that this is not the first (leftmost) interval. */
1271
1272 INTERVAL
1273 merge_interval_left (i)
1274 register INTERVAL i;
1275 {
1276 register int absorb = LENGTH (i);
1277 register INTERVAL predecessor;
1278
1279 /* Zero out this interval. */
1280 i->total_length -= absorb;
1281
1282 /* Find the preceding interval. */
1283 if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down,
1284 adding ABSORB as we go. */
1285 {
1286 predecessor = i->left;
1287 while (! NULL_RIGHT_CHILD (predecessor))
1288 {
1289 predecessor->total_length += absorb;
1290 predecessor = predecessor->right;
1291 }
1292
1293 predecessor->total_length += absorb;
1294 delete_interval (i);
1295 return predecessor;
1296 }
1297
1298 predecessor = i;
1299 while (! NULL_PARENT (predecessor)) /* It's above us. Go up,
1300 subtracting ABSORB. */
1301 {
1302 if (AM_RIGHT_CHILD (predecessor))
1303 {
1304 predecessor = predecessor->parent;
1305 delete_interval (i);
1306 return predecessor;
1307 }
1308
1309 predecessor = predecessor->parent;
1310 predecessor->total_length -= absorb;
1311 }
1312
1313 /* This must be the leftmost or first interval and cannot
1314 be merged left. The caller should have known. */
1315 abort ();
1316 }
1317 \f
1318 /* Make an exact copy of interval tree SOURCE which descends from
1319 PARENT. This is done by recursing through SOURCE, copying
1320 the current interval and its properties, and then adjusting
1321 the pointers of the copy. */
1322
1323 static INTERVAL
1324 reproduce_tree (source, parent)
1325 INTERVAL source, parent;
1326 {
1327 register INTERVAL t = make_interval ();
1328
1329 bcopy (source, t, INTERVAL_SIZE);
1330 copy_properties (source, t);
1331 t->parent = parent;
1332 if (! NULL_LEFT_CHILD (source))
1333 t->left = reproduce_tree (source->left, t);
1334 if (! NULL_RIGHT_CHILD (source))
1335 t->right = reproduce_tree (source->right, t);
1336
1337 return t;
1338 }
1339
1340 #if 0
1341 /* Nobody calls this. Perhaps it's a vestige of an earlier design. */
1342
1343 /* Make a new interval of length LENGTH starting at START in the
1344 group of intervals INTERVALS, which is actually an interval tree.
1345 Returns the new interval.
1346
1347 Generate an error if the new positions would overlap an existing
1348 interval. */
1349
1350 static INTERVAL
1351 make_new_interval (intervals, start, length)
1352 INTERVAL intervals;
1353 int start, length;
1354 {
1355 INTERVAL slot;
1356
1357 slot = find_interval (intervals, start);
1358 if (start + length > slot->position + LENGTH (slot))
1359 error ("Interval would overlap");
1360
1361 if (start == slot->position && length == LENGTH (slot))
1362 return slot;
1363
1364 if (slot->position == start)
1365 {
1366 /* New right node. */
1367 split_interval_right (slot, length);
1368 return slot;
1369 }
1370
1371 if (slot->position + LENGTH (slot) == start + length)
1372 {
1373 /* New left node. */
1374 split_interval_left (slot, LENGTH (slot) - length);
1375 return slot;
1376 }
1377
1378 /* Convert interval SLOT into three intervals. */
1379 split_interval_left (slot, start - slot->position);
1380 split_interval_right (slot, length);
1381 return slot;
1382 }
1383 #endif
1384 \f
1385 /* Insert the intervals of SOURCE into BUFFER at POSITION.
1386 LENGTH is the length of the text in SOURCE.
1387
1388 This is used in insdel.c when inserting Lisp_Strings into the
1389 buffer. The text corresponding to SOURCE is already in the buffer
1390 when this is called. The intervals of new tree are a copy of those
1391 belonging to the string being inserted; intervals are never
1392 shared.
1393
1394 If the inserted text had no intervals associated, and we don't
1395 want to inherit the surrounding text's properties, this function
1396 simply returns -- offset_intervals should handle placing the
1397 text in the correct interval, depending on the sticky bits.
1398
1399 If the inserted text had properties (intervals), then there are two
1400 cases -- either insertion happened in the middle of some interval,
1401 or between two intervals.
1402
1403 If the text goes into the middle of an interval, then new
1404 intervals are created in the middle with only the properties of
1405 the new text, *unless* the macro MERGE_INSERTIONS is true, in
1406 which case the new text has the union of its properties and those
1407 of the text into which it was inserted.
1408
1409 If the text goes between two intervals, then if neither interval
1410 had its appropriate sticky property set (front_sticky, rear_sticky),
1411 the new text has only its properties. If one of the sticky properties
1412 is set, then the new text "sticks" to that region and its properties
1413 depend on merging as above. If both the preceding and succeeding
1414 intervals to the new text are "sticky", then the new text retains
1415 only its properties, as if neither sticky property were set. Perhaps
1416 we should consider merging all three sets of properties onto the new
1417 text... */
1418
1419 void
1420 graft_intervals_into_buffer (source, position, length, buffer, inherit)
1421 INTERVAL source;
1422 int position, length;
1423 struct buffer *buffer;
1424 int inherit;
1425 {
1426 register INTERVAL under, over, this, prev;
1427 register INTERVAL tree = buffer->intervals;
1428 int middle;
1429
1430 /* If the new text has no properties, it becomes part of whatever
1431 interval it was inserted into. */
1432 if (NULL_INTERVAL_P (source))
1433 {
1434 Lisp_Object buf;
1435 if (!inherit && ! NULL_INTERVAL_P (tree))
1436 {
1437 XSET (buf, Lisp_Buffer, buffer);
1438 Fset_text_properties (make_number (position),
1439 make_number (position + length),
1440 Qnil, buf);
1441 }
1442 if (! NULL_INTERVAL_P (buffer->intervals))
1443 buffer->intervals = balance_an_interval (buffer->intervals);
1444 return;
1445 }
1446
1447 if (NULL_INTERVAL_P (tree))
1448 {
1449 /* The inserted text constitutes the whole buffer, so
1450 simply copy over the interval structure. */
1451 if ((BUF_Z (buffer) - BUF_BEG (buffer)) == TOTAL_LENGTH (source))
1452 {
1453 Lisp_Object buf;
1454 XSET (buf, Lisp_Buffer, buffer);
1455 buffer->intervals = reproduce_tree (source, buf);
1456 /* Explicitly free the old tree here. */
1457
1458 return;
1459 }
1460
1461 /* Create an interval tree in which to place a copy
1462 of the intervals of the inserted string. */
1463 {
1464 Lisp_Object buf;
1465 XSET (buf, Lisp_Buffer, buffer);
1466 tree = create_root_interval (buf);
1467 }
1468 }
1469 else if (TOTAL_LENGTH (tree) == TOTAL_LENGTH (source))
1470 /* If the buffer contains only the new string, but
1471 there was already some interval tree there, then it may be
1472 some zero length intervals. Eventually, do something clever
1473 about inserting properly. For now, just waste the old intervals. */
1474 {
1475 buffer->intervals = reproduce_tree (source, tree->parent);
1476 /* Explicitly free the old tree here. */
1477
1478 return;
1479 }
1480 /* Paranoia -- the text has already been added, so this buffer
1481 should be of non-zero length. */
1482 else if (TOTAL_LENGTH (tree) == 0)
1483 abort ();
1484
1485 this = under = find_interval (tree, position);
1486 if (NULL_INTERVAL_P (under)) /* Paranoia */
1487 abort ();
1488 over = find_interval (source, 1);
1489
1490 /* Here for insertion in the middle of an interval.
1491 Split off an equivalent interval to the right,
1492 then don't bother with it any more. */
1493
1494 if (position > under->position)
1495 {
1496 INTERVAL end_unchanged
1497 = split_interval_left (this, position - under->position);
1498 copy_properties (under, end_unchanged);
1499 under->position = position;
1500 prev = 0;
1501 middle = 1;
1502 }
1503 else
1504 {
1505 prev = previous_interval (under);
1506 if (prev && !END_NONSTICKY_P (prev))
1507 prev = 0;
1508 }
1509
1510 /* Insertion is now at beginning of UNDER. */
1511
1512 /* The inserted text "sticks" to the interval `under',
1513 which means it gets those properties.
1514 The properties of under are the result of
1515 adjust_intervals_for_insertion, so stickyness has
1516 already been taken care of. */
1517
1518 while (! NULL_INTERVAL_P (over))
1519 {
1520 if (LENGTH (over) < LENGTH (under))
1521 {
1522 this = split_interval_left (under, LENGTH (over));
1523 copy_properties (under, this);
1524 }
1525 else
1526 this = under;
1527 copy_properties (over, this);
1528 if (inherit)
1529 merge_properties (over, this);
1530 else
1531 copy_properties (over, this);
1532 over = next_interval (over);
1533 }
1534
1535 if (! NULL_INTERVAL_P (buffer->intervals))
1536 buffer->intervals = balance_an_interval (buffer->intervals);
1537 return;
1538 }
1539
1540 /* Get the value of property PROP from PLIST,
1541 which is the plist of an interval.
1542 We check for direct properties and for categories with property PROP. */
1543
1544 Lisp_Object
1545 textget (plist, prop)
1546 Lisp_Object plist;
1547 register Lisp_Object prop;
1548 {
1549 register Lisp_Object tail, fallback;
1550 fallback = Qnil;
1551
1552 for (tail = plist; !NILP (tail); tail = Fcdr (Fcdr (tail)))
1553 {
1554 register Lisp_Object tem;
1555 tem = Fcar (tail);
1556 if (EQ (prop, tem))
1557 return Fcar (Fcdr (tail));
1558 if (EQ (tem, Qcategory))
1559 {
1560 tem = Fcar (Fcdr (tail));
1561 if (SYMBOLP (tem))
1562 fallback = Fget (tem, prop);
1563 }
1564 }
1565
1566 return fallback;
1567 }
1568
1569 /* Get the value of property PROP from PLIST,
1570 which is the plist of an interval.
1571 We check for direct properties only! */
1572
1573 Lisp_Object
1574 textget_direct (plist, prop)
1575 Lisp_Object plist;
1576 register Lisp_Object prop;
1577 {
1578 register Lisp_Object tail;
1579
1580 for (tail = plist; !NILP (tail); tail = Fcdr (Fcdr (tail)))
1581 {
1582 if (EQ (prop, Fcar (tail)))
1583 return Fcar (Fcdr (tail));
1584 }
1585
1586 return Qnil;
1587 }
1588 \f
1589 /* Set point in BUFFER to POSITION. If the target position is
1590 before an intangible character, move to an ok place. */
1591
1592 void
1593 set_point (position, buffer)
1594 register int position;
1595 register struct buffer *buffer;
1596 {
1597 register INTERVAL to, from, toprev, fromprev, target;
1598 int buffer_point;
1599 register Lisp_Object obj;
1600 int backwards = (position < BUF_PT (buffer)) ? 1 : 0;
1601 int old_position = buffer->text.pt;
1602
1603 if (position == buffer->text.pt)
1604 return;
1605
1606 /* Check this now, before checking if the buffer has any intervals.
1607 That way, we can catch conditions which break this sanity check
1608 whether or not there are intervals in the buffer. */
1609 if (position > BUF_Z (buffer) || position < BUF_BEG (buffer))
1610 abort ();
1611
1612 if (NULL_INTERVAL_P (buffer->intervals))
1613 {
1614 buffer->text.pt = position;
1615 return;
1616 }
1617
1618 /* Set TO to the interval containing the char after POSITION,
1619 and TOPREV to the interval containing the char before POSITION.
1620 Either one may be null. They may be equal. */
1621 to = find_interval (buffer->intervals, position);
1622 if (position == BUF_BEGV (buffer))
1623 toprev = 0;
1624 else if (to->position == position)
1625 toprev = previous_interval (to);
1626 else
1627 toprev = to;
1628
1629 buffer_point = (BUF_PT (buffer) == BUF_ZV (buffer)
1630 ? BUF_ZV (buffer) - 1
1631 : BUF_PT (buffer));
1632
1633 /* Set FROM to the interval containing the char after PT,
1634 and FROMPREV to the interval containing the char before PT.
1635 Either one may be null. They may be equal. */
1636 /* We could cache this and save time. */
1637 from = find_interval (buffer->intervals, buffer_point);
1638 if (buffer_point == BUF_BEGV (buffer))
1639 fromprev = 0;
1640 else if (from->position == BUF_PT (buffer))
1641 fromprev = previous_interval (from);
1642 else if (buffer_point != BUF_PT (buffer))
1643 fromprev = from, from = 0;
1644 else
1645 fromprev = from;
1646
1647 /* Moving within an interval. */
1648 if (to == from && toprev == fromprev && INTERVAL_VISIBLE_P (to))
1649 {
1650 buffer->text.pt = position;
1651 return;
1652 }
1653
1654 /* If the new position is between two intangible characters,
1655 move forward or backward across all such characters. */
1656 if (NILP (Vinhibit_point_motion_hooks) && ! NULL_INTERVAL_P (to)
1657 && ! NULL_INTERVAL_P (toprev))
1658 {
1659 if (backwards)
1660 {
1661 /* Make sure the following character is intangible
1662 if the previous one is. */
1663 if (toprev == to
1664 || ! NILP (textget (to->plist, Qintangible)))
1665 /* Ok, that is so. Back up across intangible text. */
1666 while (! NULL_INTERVAL_P (toprev)
1667 && ! NILP (textget (toprev->plist, Qintangible)))
1668 {
1669 to = toprev;
1670 toprev = previous_interval (toprev);
1671 if (NULL_INTERVAL_P (toprev))
1672 position = BUF_BEGV (buffer);
1673 else
1674 /* This is the only line that's not
1675 dual to the following loop.
1676 That's because we want the position
1677 at the end of TOPREV. */
1678 position = to->position;
1679 }
1680 }
1681 else
1682 {
1683 /* Make sure the previous character is intangible
1684 if the following one is. */
1685 if (toprev == to
1686 || ! NILP (textget (toprev->plist, Qintangible)))
1687 /* Ok, that is so. Advance across intangible text. */
1688 while (! NULL_INTERVAL_P (to)
1689 && ! NILP (textget (to->plist, Qintangible)))
1690 {
1691 toprev = to;
1692 to = next_interval (to);
1693 if (NULL_INTERVAL_P (to))
1694 position = BUF_ZV (buffer);
1695 else
1696 position = to->position;
1697 }
1698 }
1699 /* Here TO is the interval after the stopping point
1700 and TOPREV is the interval before the stopping point.
1701 One or the other may be null. */
1702 }
1703
1704 buffer->text.pt = position;
1705
1706 /* We run point-left and point-entered hooks here, iff the
1707 two intervals are not equivalent. These hooks take
1708 (old_point, new_point) as arguments. */
1709 if (NILP (Vinhibit_point_motion_hooks)
1710 && (! intervals_equal (from, to)
1711 || ! intervals_equal (fromprev, toprev)))
1712 {
1713 Lisp_Object leave_after, leave_before, enter_after, enter_before;
1714
1715 if (fromprev)
1716 leave_after = textget (fromprev->plist, Qpoint_left);
1717 else
1718 leave_after = Qnil;
1719 if (from)
1720 leave_before = textget (from->plist, Qpoint_left);
1721 else
1722 leave_before = Qnil;
1723
1724 if (toprev)
1725 enter_after = textget (toprev->plist, Qpoint_entered);
1726 else
1727 enter_after = Qnil;
1728 if (to)
1729 enter_before = textget (to->plist, Qpoint_entered);
1730 else
1731 enter_before = Qnil;
1732
1733 if (! EQ (leave_before, enter_before) && !NILP (leave_before))
1734 call2 (leave_before, old_position, position);
1735 if (! EQ (leave_after, enter_after) && !NILP (leave_after))
1736 call2 (leave_after, old_position, position);
1737
1738 if (! EQ (enter_before, leave_before) && !NILP (enter_before))
1739 call2 (enter_before, old_position, position);
1740 if (! EQ (enter_after, leave_after) && !NILP (enter_after))
1741 call2 (enter_after, old_position, position);
1742 }
1743 }
1744
1745 /* Set point temporarily, without checking any text properties. */
1746
1747 INLINE void
1748 temp_set_point (position, buffer)
1749 int position;
1750 struct buffer *buffer;
1751 {
1752 buffer->text.pt = position;
1753 }
1754 \f
1755 /* Return the proper local map for position POSITION in BUFFER.
1756 Use the map specified by the local-map property, if any.
1757 Otherwise, use BUFFER's local map. */
1758
1759 Lisp_Object
1760 get_local_map (position, buffer)
1761 register int position;
1762 register struct buffer *buffer;
1763 {
1764 register INTERVAL interval;
1765 Lisp_Object prop, tem;
1766
1767 if (NULL_INTERVAL_P (buffer->intervals))
1768 return current_buffer->keymap;
1769
1770 /* Perhaps we should just change `position' to the limit. */
1771 if (position > BUF_Z (buffer) || position < BUF_BEG (buffer))
1772 abort ();
1773
1774 interval = find_interval (buffer->intervals, position);
1775 prop = textget (interval->plist, Qlocal_map);
1776 if (NILP (prop))
1777 return current_buffer->keymap;
1778
1779 /* Use the local map only if it is valid. */
1780 tem = Fkeymapp (prop);
1781 if (!NILP (tem))
1782 return prop;
1783
1784 return current_buffer->keymap;
1785 }
1786 \f
1787 /* Call the modification hook functions in LIST, each with START and END. */
1788
1789 static void
1790 call_mod_hooks (list, start, end)
1791 Lisp_Object list, start, end;
1792 {
1793 struct gcpro gcpro1;
1794 GCPRO1 (list);
1795 while (!NILP (list))
1796 {
1797 call2 (Fcar (list), start, end);
1798 list = Fcdr (list);
1799 }
1800 UNGCPRO;
1801 }
1802
1803 /* Check for read-only intervals and signal an error if we find one.
1804 Then check for any modification hooks in the range START up to
1805 (but not including) TO. Create a list of all these hooks in
1806 lexicographic order, eliminating consecutive extra copies of the
1807 same hook. Then call those hooks in order, with START and END - 1
1808 as arguments. */
1809
1810 void
1811 verify_interval_modification (buf, start, end)
1812 struct buffer *buf;
1813 int start, end;
1814 {
1815 register INTERVAL intervals = buf->intervals;
1816 register INTERVAL i, prev;
1817 Lisp_Object hooks;
1818 register Lisp_Object prev_mod_hooks;
1819 Lisp_Object mod_hooks;
1820 struct gcpro gcpro1;
1821
1822 hooks = Qnil;
1823 prev_mod_hooks = Qnil;
1824 mod_hooks = Qnil;
1825
1826 if (NULL_INTERVAL_P (intervals))
1827 return;
1828
1829 if (start > end)
1830 {
1831 int temp = start;
1832 start = end;
1833 end = temp;
1834 }
1835
1836 /* For an insert operation, check the two chars around the position. */
1837 if (start == end)
1838 {
1839 INTERVAL prev;
1840 Lisp_Object before, after;
1841
1842 /* Set I to the interval containing the char after START,
1843 and PREV to the interval containing the char before START.
1844 Either one may be null. They may be equal. */
1845 i = find_interval (intervals, start);
1846
1847 if (start == BUF_BEGV (buf))
1848 prev = 0;
1849 else if (i->position == start)
1850 prev = previous_interval (i);
1851 else if (i->position < start)
1852 prev = i;
1853 if (start == BUF_ZV (buf))
1854 i = 0;
1855
1856 /* If Vinhibit_read_only is set and is not a list, we can
1857 skip the read_only checks. */
1858 if (NILP (Vinhibit_read_only) || CONSP (Vinhibit_read_only))
1859 {
1860 /* If I and PREV differ we need to check for the read-only
1861 property together with its stickyness. If either I or
1862 PREV are 0, this check is all we need.
1863 We have to take special care, since read-only may be
1864 indirectly defined via the category property. */
1865 if (i != prev)
1866 {
1867 if (! NULL_INTERVAL_P (i))
1868 {
1869 after = textget (i->plist, Qread_only);
1870
1871 /* If interval I is read-only and read-only is
1872 front-sticky, inhibit insertion.
1873 Check for read-only as well as category. */
1874 if (! NILP (after)
1875 && NILP (Fmemq (after, Vinhibit_read_only)))
1876 {
1877 Lisp_Object tem;
1878
1879 tem = textget (i->plist, Qfront_sticky);
1880 if (TMEM (Qread_only, tem)
1881 || (NILP (textget_direct (i->plist, Qread_only))
1882 && TMEM (Qcategory, tem)))
1883 error ("Attempt to insert within read-only text");
1884 }
1885 }
1886
1887 if (! NULL_INTERVAL_P (prev))
1888 {
1889 before = textget (prev->plist, Qread_only);
1890
1891 /* If interval PREV is read-only and read-only isn't
1892 rear-nonsticky, inhibit insertion.
1893 Check for read-only as well as category. */
1894 if (! NILP (before)
1895 && NILP (Fmemq (before, Vinhibit_read_only)))
1896 {
1897 Lisp_Object tem;
1898
1899 tem = textget (prev->plist, Qrear_nonsticky);
1900 if (! TMEM (Qread_only, tem)
1901 && (! NILP (textget_direct (prev->plist,Qread_only))
1902 || ! TMEM (Qcategory, tem)))
1903 error ("Attempt to insert within read-only text");
1904 }
1905 }
1906 }
1907 else if (! NULL_INTERVAL_P (i))
1908 {
1909 after = textget (i->plist, Qread_only);
1910
1911 /* If interval I is read-only and read-only is
1912 front-sticky, inhibit insertion.
1913 Check for read-only as well as category. */
1914 if (! NILP (after) && NILP (Fmemq (after, Vinhibit_read_only)))
1915 {
1916 Lisp_Object tem;
1917
1918 tem = textget (i->plist, Qfront_sticky);
1919 if (TMEM (Qread_only, tem)
1920 || (NILP (textget_direct (i->plist, Qread_only))
1921 && TMEM (Qcategory, tem)))
1922 error ("Attempt to insert within read-only text");
1923
1924 tem = textget (prev->plist, Qrear_nonsticky);
1925 if (! TMEM (Qread_only, tem)
1926 && (! NILP (textget_direct (prev->plist, Qread_only))
1927 || ! TMEM (Qcategory, tem)))
1928 error ("Attempt to insert within read-only text");
1929 }
1930 }
1931 }
1932
1933 /* Run both insert hooks (just once if they're the same). */
1934 if (!NULL_INTERVAL_P (prev))
1935 prev_mod_hooks = textget (prev->plist, Qinsert_behind_hooks);
1936 if (!NULL_INTERVAL_P (i))
1937 mod_hooks = textget (i->plist, Qinsert_in_front_hooks);
1938 GCPRO1 (mod_hooks);
1939 if (! NILP (prev_mod_hooks))
1940 call_mod_hooks (prev_mod_hooks, make_number (start),
1941 make_number (end));
1942 UNGCPRO;
1943 if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
1944 call_mod_hooks (mod_hooks, make_number (start), make_number (end));
1945 }
1946 else
1947 {
1948 /* Loop over intervals on or next to START...END,
1949 collecting their hooks. */
1950
1951 i = find_interval (intervals, start);
1952 do
1953 {
1954 if (! INTERVAL_WRITABLE_P (i))
1955 error ("Attempt to modify read-only text");
1956
1957 mod_hooks = textget (i->plist, Qmodification_hooks);
1958 if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
1959 {
1960 hooks = Fcons (mod_hooks, hooks);
1961 prev_mod_hooks = mod_hooks;
1962 }
1963
1964 i = next_interval (i);
1965 }
1966 /* Keep going thru the interval containing the char before END. */
1967 while (! NULL_INTERVAL_P (i) && i->position < end);
1968
1969 GCPRO1 (hooks);
1970 hooks = Fnreverse (hooks);
1971 while (! EQ (hooks, Qnil))
1972 {
1973 call_mod_hooks (Fcar (hooks), make_number (start),
1974 make_number (end));
1975 hooks = Fcdr (hooks);
1976 }
1977 UNGCPRO;
1978 }
1979 }
1980
1981 /* Produce an interval tree reflecting the intervals in
1982 TREE from START to START + LENGTH. */
1983
1984 INTERVAL
1985 copy_intervals (tree, start, length)
1986 INTERVAL tree;
1987 int start, length;
1988 {
1989 register INTERVAL i, new, t;
1990 register int got, prevlen;
1991
1992 if (NULL_INTERVAL_P (tree) || length <= 0)
1993 return NULL_INTERVAL;
1994
1995 i = find_interval (tree, start);
1996 if (NULL_INTERVAL_P (i) || LENGTH (i) == 0)
1997 abort ();
1998
1999 /* If there is only one interval and it's the default, return nil. */
2000 if ((start - i->position + 1 + length) < LENGTH (i)
2001 && DEFAULT_INTERVAL_P (i))
2002 return NULL_INTERVAL;
2003
2004 new = make_interval ();
2005 new->position = 1;
2006 got = (LENGTH (i) - (start - i->position));
2007 new->total_length = length;
2008 copy_properties (i, new);
2009
2010 t = new;
2011 prevlen = got;
2012 while (got < length)
2013 {
2014 i = next_interval (i);
2015 t = split_interval_right (t, prevlen);
2016 copy_properties (i, t);
2017 prevlen = LENGTH (i);
2018 got += prevlen;
2019 }
2020
2021 return balance_an_interval (new);
2022 }
2023
2024 /* Give STRING the properties of BUFFER from POSITION to LENGTH. */
2025
2026 INLINE void
2027 copy_intervals_to_string (string, buffer, position, length)
2028 Lisp_Object string, buffer;
2029 int position, length;
2030 {
2031 INTERVAL interval_copy = copy_intervals (XBUFFER (buffer)->intervals,
2032 position, length);
2033 if (NULL_INTERVAL_P (interval_copy))
2034 return;
2035
2036 interval_copy->parent = (INTERVAL) string;
2037 XSTRING (string)->intervals = interval_copy;
2038 }
2039
2040 #endif /* USE_TEXT_PROPERTIES */