(X_IO_BUG): Definition deleted.
[bpt/emacs.git] / 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 before an intangible character,
1655 move forward over all such. */
1656 while (! NULL_INTERVAL_P (to)
1657 && ! NILP (textget (to->plist, Qintangible)))
1658 {
1659 toprev = to;
1660 to = next_interval (to);
1661 if (NULL_INTERVAL_P (to))
1662 position = BUF_ZV (buffer);
1663 else
1664 position = to->position;
1665 }
1666
1667 buffer->text.pt = position;
1668
1669 /* We run point-left and point-entered hooks here, iff the
1670 two intervals are not equivalent. These hooks take
1671 (old_point, new_point) as arguments. */
1672 if (NILP (Vinhibit_point_motion_hooks)
1673 && (! intervals_equal (from, to)
1674 || ! intervals_equal (fromprev, toprev)))
1675 {
1676 Lisp_Object leave_after, leave_before, enter_after, enter_before;
1677
1678 if (fromprev)
1679 leave_after = textget (fromprev->plist, Qpoint_left);
1680 else
1681 leave_after = Qnil;
1682 if (from)
1683 leave_before = textget (from->plist, Qpoint_left);
1684 else
1685 leave_before = Qnil;
1686
1687 if (toprev)
1688 enter_after = textget (toprev->plist, Qpoint_entered);
1689 else
1690 enter_after = Qnil;
1691 if (to)
1692 enter_before = textget (to->plist, Qpoint_entered);
1693 else
1694 enter_before = Qnil;
1695
1696 if (! EQ (leave_before, enter_before) && !NILP (leave_before))
1697 call2 (leave_before, old_position, position);
1698 if (! EQ (leave_after, enter_after) && !NILP (leave_after))
1699 call2 (leave_after, old_position, position);
1700
1701 if (! EQ (enter_before, leave_before) && !NILP (enter_before))
1702 call2 (enter_before, old_position, position);
1703 if (! EQ (enter_after, leave_after) && !NILP (enter_after))
1704 call2 (enter_after, old_position, position);
1705 }
1706 }
1707
1708 /* Set point temporarily, without checking any text properties. */
1709
1710 INLINE void
1711 temp_set_point (position, buffer)
1712 int position;
1713 struct buffer *buffer;
1714 {
1715 buffer->text.pt = position;
1716 }
1717 \f
1718 /* Return the proper local map for position POSITION in BUFFER.
1719 Use the map specified by the local-map property, if any.
1720 Otherwise, use BUFFER's local map. */
1721
1722 Lisp_Object
1723 get_local_map (position, buffer)
1724 register int position;
1725 register struct buffer *buffer;
1726 {
1727 register INTERVAL interval;
1728 Lisp_Object prop, tem;
1729
1730 if (NULL_INTERVAL_P (buffer->intervals))
1731 return current_buffer->keymap;
1732
1733 /* Perhaps we should just change `position' to the limit. */
1734 if (position > BUF_Z (buffer) || position < BUF_BEG (buffer))
1735 abort ();
1736
1737 interval = find_interval (buffer->intervals, position);
1738 prop = textget (interval->plist, Qlocal_map);
1739 if (NILP (prop))
1740 return current_buffer->keymap;
1741
1742 /* Use the local map only if it is valid. */
1743 tem = Fkeymapp (prop);
1744 if (!NILP (tem))
1745 return prop;
1746
1747 return current_buffer->keymap;
1748 }
1749 \f
1750 /* Call the modification hook functions in LIST, each with START and END. */
1751
1752 static void
1753 call_mod_hooks (list, start, end)
1754 Lisp_Object list, start, end;
1755 {
1756 struct gcpro gcpro1;
1757 GCPRO1 (list);
1758 while (!NILP (list))
1759 {
1760 call2 (Fcar (list), start, end);
1761 list = Fcdr (list);
1762 }
1763 UNGCPRO;
1764 }
1765
1766 /* Check for read-only intervals and signal an error if we find one.
1767 Then check for any modification hooks in the range START up to
1768 (but not including) TO. Create a list of all these hooks in
1769 lexicographic order, eliminating consecutive extra copies of the
1770 same hook. Then call those hooks in order, with START and END - 1
1771 as arguments. */
1772
1773 void
1774 verify_interval_modification (buf, start, end)
1775 struct buffer *buf;
1776 int start, end;
1777 {
1778 register INTERVAL intervals = buf->intervals;
1779 register INTERVAL i, prev;
1780 Lisp_Object hooks;
1781 register Lisp_Object prev_mod_hooks;
1782 Lisp_Object mod_hooks;
1783 struct gcpro gcpro1;
1784
1785 hooks = Qnil;
1786 prev_mod_hooks = Qnil;
1787 mod_hooks = Qnil;
1788
1789 if (NULL_INTERVAL_P (intervals))
1790 return;
1791
1792 if (start > end)
1793 {
1794 int temp = start;
1795 start = end;
1796 end = temp;
1797 }
1798
1799 /* For an insert operation, check the two chars around the position. */
1800 if (start == end)
1801 {
1802 INTERVAL prev;
1803 Lisp_Object before, after;
1804
1805 /* Set I to the interval containing the char after START,
1806 and PREV to the interval containing the char before START.
1807 Either one may be null. They may be equal. */
1808 i = find_interval (intervals, start);
1809
1810 if (start == BUF_BEGV (buf))
1811 prev = 0;
1812 else if (i->position == start)
1813 prev = previous_interval (i);
1814 else if (i->position < start)
1815 prev = i;
1816 if (start == BUF_ZV (buf))
1817 i = 0;
1818
1819 /* If Vinhibit_read_only is set and is not a list, we can
1820 skip the read_only checks. */
1821 if (NILP (Vinhibit_read_only) || CONSP (Vinhibit_read_only))
1822 {
1823 /* If I and PREV differ we need to check for the read-only
1824 property together with its stickyness. If either I or
1825 PREV are 0, this check is all we need.
1826 We have to take special care, since read-only may be
1827 indirectly defined via the category property. */
1828 if (i != prev)
1829 {
1830 if (! NULL_INTERVAL_P (i))
1831 {
1832 after = textget (i->plist, Qread_only);
1833
1834 /* If interval I is read-only and read-only is
1835 front-sticky, inhibit insertion.
1836 Check for read-only as well as category. */
1837 if (! NILP (after)
1838 && NILP (Fmemq (after, Vinhibit_read_only)))
1839 {
1840 Lisp_Object tem;
1841
1842 tem = textget (i->plist, Qfront_sticky);
1843 if (TMEM (Qread_only, tem)
1844 || (NILP (textget_direct (i->plist, Qread_only))
1845 && TMEM (Qcategory, tem)))
1846 error ("Attempt to insert within read-only text");
1847 }
1848 }
1849
1850 if (! NULL_INTERVAL_P (prev))
1851 {
1852 before = textget (prev->plist, Qread_only);
1853
1854 /* If interval PREV is read-only and read-only isn't
1855 rear-nonsticky, inhibit insertion.
1856 Check for read-only as well as category. */
1857 if (! NILP (before)
1858 && NILP (Fmemq (before, Vinhibit_read_only)))
1859 {
1860 Lisp_Object tem;
1861
1862 tem = textget (prev->plist, Qrear_nonsticky);
1863 if (! TMEM (Qread_only, tem)
1864 && (! NILP (textget_direct (prev->plist,Qread_only))
1865 || ! TMEM (Qcategory, tem)))
1866 error ("Attempt to insert within read-only text");
1867 }
1868 }
1869 }
1870 else if (! NULL_INTERVAL_P (i))
1871 {
1872 after = textget (i->plist, Qread_only);
1873
1874 /* If interval I is read-only and read-only is
1875 front-sticky, inhibit insertion.
1876 Check for read-only as well as category. */
1877 if (! NILP (after) && NILP (Fmemq (after, Vinhibit_read_only)))
1878 {
1879 Lisp_Object tem;
1880
1881 tem = textget (i->plist, Qfront_sticky);
1882 if (TMEM (Qread_only, tem)
1883 || (NILP (textget_direct (i->plist, Qread_only))
1884 && TMEM (Qcategory, tem)))
1885 error ("Attempt to insert within read-only text");
1886
1887 tem = textget (prev->plist, Qrear_nonsticky);
1888 if (! TMEM (Qread_only, tem)
1889 && (! NILP (textget_direct (prev->plist, Qread_only))
1890 || ! TMEM (Qcategory, tem)))
1891 error ("Attempt to insert within read-only text");
1892 }
1893 }
1894 }
1895
1896 /* Run both insert hooks (just once if they're the same). */
1897 if (!NULL_INTERVAL_P (prev))
1898 prev_mod_hooks = textget (prev->plist, Qinsert_behind_hooks);
1899 if (!NULL_INTERVAL_P (i))
1900 mod_hooks = textget (i->plist, Qinsert_in_front_hooks);
1901 GCPRO1 (mod_hooks);
1902 if (! NILP (prev_mod_hooks))
1903 call_mod_hooks (prev_mod_hooks, make_number (start),
1904 make_number (end));
1905 UNGCPRO;
1906 if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
1907 call_mod_hooks (mod_hooks, make_number (start), make_number (end));
1908 }
1909 else
1910 {
1911 /* Loop over intervals on or next to START...END,
1912 collecting their hooks. */
1913
1914 i = find_interval (intervals, start);
1915 do
1916 {
1917 if (! INTERVAL_WRITABLE_P (i))
1918 error ("Attempt to modify read-only text");
1919
1920 mod_hooks = textget (i->plist, Qmodification_hooks);
1921 if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
1922 {
1923 hooks = Fcons (mod_hooks, hooks);
1924 prev_mod_hooks = mod_hooks;
1925 }
1926
1927 i = next_interval (i);
1928 }
1929 /* Keep going thru the interval containing the char before END. */
1930 while (! NULL_INTERVAL_P (i) && i->position < end);
1931
1932 GCPRO1 (hooks);
1933 hooks = Fnreverse (hooks);
1934 while (! EQ (hooks, Qnil))
1935 {
1936 call_mod_hooks (Fcar (hooks), make_number (start),
1937 make_number (end));
1938 hooks = Fcdr (hooks);
1939 }
1940 UNGCPRO;
1941 }
1942 }
1943
1944 /* Produce an interval tree reflecting the intervals in
1945 TREE from START to START + LENGTH. */
1946
1947 INTERVAL
1948 copy_intervals (tree, start, length)
1949 INTERVAL tree;
1950 int start, length;
1951 {
1952 register INTERVAL i, new, t;
1953 register int got, prevlen;
1954
1955 if (NULL_INTERVAL_P (tree) || length <= 0)
1956 return NULL_INTERVAL;
1957
1958 i = find_interval (tree, start);
1959 if (NULL_INTERVAL_P (i) || LENGTH (i) == 0)
1960 abort ();
1961
1962 /* If there is only one interval and it's the default, return nil. */
1963 if ((start - i->position + 1 + length) < LENGTH (i)
1964 && DEFAULT_INTERVAL_P (i))
1965 return NULL_INTERVAL;
1966
1967 new = make_interval ();
1968 new->position = 1;
1969 got = (LENGTH (i) - (start - i->position));
1970 new->total_length = length;
1971 copy_properties (i, new);
1972
1973 t = new;
1974 prevlen = got;
1975 while (got < length)
1976 {
1977 i = next_interval (i);
1978 t = split_interval_right (t, prevlen);
1979 copy_properties (i, t);
1980 prevlen = LENGTH (i);
1981 got += prevlen;
1982 }
1983
1984 return balance_an_interval (new);
1985 }
1986
1987 /* Give STRING the properties of BUFFER from POSITION to LENGTH. */
1988
1989 INLINE void
1990 copy_intervals_to_string (string, buffer, position, length)
1991 Lisp_Object string, buffer;
1992 int position, length;
1993 {
1994 INTERVAL interval_copy = copy_intervals (XBUFFER (buffer)->intervals,
1995 position, length);
1996 if (NULL_INTERVAL_P (interval_copy))
1997 return;
1998
1999 interval_copy->parent = (INTERVAL) string;
2000 XSTRING (string)->intervals = interval_copy;
2001 }
2002
2003 #endif /* USE_TEXT_PROPERTIES */