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