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