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