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