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