diff options
| author | Richard M. Stallman | 1993-07-31 21:58:03 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1993-07-31 21:58:03 +0000 |
| commit | 7ce503fdda34ee029bb1862c71cb756db5cac791 (patch) | |
| tree | e8a4f8647d1a49e1662ec11b4df82d0012502bbf | |
| parent | 58943db0069c771583df071c58f88ece0cdf8820 (diff) | |
| download | emacs-7ce503fdda34ee029bb1862c71cb756db5cac791.tar.gz emacs-7ce503fdda34ee029bb1862c71cb756db5cac791.zip | |
(adjust_intervals_for_insertion): Handle insertion
between two unlike intervals via merge_properties_sticky.
(merge_properties_sticky): New function.
(graft_intervals_into_buffer): Leave handling of `sticky'-ness to
adjust_intervals_for_insertion, then merge properties of the
inserted text onto the old ones.
(textget_direct): New function.
(set_point): Fix calculating of fromprev.
(verify_interval_modification): Check for `read-only' property
and take its `sticky'-ness into account.
(set_point): Ignore `invisible' property unless property value is `hidden'.
| -rw-r--r-- | src/intervals.c | 442 |
1 files changed, 321 insertions, 121 deletions
diff --git a/src/intervals.c b/src/intervals.c index b39709e0b9e..42f35942137 100644 --- a/src/intervals.c +++ b/src/intervals.c | |||
| @@ -5,7 +5,7 @@ This file is part of GNU Emacs. | |||
| 5 | 5 | ||
| 6 | GNU Emacs is free software; you can redistribute it and/or modify | 6 | GNU Emacs is free software; you can redistribute it and/or modify |
| 7 | it under the terms of the GNU General Public License as published by | 7 | it under the terms of the GNU General Public License as published by |
| 8 | the Free Software Foundation; either version 1, or (at your option) | 8 | the Free Software Foundation; either version 2, or (at your option) |
| 9 | any later version. | 9 | any later version. |
| 10 | 10 | ||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | 11 | GNU Emacs is distributed in the hope that it will be useful, |
| @@ -43,16 +43,16 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |||
| 43 | #include "intervals.h" | 43 | #include "intervals.h" |
| 44 | #include "buffer.h" | 44 | #include "buffer.h" |
| 45 | 45 | ||
| 46 | /* The rest of the file is within this conditional. */ | 46 | /* The rest of the file is within this conditional. */ |
| 47 | #ifdef USE_TEXT_PROPERTIES | 47 | #ifdef USE_TEXT_PROPERTIES |
| 48 | 48 | ||
| 49 | /* Factor for weight-balancing interval trees. */ | 49 | /* Factor for weight-balancing interval trees. */ |
| 50 | Lisp_Object interval_balance_threshold; | 50 | Lisp_Object interval_balance_threshold; |
| 51 | 51 | ||
| 52 | /* Utility functions for intervals. */ | 52 | /* Utility functions for intervals. */ |
| 53 | 53 | ||
| 54 | 54 | ||
| 55 | /* Create the root interval of some object, a buffer or string. */ | 55 | /* Create the root interval of some object, a buffer or string. */ |
| 56 | 56 | ||
| 57 | INTERVAL | 57 | INTERVAL |
| 58 | create_root_interval (parent) | 58 | create_root_interval (parent) |
| @@ -125,7 +125,7 @@ merge_properties (source, target) | |||
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | /* Return 1 if the two intervals have the same properties, | 127 | /* Return 1 if the two intervals have the same properties, |
| 128 | 0 otherwise. */ | 128 | 0 otherwise. */ |
| 129 | 129 | ||
| 130 | int | 130 | int |
| 131 | intervals_equal (i0, i1) | 131 | intervals_equal (i0, i1) |
| @@ -147,27 +147,27 @@ intervals_equal (i0, i1) | |||
| 147 | i0_cdr = i0->plist; | 147 | i0_cdr = i0->plist; |
| 148 | while (!NILP (i0_cdr)) | 148 | while (!NILP (i0_cdr)) |
| 149 | { | 149 | { |
| 150 | /* Lengths of the two plists were unequal */ | 150 | /* Lengths of the two plists were unequal. */ |
| 151 | if (i1_len == 0) | 151 | if (i1_len == 0) |
| 152 | return 0; | 152 | return 0; |
| 153 | 153 | ||
| 154 | i0_sym = Fcar (i0_cdr); | 154 | i0_sym = Fcar (i0_cdr); |
| 155 | i1_val = Fmemq (i0_sym, i1->plist); | 155 | i1_val = Fmemq (i0_sym, i1->plist); |
| 156 | 156 | ||
| 157 | /* i0 has something i1 doesn't */ | 157 | /* i0 has something i1 doesn't. */ |
| 158 | if (EQ (i1_val, Qnil)) | 158 | if (EQ (i1_val, Qnil)) |
| 159 | return 0; | 159 | return 0; |
| 160 | 160 | ||
| 161 | /* i0 and i1 both have sym, but it has different values in each */ | 161 | /* i0 and i1 both have sym, but it has different values in each. */ |
| 162 | i0_cdr = Fcdr (i0_cdr); | 162 | i0_cdr = Fcdr (i0_cdr); |
| 163 | if (! EQ (i1_val, Fcar (i0_cdr))) | 163 | if (! EQ (Fcar (Fcdr (i1_val)), Fcar (i0_cdr))) |
| 164 | return 0; | 164 | return 0; |
| 165 | 165 | ||
| 166 | i0_cdr = Fcdr (i0_cdr); | 166 | i0_cdr = Fcdr (i0_cdr); |
| 167 | i1_len--; | 167 | i1_len--; |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | /* Lengths of the two plists were unequal */ | 170 | /* Lengths of the two plists were unequal. */ |
| 171 | if (i1_len > 0) | 171 | if (i1_len > 0) |
| 172 | return 0; | 172 | return 0; |
| 173 | 173 | ||
| @@ -200,7 +200,7 @@ traverse_intervals (tree, position, depth, function, arg) | |||
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | #if 0 | 202 | #if 0 |
| 203 | /* These functions are temporary, for debugging purposes only. */ | 203 | /* These functions are temporary, for debugging purposes only. */ |
| 204 | 204 | ||
| 205 | INTERVAL search_interval, found_interval; | 205 | INTERVAL search_interval, found_interval; |
| 206 | 206 | ||
| @@ -279,7 +279,7 @@ rotate_right (interval) | |||
| 279 | INTERVAL B = interval->left; | 279 | INTERVAL B = interval->left; |
| 280 | int len = LENGTH (interval); | 280 | int len = LENGTH (interval); |
| 281 | 281 | ||
| 282 | /* Deal with any Parent of A; make it point to B. */ | 282 | /* Deal with any Parent of A; make it point to B. */ |
| 283 | if (! ROOT_INTERVAL_P (interval)) | 283 | if (! ROOT_INTERVAL_P (interval)) |
| 284 | if (AM_LEFT_CHILD (interval)) | 284 | if (AM_LEFT_CHILD (interval)) |
| 285 | interval->parent->left = interval->left; | 285 | interval->parent->left = interval->left; |
| @@ -287,15 +287,15 @@ rotate_right (interval) | |||
| 287 | interval->parent->right = interval->left; | 287 | interval->parent->right = interval->left; |
| 288 | interval->left->parent = interval->parent; | 288 | interval->left->parent = interval->parent; |
| 289 | 289 | ||
| 290 | /* B gets the same length as A, since it get A's position in the tree. */ | 290 | /* B gets the same length as A, since it get A's position in the tree. */ |
| 291 | interval->left->total_length = interval->total_length; | 291 | interval->left->total_length = interval->total_length; |
| 292 | 292 | ||
| 293 | /* B becomes the parent of A. */ | 293 | /* B becomes the parent of A. */ |
| 294 | i = interval->left->right; | 294 | i = interval->left->right; |
| 295 | interval->left->right = interval; | 295 | interval->left->right = interval; |
| 296 | interval->parent = interval->left; | 296 | interval->parent = interval->left; |
| 297 | 297 | ||
| 298 | /* A gets c as left child. */ | 298 | /* A gets c as left child. */ |
| 299 | interval->left = i; | 299 | interval->left = i; |
| 300 | if (! NULL_INTERVAL_P (i)) | 300 | if (! NULL_INTERVAL_P (i)) |
| 301 | i->parent = interval; | 301 | i->parent = interval; |
| @@ -322,7 +322,7 @@ rotate_left (interval) | |||
| 322 | INTERVAL B = interval->right; | 322 | INTERVAL B = interval->right; |
| 323 | int len = LENGTH (interval); | 323 | int len = LENGTH (interval); |
| 324 | 324 | ||
| 325 | /* Deal with the parent of A. */ | 325 | /* Deal with the parent of A. */ |
| 326 | if (! ROOT_INTERVAL_P (interval)) | 326 | if (! ROOT_INTERVAL_P (interval)) |
| 327 | if (AM_LEFT_CHILD (interval)) | 327 | if (AM_LEFT_CHILD (interval)) |
| 328 | interval->parent->left = interval->right; | 328 | interval->parent->left = interval->right; |
| @@ -330,7 +330,7 @@ rotate_left (interval) | |||
| 330 | interval->parent->right = interval->right; | 330 | interval->parent->right = interval->right; |
| 331 | interval->right->parent = interval->parent; | 331 | interval->right->parent = interval->parent; |
| 332 | 332 | ||
| 333 | /* B must have the same total length of A. */ | 333 | /* B must have the same total length of A. */ |
| 334 | interval->right->total_length = interval->total_length; | 334 | interval->right->total_length = interval->total_length; |
| 335 | 335 | ||
| 336 | /* Make B the parent of A */ | 336 | /* Make B the parent of A */ |
| @@ -359,7 +359,7 @@ rotate_left (interval) | |||
| 359 | result. | 359 | result. |
| 360 | 360 | ||
| 361 | Note that this does not change the position of INTERVAL; if it is a root, | 361 | Note that this does not change the position of INTERVAL; if it is a root, |
| 362 | it is still a root after this operation. */ | 362 | it is still a root after this operation. */ |
| 363 | 363 | ||
| 364 | INTERVAL | 364 | INTERVAL |
| 365 | split_interval_right (interval, offset) | 365 | split_interval_right (interval, offset) |
| @@ -381,7 +381,7 @@ split_interval_right (interval, offset) | |||
| 381 | return new; | 381 | return new; |
| 382 | } | 382 | } |
| 383 | 383 | ||
| 384 | /* Insert the new node between INTERVAL and its right child. */ | 384 | /* Insert the new node between INTERVAL and its right child. */ |
| 385 | new->right = interval->right; | 385 | new->right = interval->right; |
| 386 | interval->right->parent = new; | 386 | interval->right->parent = new; |
| 387 | interval->right = new; | 387 | interval->right = new; |
| @@ -402,7 +402,7 @@ split_interval_right (interval, offset) | |||
| 402 | result. | 402 | result. |
| 403 | 403 | ||
| 404 | Note that this does not change the position of INTERVAL; if it is a root, | 404 | Note that this does not change the position of INTERVAL; if it is a root, |
| 405 | it is still a root after this operation. */ | 405 | it is still a root after this operation. */ |
| 406 | 406 | ||
| 407 | INTERVAL | 407 | INTERVAL |
| 408 | split_interval_left (interval, offset) | 408 | split_interval_left (interval, offset) |
| @@ -425,7 +425,7 @@ split_interval_left (interval, offset) | |||
| 425 | return new; | 425 | return new; |
| 426 | } | 426 | } |
| 427 | 427 | ||
| 428 | /* Insert the new node between INTERVAL and its left child. */ | 428 | /* Insert the new node between INTERVAL and its left child. */ |
| 429 | new->left = interval->left; | 429 | new->left = interval->left; |
| 430 | new->left->parent = new; | 430 | new->left->parent = new; |
| 431 | interval->left = new; | 431 | interval->left = new; |
| @@ -441,7 +441,7 @@ split_interval_left (interval, offset) | |||
| 441 | 441 | ||
| 442 | The `position' field, which is a cache of an interval's position, | 442 | The `position' field, which is a cache of an interval's position, |
| 443 | is updated in the interval found. Other functions (e.g., next_interval) | 443 | is updated in the interval found. Other functions (e.g., next_interval) |
| 444 | will update this cache based on the result of find_interval. */ | 444 | will update this cache based on the result of find_interval. */ |
| 445 | 445 | ||
| 446 | INLINE INTERVAL | 446 | INLINE INTERVAL |
| 447 | find_interval (tree, position) | 447 | find_interval (tree, position) |
| @@ -485,7 +485,7 @@ find_interval (tree, position) | |||
| 485 | 485 | ||
| 486 | /* Find the succeeding interval (lexicographically) to INTERVAL. | 486 | /* Find the succeeding interval (lexicographically) to INTERVAL. |
| 487 | Sets the `position' field based on that of INTERVAL (see | 487 | Sets the `position' field based on that of INTERVAL (see |
| 488 | find_interval). */ | 488 | find_interval). */ |
| 489 | 489 | ||
| 490 | INTERVAL | 490 | INTERVAL |
| 491 | next_interval (interval) | 491 | next_interval (interval) |
| @@ -525,7 +525,7 @@ next_interval (interval) | |||
| 525 | 525 | ||
| 526 | /* Find the preceding interval (lexicographically) to INTERVAL. | 526 | /* Find the preceding interval (lexicographically) to INTERVAL. |
| 527 | Sets the `position' field based on that of INTERVAL (see | 527 | Sets the `position' field based on that of INTERVAL (see |
| 528 | find_interval). */ | 528 | find_interval). */ |
| 529 | 529 | ||
| 530 | INTERVAL | 530 | INTERVAL |
| 531 | previous_interval (interval) | 531 | previous_interval (interval) |
| @@ -574,7 +574,7 @@ previous_interval (interval) | |||
| 574 | finding the interval at position (don't add length going down), | 574 | finding the interval at position (don't add length going down), |
| 575 | if it's the beginning of the interval, get the previous interval | 575 | if it's the beginning of the interval, get the previous interval |
| 576 | and check the hugry bits of both. Then add the length going back up | 576 | and check the hugry bits of both. Then add the length going back up |
| 577 | to the root. */ | 577 | to the root. */ |
| 578 | 578 | ||
| 579 | static INTERVAL | 579 | static INTERVAL |
| 580 | adjust_intervals_for_insertion (tree, position, length) | 580 | adjust_intervals_for_insertion (tree, position, length) |
| @@ -612,7 +612,7 @@ adjust_intervals_for_insertion (tree, position, length) | |||
| 612 | else | 612 | else |
| 613 | { | 613 | { |
| 614 | /* If we are to use zero-length intervals as buffer pointers, | 614 | /* If we are to use zero-length intervals as buffer pointers, |
| 615 | then this code will have to change. */ | 615 | then this code will have to change. */ |
| 616 | this->total_length += length; | 616 | this->total_length += length; |
| 617 | this->position = LEFT_TOTAL_LENGTH (this) | 617 | this->position = LEFT_TOTAL_LENGTH (this) |
| 618 | + position - relative_position + 1; | 618 | + position - relative_position + 1; |
| @@ -633,7 +633,7 @@ adjust_intervals_for_insertion (tree, position, length) | |||
| 633 | 633 | ||
| 634 | If both intervals are "sticky", then make them belong to the left-most | 634 | If both intervals are "sticky", then make them belong to the left-most |
| 635 | interval. Another possibility would be to create a new interval for | 635 | interval. Another possibility would be to create a new interval for |
| 636 | this text, and make it have the merged properties of both ends. */ | 636 | this text, and make it have the merged properties of both ends. */ |
| 637 | 637 | ||
| 638 | static INTERVAL | 638 | static INTERVAL |
| 639 | adjust_intervals_for_insertion (tree, position, length) | 639 | adjust_intervals_for_insertion (tree, position, length) |
| @@ -641,42 +641,179 @@ adjust_intervals_for_insertion (tree, position, length) | |||
| 641 | int position, length; | 641 | int position, length; |
| 642 | { | 642 | { |
| 643 | register INTERVAL i; | 643 | register INTERVAL i; |
| 644 | 644 | register INTERVAL temp; | |
| 645 | int eobp = 0; | ||
| 646 | |||
| 645 | if (TOTAL_LENGTH (tree) == 0) /* Paranoia */ | 647 | if (TOTAL_LENGTH (tree) == 0) /* Paranoia */ |
| 646 | abort (); | 648 | abort (); |
| 647 | 649 | ||
| 648 | /* If inserting at point-max of a buffer, that position will be out | 650 | /* If inserting at point-max of a buffer, that position will be out |
| 649 | of range. Remember that buffer positions are 1-based. */ | 651 | of range. Remember that buffer positions are 1-based. */ |
| 650 | if (position > BEG + TOTAL_LENGTH (tree)) | 652 | if (position >= BEG + TOTAL_LENGTH (tree)){ |
| 651 | position = BEG + TOTAL_LENGTH (tree); | 653 | position = BEG + TOTAL_LENGTH (tree); |
| 654 | eobp = 1; | ||
| 655 | } | ||
| 652 | 656 | ||
| 653 | i = find_interval (tree, position); | 657 | i = find_interval (tree, position); |
| 658 | |||
| 654 | /* If we are positioned between intervals, check the stickiness of | 659 | /* If we are positioned between intervals, check the stickiness of |
| 655 | both of them. */ | 660 | both of them. We have to do this too, if we are at BEG or Z. */ |
| 656 | if (position == i->position | 661 | if (position == i->position || eobp) |
| 657 | && position != BEG) | ||
| 658 | { | 662 | { |
| 659 | register INTERVAL prev = previous_interval (i); | 663 | register INTERVAL prev; |
| 664 | |||
| 665 | if (position == BEG) | ||
| 666 | prev = 0; | ||
| 667 | else if (eobp) | ||
| 668 | { | ||
| 669 | prev = i; | ||
| 670 | i = 0; | ||
| 671 | } | ||
| 672 | else | ||
| 673 | prev = previous_interval (i); | ||
| 660 | 674 | ||
| 661 | /* If both intervals are sticky here, then default to the | 675 | /* Even if we are positioned between intervals, we default |
| 662 | left-most one. But perhaps we should create a new | 676 | to the left one if it exists. We extend it now and split |
| 663 | interval here instead... */ | 677 | off a part later, if stickyness demands it. */ |
| 664 | if (END_STICKY_P (prev) || ! FRONT_STICKY_P (i)) | 678 | for (temp = prev ? prev : i; ! NULL_INTERVAL_P (temp); temp = temp->parent) |
| 665 | i = prev; | 679 | temp->total_length += length; |
| 680 | |||
| 681 | /* If at least one interval has sticky properties, | ||
| 682 | we check the stickyness property by property. */ | ||
| 683 | if (END_NONSTICKY_P (prev) || FRONT_STICKY_P (i)) | ||
| 684 | { | ||
| 685 | Lisp_Object pleft = NULL_INTERVAL_P (prev) ? Qnil : prev->plist; | ||
| 686 | Lisp_Object pright = NULL_INTERVAL_P (i) ? Qnil : i->plist; | ||
| 687 | struct interval newi; | ||
| 688 | |||
| 689 | newi.plist = merge_properties_sticky (pleft, pright); | ||
| 690 | |||
| 691 | if(! prev) /* i.e. position == BEG */ | ||
| 692 | { | ||
| 693 | if (! intervals_equal (i, &newi)) | ||
| 694 | { | ||
| 695 | i = split_interval_left (i, length); | ||
| 696 | i->plist = newi.plist; | ||
| 697 | } | ||
| 698 | } | ||
| 699 | else if (! intervals_equal (prev, &newi)) | ||
| 700 | { | ||
| 701 | prev = split_interval_right (prev, | ||
| 702 | position - prev->position); | ||
| 703 | prev->plist = newi.plist; | ||
| 704 | if (! NULL_INTERVAL_P (i) | ||
| 705 | && intervals_equal (prev, i)) | ||
| 706 | merge_interval_right (prev); | ||
| 707 | } | ||
| 708 | |||
| 709 | /* We will need to update the cache here later. */ | ||
| 710 | } | ||
| 711 | else if (! prev && ! NILP (i->plist)) | ||
| 712 | { | ||
| 713 | /* Just split off a new interval at the left. | ||
| 714 | Since I wasn't front-sticky, the empty plist is ok. */ | ||
| 715 | i = split_interval_left (i, length); | ||
| 716 | } | ||
| 666 | } | 717 | } |
| 667 | 718 | ||
| 668 | while (! NULL_INTERVAL_P (i)) | 719 | /* Otherwise just extend the interval. */ |
| 720 | else | ||
| 669 | { | 721 | { |
| 670 | i->total_length += length; | 722 | for (temp = i; ! NULL_INTERVAL_P (temp); temp = temp->parent) |
| 671 | i = i->parent; | 723 | temp->total_length += length; |
| 672 | } | 724 | } |
| 673 | 725 | ||
| 674 | return tree; | 726 | return tree; |
| 675 | } | 727 | } |
| 728 | |||
| 729 | Lisp_Object | ||
| 730 | merge_properties_sticky (pleft, pright) | ||
| 731 | Lisp_Object pleft, pright; | ||
| 732 | { | ||
| 733 | register Lisp_Object props = Qnil, front = Qnil, rear = Qnil; | ||
| 734 | |||
| 735 | Lisp_Object lfront = textget (pleft, Qfront_sticky); | ||
| 736 | Lisp_Object lrear = textget (pleft, Qrear_nonsticky); | ||
| 737 | Lisp_Object rfront = textget (pright, Qfront_sticky); | ||
| 738 | Lisp_Object rrear = textget (pright, Qrear_nonsticky); | ||
| 739 | |||
| 740 | register Lisp_Object tail1, tail2, sym; | ||
| 741 | |||
| 742 | /* Go through each element of PLEFT. */ | ||
| 743 | for (tail1 = pleft; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1))) | ||
| 744 | { | ||
| 745 | sym = Fcar (tail1); | ||
| 746 | |||
| 747 | /* Sticky properties get special treatment. */ | ||
| 748 | if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky)) | ||
| 749 | continue; | ||
| 750 | |||
| 751 | if (NILP (Fmemq (sym, lrear))) | ||
| 752 | { | ||
| 753 | /* rear-sticky is dominant, we needn't search in PRIGHT. */ | ||
| 754 | |||
| 755 | props = Fcons (sym, Fcons (Fcar (Fcdr (tail1)), props)); | ||
| 756 | if (! NILP (Fmemq (sym, lfront))) | ||
| 757 | front = Fcons (sym, front); | ||
| 758 | } | ||
| 759 | else | ||
| 760 | { | ||
| 761 | /* Go through PRIGHT, looking for sym. */ | ||
| 762 | for (tail2 = pright; ! NILP (tail2); tail2 = Fcdr (Fcdr (tail2))) | ||
| 763 | if (EQ (sym, Fcar (tail2))) | ||
| 764 | { | ||
| 765 | |||
| 766 | if (! NILP (Fmemq (sym, rfront))) | ||
| 767 | { | ||
| 768 | /* Nonsticky at the left and sticky at the right, | ||
| 769 | so take the right one. */ | ||
| 770 | props = Fcons (sym, Fcons (Fcar (Fcdr (tail2)), props)); | ||
| 771 | front = Fcons (sym, front); | ||
| 772 | if (! NILP (Fmemq (sym, rrear))) | ||
| 773 | rear = Fcons (sym, rear); | ||
| 774 | } | ||
| 775 | break; | ||
| 776 | } | ||
| 777 | } | ||
| 778 | } | ||
| 779 | /* Now let's see what to keep from PRIGHT. */ | ||
| 780 | for (tail2 = pright; ! NILP (tail2); tail2 = Fcdr (Fcdr (tail2))) | ||
| 781 | { | ||
| 782 | sym = Fcar (tail2); | ||
| 783 | |||
| 784 | /* Sticky properties get special treatment. */ | ||
| 785 | if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky)) | ||
| 786 | continue; | ||
| 787 | |||
| 788 | /* If it ain't sticky, we don't take it. */ | ||
| 789 | if (NILP (Fmemq (sym, rfront))) | ||
| 790 | continue; | ||
| 791 | |||
| 792 | /* If sym is in PLEFT we already got it. */ | ||
| 793 | for (tail1 = pleft; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1))) | ||
| 794 | if (EQ (sym, Fcar (tail1))) | ||
| 795 | break; | ||
| 796 | |||
| 797 | if (NILP (tail1)) | ||
| 798 | { | ||
| 799 | props = Fcons (sym, Fcons (Fcar (Fcdr (tail2)), props)); | ||
| 800 | front = Fcons (sym, front); | ||
| 801 | if (! NILP (Fmemq (sym, rrear))) | ||
| 802 | rear = Fcons (sym, rear); | ||
| 803 | } | ||
| 804 | } | ||
| 805 | if (! NILP (front)) | ||
| 806 | props = Fcons (Qfront_sticky, Fcons (front, props)); | ||
| 807 | if (! NILP (rear)) | ||
| 808 | props = Fcons (Qrear_nonsticky, Fcons (rear, props)); | ||
| 809 | return props; | ||
| 810 | |||
| 811 | } | ||
| 812 | |||
| 676 | 813 | ||
| 677 | /* Delete an node I from its interval tree by merging its subtrees | 814 | /* Delete an node I from its interval tree by merging its subtrees |
| 678 | into one subtree which is then returned. Caller is responsible for | 815 | into one subtree which is then returned. Caller is responsible for |
| 679 | storing the resulting subtree into its parent. */ | 816 | storing the resulting subtree into its parent. */ |
| 680 | 817 | ||
| 681 | static INTERVAL | 818 | static INTERVAL |
| 682 | delete_node (i) | 819 | delete_node (i) |
| @@ -709,7 +846,7 @@ delete_node (i) | |||
| 709 | and properly connecting the resultant subtree. | 846 | and properly connecting the resultant subtree. |
| 710 | 847 | ||
| 711 | I is presumed to be empty; that is, no adjustments are made | 848 | I is presumed to be empty; that is, no adjustments are made |
| 712 | for the length of I. */ | 849 | for the length of I. */ |
| 713 | 850 | ||
| 714 | void | 851 | void |
| 715 | delete_interval (i) | 852 | delete_interval (i) |
| @@ -718,7 +855,7 @@ delete_interval (i) | |||
| 718 | register INTERVAL parent; | 855 | register INTERVAL parent; |
| 719 | int amt = LENGTH (i); | 856 | int amt = LENGTH (i); |
| 720 | 857 | ||
| 721 | if (amt > 0) /* Only used on zero-length intervals now. */ | 858 | if (amt > 0) /* Only used on zero-length intervals now. */ |
| 722 | abort (); | 859 | abort (); |
| 723 | 860 | ||
| 724 | if (ROOT_INTERVAL_P (i)) | 861 | if (ROOT_INTERVAL_P (i)) |
| @@ -763,7 +900,7 @@ delete_interval (i) | |||
| 763 | recursively on subtrees. | 900 | recursively on subtrees. |
| 764 | 901 | ||
| 765 | Do this by recursing down TREE to the interval in question, and | 902 | Do this by recursing down TREE to the interval in question, and |
| 766 | deleting the appropriate amount of text. */ | 903 | deleting the appropriate amount of text. */ |
| 767 | 904 | ||
| 768 | static int | 905 | static int |
| 769 | interval_deletion_adjustment (tree, from, amount) | 906 | interval_deletion_adjustment (tree, from, amount) |
| @@ -798,7 +935,7 @@ interval_deletion_adjustment (tree, from, amount) | |||
| 798 | tree->total_length -= subtract; | 935 | tree->total_length -= subtract; |
| 799 | return subtract; | 936 | return subtract; |
| 800 | } | 937 | } |
| 801 | /* Here -- this node */ | 938 | /* Here -- this node. */ |
| 802 | else | 939 | else |
| 803 | { | 940 | { |
| 804 | /* How much can we delete from this interval? */ | 941 | /* How much can we delete from this interval? */ |
| @@ -816,13 +953,13 @@ interval_deletion_adjustment (tree, from, amount) | |||
| 816 | return amount; | 953 | return amount; |
| 817 | } | 954 | } |
| 818 | 955 | ||
| 819 | /* Never reach here */ | 956 | /* Never reach here. */ |
| 820 | } | 957 | } |
| 821 | 958 | ||
| 822 | /* Effect the adjustments necessary to the interval tree of BUFFER to | 959 | /* Effect the adjustments necessary to the interval tree of BUFFER to |
| 823 | correspond to the deletion of LENGTH characters from that buffer | 960 | correspond to the deletion of LENGTH characters from that buffer |
| 824 | text. The deletion is effected at position START (which is a | 961 | text. The deletion is effected at position START (which is a |
| 825 | buffer position, i.e. origin 1). */ | 962 | buffer position, i.e. origin 1). */ |
| 826 | 963 | ||
| 827 | static void | 964 | static void |
| 828 | adjust_intervals_for_deletion (buffer, start, length) | 965 | adjust_intervals_for_deletion (buffer, start, length) |
| @@ -870,7 +1007,7 @@ adjust_intervals_for_deletion (buffer, start, length) | |||
| 870 | /* Make the adjustments necessary to the interval tree of BUFFER to | 1007 | /* Make the adjustments necessary to the interval tree of BUFFER to |
| 871 | represent an addition or deletion of LENGTH characters starting | 1008 | represent an addition or deletion of LENGTH characters starting |
| 872 | at position START. Addition or deletion is indicated by the sign | 1009 | at position START. Addition or deletion is indicated by the sign |
| 873 | of LENGTH. */ | 1010 | of LENGTH. */ |
| 874 | 1011 | ||
| 875 | INLINE void | 1012 | INLINE void |
| 876 | offset_intervals (buffer, start, length) | 1013 | offset_intervals (buffer, start, length) |
| @@ -893,7 +1030,7 @@ offset_intervals (buffer, start, length) | |||
| 893 | 1030 | ||
| 894 | IMPORTANT: | 1031 | IMPORTANT: |
| 895 | The caller must verify that this is not the last (rightmost) | 1032 | The caller must verify that this is not the last (rightmost) |
| 896 | interval. */ | 1033 | interval. */ |
| 897 | 1034 | ||
| 898 | INTERVAL | 1035 | INTERVAL |
| 899 | merge_interval_right (i) | 1036 | merge_interval_right (i) |
| @@ -902,12 +1039,12 @@ merge_interval_right (i) | |||
| 902 | register int absorb = LENGTH (i); | 1039 | register int absorb = LENGTH (i); |
| 903 | register INTERVAL successor; | 1040 | register INTERVAL successor; |
| 904 | 1041 | ||
| 905 | /* Zero out this interval. */ | 1042 | /* Zero out this interval. */ |
| 906 | i->total_length -= absorb; | 1043 | i->total_length -= absorb; |
| 907 | 1044 | ||
| 908 | /* Find the succeeding interval. */ | 1045 | /* Find the succeeding interval. */ |
| 909 | if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb | 1046 | if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb |
| 910 | as we descend. */ | 1047 | as we descend. */ |
| 911 | { | 1048 | { |
| 912 | successor = i->right; | 1049 | successor = i->right; |
| 913 | while (! NULL_LEFT_CHILD (successor)) | 1050 | while (! NULL_LEFT_CHILD (successor)) |
| @@ -923,7 +1060,7 @@ merge_interval_right (i) | |||
| 923 | 1060 | ||
| 924 | successor = i; | 1061 | successor = i; |
| 925 | while (! NULL_PARENT (successor)) /* It's above us. Subtract as | 1062 | while (! NULL_PARENT (successor)) /* It's above us. Subtract as |
| 926 | we ascend. */ | 1063 | we ascend. */ |
| 927 | { | 1064 | { |
| 928 | if (AM_LEFT_CHILD (successor)) | 1065 | if (AM_LEFT_CHILD (successor)) |
| 929 | { | 1066 | { |
| @@ -937,7 +1074,7 @@ merge_interval_right (i) | |||
| 937 | } | 1074 | } |
| 938 | 1075 | ||
| 939 | /* This must be the rightmost or last interval and cannot | 1076 | /* This must be the rightmost or last interval and cannot |
| 940 | be merged right. The caller should have known. */ | 1077 | be merged right. The caller should have known. */ |
| 941 | abort (); | 1078 | abort (); |
| 942 | } | 1079 | } |
| 943 | 1080 | ||
| @@ -946,7 +1083,7 @@ merge_interval_right (i) | |||
| 946 | The properties of I are lost. Interval node I is removed from the tree. | 1083 | The properties of I are lost. Interval node I is removed from the tree. |
| 947 | 1084 | ||
| 948 | IMPORTANT: | 1085 | IMPORTANT: |
| 949 | The caller must verify that this is not the first (leftmost) interval. */ | 1086 | The caller must verify that this is not the first (leftmost) interval. */ |
| 950 | 1087 | ||
| 951 | INTERVAL | 1088 | INTERVAL |
| 952 | merge_interval_left (i) | 1089 | merge_interval_left (i) |
| @@ -955,12 +1092,12 @@ merge_interval_left (i) | |||
| 955 | register int absorb = LENGTH (i); | 1092 | register int absorb = LENGTH (i); |
| 956 | register INTERVAL predecessor; | 1093 | register INTERVAL predecessor; |
| 957 | 1094 | ||
| 958 | /* Zero out this interval. */ | 1095 | /* Zero out this interval. */ |
| 959 | i->total_length -= absorb; | 1096 | i->total_length -= absorb; |
| 960 | 1097 | ||
| 961 | /* Find the preceding interval. */ | 1098 | /* Find the preceding interval. */ |
| 962 | if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down, | 1099 | if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down, |
| 963 | adding ABSORB as we go. */ | 1100 | adding ABSORB as we go. */ |
| 964 | { | 1101 | { |
| 965 | predecessor = i->left; | 1102 | predecessor = i->left; |
| 966 | while (! NULL_RIGHT_CHILD (predecessor)) | 1103 | while (! NULL_RIGHT_CHILD (predecessor)) |
| @@ -976,7 +1113,7 @@ merge_interval_left (i) | |||
| 976 | 1113 | ||
| 977 | predecessor = i; | 1114 | predecessor = i; |
| 978 | while (! NULL_PARENT (predecessor)) /* It's above us. Go up, | 1115 | while (! NULL_PARENT (predecessor)) /* It's above us. Go up, |
| 979 | subtracting ABSORB. */ | 1116 | subtracting ABSORB. */ |
| 980 | { | 1117 | { |
| 981 | if (AM_RIGHT_CHILD (predecessor)) | 1118 | if (AM_RIGHT_CHILD (predecessor)) |
| 982 | { | 1119 | { |
| @@ -990,14 +1127,14 @@ merge_interval_left (i) | |||
| 990 | } | 1127 | } |
| 991 | 1128 | ||
| 992 | /* This must be the leftmost or first interval and cannot | 1129 | /* This must be the leftmost or first interval and cannot |
| 993 | be merged left. The caller should have known. */ | 1130 | be merged left. The caller should have known. */ |
| 994 | abort (); | 1131 | abort (); |
| 995 | } | 1132 | } |
| 996 | 1133 | ||
| 997 | /* Make an exact copy of interval tree SOURCE which descends from | 1134 | /* Make an exact copy of interval tree SOURCE which descends from |
| 998 | PARENT. This is done by recursing through SOURCE, copying | 1135 | PARENT. This is done by recursing through SOURCE, copying |
| 999 | the current interval and its properties, and then adjusting | 1136 | the current interval and its properties, and then adjusting |
| 1000 | the pointers of the copy. */ | 1137 | the pointers of the copy. */ |
| 1001 | 1138 | ||
| 1002 | static INTERVAL | 1139 | static INTERVAL |
| 1003 | reproduce_tree (source, parent) | 1140 | reproduce_tree (source, parent) |
| @@ -1024,7 +1161,7 @@ reproduce_tree (source, parent) | |||
| 1024 | Returns the new interval. | 1161 | Returns the new interval. |
| 1025 | 1162 | ||
| 1026 | Generate an error if the new positions would overlap an existing | 1163 | Generate an error if the new positions would overlap an existing |
| 1027 | interval. */ | 1164 | interval. */ |
| 1028 | 1165 | ||
| 1029 | static INTERVAL | 1166 | static INTERVAL |
| 1030 | make_new_interval (intervals, start, length) | 1167 | make_new_interval (intervals, start, length) |
| @@ -1042,19 +1179,19 @@ make_new_interval (intervals, start, length) | |||
| 1042 | 1179 | ||
| 1043 | if (slot->position == start) | 1180 | if (slot->position == start) |
| 1044 | { | 1181 | { |
| 1045 | /* New right node. */ | 1182 | /* New right node. */ |
| 1046 | split_interval_right (slot, length); | 1183 | split_interval_right (slot, length); |
| 1047 | return slot; | 1184 | return slot; |
| 1048 | } | 1185 | } |
| 1049 | 1186 | ||
| 1050 | if (slot->position + LENGTH (slot) == start + length) | 1187 | if (slot->position + LENGTH (slot) == start + length) |
| 1051 | { | 1188 | { |
| 1052 | /* New left node. */ | 1189 | /* New left node. */ |
| 1053 | split_interval_left (slot, LENGTH (slot) - length); | 1190 | split_interval_left (slot, LENGTH (slot) - length); |
| 1054 | return slot; | 1191 | return slot; |
| 1055 | } | 1192 | } |
| 1056 | 1193 | ||
| 1057 | /* Convert interval SLOT into three intervals. */ | 1194 | /* Convert interval SLOT into three intervals. */ |
| 1058 | split_interval_left (slot, start - slot->position); | 1195 | split_interval_left (slot, start - slot->position); |
| 1059 | split_interval_right (slot, length); | 1196 | split_interval_right (slot, length); |
| 1060 | return slot; | 1197 | return slot; |
| @@ -1091,7 +1228,7 @@ make_new_interval (intervals, start, length) | |||
| 1091 | intervals to the new text are "sticky", then the new text retains | 1228 | intervals to the new text are "sticky", then the new text retains |
| 1092 | only its properties, as if neither sticky property were set. Perhaps | 1229 | only its properties, as if neither sticky property were set. Perhaps |
| 1093 | we should consider merging all three sets of properties onto the new | 1230 | we should consider merging all three sets of properties onto the new |
| 1094 | text... */ | 1231 | text... */ |
| 1095 | 1232 | ||
| 1096 | void | 1233 | void |
| 1097 | graft_intervals_into_buffer (source, position, buffer) | 1234 | graft_intervals_into_buffer (source, position, buffer) |
| @@ -1104,26 +1241,26 @@ graft_intervals_into_buffer (source, position, buffer) | |||
| 1104 | int middle; | 1241 | int middle; |
| 1105 | 1242 | ||
| 1106 | /* If the new text has no properties, it becomes part of whatever | 1243 | /* If the new text has no properties, it becomes part of whatever |
| 1107 | interval it was inserted into. */ | 1244 | interval it was inserted into. */ |
| 1108 | if (NULL_INTERVAL_P (source)) | 1245 | if (NULL_INTERVAL_P (source)) |
| 1109 | return; | 1246 | return; |
| 1110 | 1247 | ||
| 1111 | if (NULL_INTERVAL_P (tree)) | 1248 | if (NULL_INTERVAL_P (tree)) |
| 1112 | { | 1249 | { |
| 1113 | /* The inserted text constitutes the whole buffer, so | 1250 | /* The inserted text constitutes the whole buffer, so |
| 1114 | simply copy over the interval structure. */ | 1251 | simply copy over the interval structure. */ |
| 1115 | if ((BUF_Z (buffer) - BUF_BEG (buffer)) == TOTAL_LENGTH (source)) | 1252 | if ((BUF_Z (buffer) - BUF_BEG (buffer)) == TOTAL_LENGTH (source)) |
| 1116 | { | 1253 | { |
| 1117 | Lisp_Object buf; | 1254 | Lisp_Object buf; |
| 1118 | XSET (buf, Lisp_Buffer, buffer); | 1255 | XSET (buf, Lisp_Buffer, buffer); |
| 1119 | buffer->intervals = reproduce_tree (source, buf); | 1256 | buffer->intervals = reproduce_tree (source, buf); |
| 1120 | /* Explicitly free the old tree here. */ | 1257 | /* Explicitly free the old tree here. */ |
| 1121 | 1258 | ||
| 1122 | return; | 1259 | return; |
| 1123 | } | 1260 | } |
| 1124 | 1261 | ||
| 1125 | /* Create an interval tree in which to place a copy | 1262 | /* Create an interval tree in which to place a copy |
| 1126 | of the intervals of the inserted string. */ | 1263 | of the intervals of the inserted string. */ |
| 1127 | { | 1264 | { |
| 1128 | Lisp_Object buf; | 1265 | Lisp_Object buf; |
| 1129 | XSET (buf, Lisp_Buffer, buffer); | 1266 | XSET (buf, Lisp_Buffer, buffer); |
| @@ -1135,16 +1272,16 @@ graft_intervals_into_buffer (source, position, buffer) | |||
| 1135 | /* If the buffer contains only the new string, but | 1272 | /* If the buffer contains only the new string, but |
| 1136 | there was already some interval tree there, then it may be | 1273 | there was already some interval tree there, then it may be |
| 1137 | some zero length intervals. Eventually, do something clever | 1274 | some zero length intervals. Eventually, do something clever |
| 1138 | about inserting properly. For now, just waste the old intervals. */ | 1275 | about inserting properly. For now, just waste the old intervals. */ |
| 1139 | { | 1276 | { |
| 1140 | buffer->intervals = reproduce_tree (source, tree->parent); | 1277 | buffer->intervals = reproduce_tree (source, tree->parent); |
| 1141 | /* Explicitly free the old tree here. */ | 1278 | /* Explicitly free the old tree here. */ |
| 1142 | 1279 | ||
| 1143 | return; | 1280 | return; |
| 1144 | } | 1281 | } |
| 1145 | else | 1282 | else |
| 1146 | /* Paranoia -- the text has already been added, so this buffer | 1283 | /* Paranoia -- the text has already been added, so this buffer |
| 1147 | should be of non-zero length. */ | 1284 | should be of non-zero length. */ |
| 1148 | if (TOTAL_LENGTH (tree) == 0) | 1285 | if (TOTAL_LENGTH (tree) == 0) |
| 1149 | abort (); | 1286 | abort (); |
| 1150 | 1287 | ||
| @@ -1169,31 +1306,32 @@ graft_intervals_into_buffer (source, position, buffer) | |||
| 1169 | else | 1306 | else |
| 1170 | { | 1307 | { |
| 1171 | prev = previous_interval (under); | 1308 | prev = previous_interval (under); |
| 1172 | if (prev && !END_STICKY_P (prev)) | 1309 | if (prev && !END_NONSTICKY_P (prev)) |
| 1173 | prev = 0; | 1310 | prev = 0; |
| 1174 | } | 1311 | } |
| 1175 | 1312 | ||
| 1176 | /* Insertion is now at beginning of UNDER. */ | 1313 | /* Insertion is now at beginning of UNDER. */ |
| 1177 | 1314 | ||
| 1178 | /* The inserted text "sticks" to the interval `under', | 1315 | /* The inserted text "sticks" to the interval `under', |
| 1179 | which means it gets those properties. */ | 1316 | which means it gets those properties. |
| 1317 | The properties of under are the result of | ||
| 1318 | adjust_intervals_for_insertion, so stickyness has | ||
| 1319 | already been taken care of. */ | ||
| 1320 | |||
| 1180 | while (! NULL_INTERVAL_P (over)) | 1321 | while (! NULL_INTERVAL_P (over)) |
| 1181 | { | 1322 | { |
| 1182 | if (LENGTH (over) + 1 < LENGTH (under)) | 1323 | if (LENGTH (over) + 1 < LENGTH (under)) |
| 1183 | this = split_interval_left (under, LENGTH (over)); | 1324 | { |
| 1325 | this = split_interval_left (under, LENGTH (over)); | ||
| 1326 | copy_properties (under, this); | ||
| 1327 | } | ||
| 1184 | else | 1328 | else |
| 1185 | this = under; | 1329 | this = under; |
| 1186 | copy_properties (over, this); | 1330 | copy_properties (over, this); |
| 1187 | /* Insertion at the end of an interval, PREV, | 1331 | if (MERGE_INSERTIONS (this)) |
| 1188 | inherits from PREV if PREV is sticky at the end. */ | 1332 | merge_properties (over, this); |
| 1189 | if (prev && ! FRONT_STICKY_P (under) | 1333 | else |
| 1190 | && MERGE_INSERTIONS (prev)) | 1334 | copy_properties (over, this); |
| 1191 | merge_properties (prev, this); | ||
| 1192 | /* Maybe it inherits from the following interval | ||
| 1193 | if that is sticky at the front. */ | ||
| 1194 | else if ((FRONT_STICKY_P (under) || middle) | ||
| 1195 | && MERGE_INSERTIONS (under)) | ||
| 1196 | merge_properties (under, this); | ||
| 1197 | over = next_interval (over); | 1335 | over = next_interval (over); |
| 1198 | } | 1336 | } |
| 1199 | 1337 | ||
| @@ -1225,6 +1363,26 @@ textget (plist, prop) | |||
| 1225 | 1363 | ||
| 1226 | return fallback; | 1364 | return fallback; |
| 1227 | } | 1365 | } |
| 1366 | |||
| 1367 | /* Get the value of property PROP from PLIST, | ||
| 1368 | which is the plist of an interval. | ||
| 1369 | We check for direct properties only! */ | ||
| 1370 | |||
| 1371 | Lisp_Object | ||
| 1372 | textget_direct (plist, prop) | ||
| 1373 | Lisp_Object plist; | ||
| 1374 | register Lisp_Object prop; | ||
| 1375 | { | ||
| 1376 | register Lisp_Object tail; | ||
| 1377 | |||
| 1378 | for (tail = plist; !NILP (tail); tail = Fcdr (Fcdr (tail))) | ||
| 1379 | { | ||
| 1380 | if (EQ (prop, Fcar (tail))) | ||
| 1381 | return Fcar (Fcdr (tail)); | ||
| 1382 | } | ||
| 1383 | |||
| 1384 | return Qnil; | ||
| 1385 | } | ||
| 1228 | 1386 | ||
| 1229 | /* Set point in BUFFER to POSITION. If the target position is | 1387 | /* Set point in BUFFER to POSITION. If the target position is |
| 1230 | before an invisible character which is not displayed with a special glyph, | 1388 | before an invisible character which is not displayed with a special glyph, |
| @@ -1274,9 +1432,9 @@ set_point (position, buffer) | |||
| 1274 | /* Set FROM to the interval containing the char after PT, | 1432 | /* Set FROM to the interval containing the char after PT, |
| 1275 | and FROMPREV to the interval containing the char before PT. | 1433 | and FROMPREV to the interval containing the char before PT. |
| 1276 | Either one may be null. They may be equal. */ | 1434 | Either one may be null. They may be equal. */ |
| 1277 | /* We could cache this and save time. */ | 1435 | /* We could cache this and save time. */ |
| 1278 | from = find_interval (buffer->intervals, buffer_point); | 1436 | from = find_interval (buffer->intervals, buffer_point); |
| 1279 | if (from->position == BUF_BEGV (buffer)) | 1437 | if (buffer_point == BUF_BEGV (buffer)) |
| 1280 | fromprev = 0; | 1438 | fromprev = 0; |
| 1281 | else if (from->position == BUF_PT (buffer)) | 1439 | else if (from->position == BUF_PT (buffer)) |
| 1282 | fromprev = previous_interval (from); | 1440 | fromprev = previous_interval (from); |
| @@ -1285,17 +1443,18 @@ set_point (position, buffer) | |||
| 1285 | else | 1443 | else |
| 1286 | fromprev = from; | 1444 | fromprev = from; |
| 1287 | 1445 | ||
| 1288 | /* Moving within an interval */ | 1446 | /* Moving within an interval. */ |
| 1289 | if (to == from && toprev == fromprev && INTERVAL_VISIBLE_P (to)) | 1447 | if (to == from && toprev == fromprev && INTERVAL_VISIBLE_P (to)) |
| 1290 | { | 1448 | { |
| 1291 | buffer->text.pt = position; | 1449 | buffer->text.pt = position; |
| 1292 | return; | 1450 | return; |
| 1293 | } | 1451 | } |
| 1294 | 1452 | ||
| 1295 | /* If the new position is before an invisible character, | 1453 | /* If the new position is before an invisible character |
| 1454 | that has an `invisible' property of value `hidden', | ||
| 1296 | move forward over all such. */ | 1455 | move forward over all such. */ |
| 1297 | while (! NULL_INTERVAL_P (to) | 1456 | while (! NULL_INTERVAL_P (to) |
| 1298 | && ! INTERVAL_VISIBLE_P (to) | 1457 | && EQ (textget (to->plist, Qinvisible), Qhidden) |
| 1299 | && ! DISPLAY_INVISIBLE_GLYPH (to)) | 1458 | && ! DISPLAY_INVISIBLE_GLYPH (to)) |
| 1300 | { | 1459 | { |
| 1301 | toprev = to; | 1460 | toprev = to; |
| @@ -1347,7 +1506,7 @@ set_point (position, buffer) | |||
| 1347 | } | 1506 | } |
| 1348 | } | 1507 | } |
| 1349 | 1508 | ||
| 1350 | /* Set point temporarily, without checking any text properties. */ | 1509 | /* Set point temporarily, without checking any text properties. */ |
| 1351 | 1510 | ||
| 1352 | INLINE void | 1511 | INLINE void |
| 1353 | temp_set_point (position, buffer) | 1512 | temp_set_point (position, buffer) |
| @@ -1372,7 +1531,7 @@ get_local_map (position, buffer) | |||
| 1372 | if (NULL_INTERVAL_P (buffer->intervals)) | 1531 | if (NULL_INTERVAL_P (buffer->intervals)) |
| 1373 | return current_buffer->keymap; | 1532 | return current_buffer->keymap; |
| 1374 | 1533 | ||
| 1375 | /* Perhaps we should just change `position' to the limit. */ | 1534 | /* Perhaps we should just change `position' to the limit. */ |
| 1376 | if (position > BUF_Z (buffer) || position < BUF_BEG (buffer)) | 1535 | if (position > BUF_Z (buffer) || position < BUF_BEG (buffer)) |
| 1377 | abort (); | 1536 | abort (); |
| 1378 | 1537 | ||
| @@ -1410,7 +1569,7 @@ call_mod_hooks (list, start, end) | |||
| 1410 | (but not including) TO. Create a list of all these hooks in | 1569 | (but not including) TO. Create a list of all these hooks in |
| 1411 | lexicographic order, eliminating consecutive extra copies of the | 1570 | lexicographic order, eliminating consecutive extra copies of the |
| 1412 | same hook. Then call those hooks in order, with START and END - 1 | 1571 | same hook. Then call those hooks in order, with START and END - 1 |
| 1413 | as arguments. */ | 1572 | as arguments. */ |
| 1414 | 1573 | ||
| 1415 | void | 1574 | void |
| 1416 | verify_interval_modification (buf, start, end) | 1575 | verify_interval_modification (buf, start, end) |
| @@ -1451,32 +1610,73 @@ verify_interval_modification (buf, start, end) | |||
| 1451 | 1610 | ||
| 1452 | if (start == BUF_BEGV (buf)) | 1611 | if (start == BUF_BEGV (buf)) |
| 1453 | prev = 0; | 1612 | prev = 0; |
| 1454 | if (i->position == start) | 1613 | else if (i->position == start) |
| 1455 | prev = previous_interval (i); | 1614 | prev = previous_interval (i); |
| 1456 | else if (i->position < start) | 1615 | else if (i->position < start) |
| 1457 | prev = i; | 1616 | prev = i; |
| 1458 | if (start == BUF_ZV (buf)) | 1617 | if (start == BUF_ZV (buf)) |
| 1459 | i = 0; | 1618 | i = 0; |
| 1460 | 1619 | ||
| 1461 | if (NULL_INTERVAL_P (prev)) | 1620 | /* If Vinhibit_read_only is set and is not a list, we can |
| 1462 | { | 1621 | skip the read_only checks. */ |
| 1463 | if (! INTERVAL_WRITABLE_P (i)) | 1622 | if (NILP (Vinhibit_read_only) || CONSP (Vinhibit_read_only)) |
| 1464 | error ("Attempt to insert within read-only text"); | ||
| 1465 | } | ||
| 1466 | else if (NULL_INTERVAL_P (i)) | ||
| 1467 | { | ||
| 1468 | if (! INTERVAL_WRITABLE_P (prev)) | ||
| 1469 | error ("Attempt to insert within read-only text"); | ||
| 1470 | } | ||
| 1471 | else | ||
| 1472 | { | 1623 | { |
| 1473 | before = textget (prev->plist, Qread_only); | 1624 | /* If I and PREV differ we need to check for the read-only |
| 1474 | after = textget (i->plist, Qread_only); | 1625 | property together with its stickyness. If either I or |
| 1475 | if (! NILP (before) && EQ (before, after) | 1626 | PREV are 0, this check is all we need. |
| 1476 | /* This checks Vinhibit_read_only properly | 1627 | We have to take special care, since read-only may be |
| 1477 | for the common value of the read-only property. */ | 1628 | indirectly defined via the category property. */ |
| 1478 | && ! INTERVAL_WRITABLE_P (i)) | 1629 | if (i != prev) |
| 1479 | error ("Attempt to insert within read-only text"); | 1630 | { |
| 1631 | if (! NULL_INTERVAL_P (i)) | ||
| 1632 | { | ||
| 1633 | after = textget (i->plist, Qread_only); | ||
| 1634 | |||
| 1635 | /* If interval I is read-only and read-only is | ||
| 1636 | front-sticky, inhibit insertion. | ||
| 1637 | Check for read-only as well as category. */ | ||
| 1638 | if (! NILP (after) | ||
| 1639 | && NILP (Fmemq (after, Vinhibit_read_only)) | ||
| 1640 | && (! NILP (Fmemq (Qread_only, | ||
| 1641 | textget (i->plist, Qfront_sticky))) | ||
| 1642 | || (NILP (textget_direct (i->plist, Qread_only)) | ||
| 1643 | && ! NILP (Fmemq (Qcategory, | ||
| 1644 | textget (i->plist, | ||
| 1645 | Qfront_sticky)))))) | ||
| 1646 | error ("Attempt to insert within read-only text"); | ||
| 1647 | } | ||
| 1648 | else | ||
| 1649 | after = Qnil; | ||
| 1650 | if (! NULL_INTERVAL_P (prev)) | ||
| 1651 | { | ||
| 1652 | before = textget (prev->plist, Qread_only); | ||
| 1653 | |||
| 1654 | /* If interval PREV is read-only and read-only isn't | ||
| 1655 | rear-nonsticky, inhibit insertion. | ||
| 1656 | Check for read-only as well as category. */ | ||
| 1657 | if (! NILP (before) | ||
| 1658 | && NILP (Fmemq (before, Vinhibit_read_only)) | ||
| 1659 | && NILP (Fmemq (Qread_only, | ||
| 1660 | textget (prev->plist, Qrear_nonsticky))) | ||
| 1661 | && (! NILP (textget_direct (prev->plist,Qread_only)) | ||
| 1662 | || NILP (Fmemq (Qcategory, | ||
| 1663 | textget (prev->plist, | ||
| 1664 | Qrear_nonsticky))))) | ||
| 1665 | error ("Attempt to insert within read-only text"); | ||
| 1666 | } | ||
| 1667 | else | ||
| 1668 | before = Qnil; | ||
| 1669 | } | ||
| 1670 | else if (! NULL_INTERVAL_P (i)) | ||
| 1671 | before = after = textget (i->plist, Qread_only); | ||
| 1672 | if (! NULL_INTERVAL_P (i) && ! NULL_INTERVAL_P (prev)) | ||
| 1673 | { | ||
| 1674 | /* If I and PREV differ, neither of them has a sticky | ||
| 1675 | read-only property. It only remains to check, whether | ||
| 1676 | they have a common read-only property. */ | ||
| 1677 | if (! NILP (before) && EQ (before, after)) | ||
| 1678 | error ("Attempt to insert within read-only text"); | ||
| 1679 | } | ||
| 1480 | } | 1680 | } |
| 1481 | 1681 | ||
| 1482 | /* Run both insert hooks (just once if they're the same). */ | 1682 | /* Run both insert hooks (just once if they're the same). */ |
| @@ -1529,7 +1729,7 @@ verify_interval_modification (buf, start, end) | |||
| 1529 | 1729 | ||
| 1530 | /* Balance an interval node if the amount of text in its left and right | 1730 | /* Balance an interval node if the amount of text in its left and right |
| 1531 | subtrees differs by more than the percentage specified by | 1731 | subtrees differs by more than the percentage specified by |
| 1532 | `interval-balance-threshold'. */ | 1732 | `interval-balance-threshold'. */ |
| 1533 | 1733 | ||
| 1534 | static INTERVAL | 1734 | static INTERVAL |
| 1535 | balance_an_interval (i) | 1735 | balance_an_interval (i) |
| @@ -1569,7 +1769,7 @@ balance_an_interval (i) | |||
| 1569 | } | 1769 | } |
| 1570 | 1770 | ||
| 1571 | /* Balance the interval tree TREE. Balancing is by weight | 1771 | /* Balance the interval tree TREE. Balancing is by weight |
| 1572 | (the amount of text). */ | 1772 | (the amount of text). */ |
| 1573 | 1773 | ||
| 1574 | INTERVAL | 1774 | INTERVAL |
| 1575 | balance_intervals (tree) | 1775 | balance_intervals (tree) |
| @@ -1592,7 +1792,7 @@ balance_intervals (tree) | |||
| 1592 | } | 1792 | } |
| 1593 | 1793 | ||
| 1594 | /* Produce an interval tree reflecting the intervals in | 1794 | /* Produce an interval tree reflecting the intervals in |
| 1595 | TREE from START to START + LENGTH. */ | 1795 | TREE from START to START + LENGTH. */ |
| 1596 | 1796 | ||
| 1597 | INTERVAL | 1797 | INTERVAL |
| 1598 | copy_intervals (tree, start, length) | 1798 | copy_intervals (tree, start, length) |
| @@ -1609,7 +1809,7 @@ copy_intervals (tree, start, length) | |||
| 1609 | if (NULL_INTERVAL_P (i) || LENGTH (i) == 0) | 1809 | if (NULL_INTERVAL_P (i) || LENGTH (i) == 0) |
| 1610 | abort (); | 1810 | abort (); |
| 1611 | 1811 | ||
| 1612 | /* If there is only one interval and it's the default, return nil. */ | 1812 | /* If there is only one interval and it's the default, return nil. */ |
| 1613 | if ((start - i->position + 1 + length) < LENGTH (i) | 1813 | if ((start - i->position + 1 + length) < LENGTH (i) |
| 1614 | && DEFAULT_INTERVAL_P (i)) | 1814 | && DEFAULT_INTERVAL_P (i)) |
| 1615 | return NULL_INTERVAL; | 1815 | return NULL_INTERVAL; |
| @@ -1634,7 +1834,7 @@ copy_intervals (tree, start, length) | |||
| 1634 | return balance_intervals (new); | 1834 | return balance_intervals (new); |
| 1635 | } | 1835 | } |
| 1636 | 1836 | ||
| 1637 | /* Give STRING the properties of BUFFER from POSITION to LENGTH. */ | 1837 | /* Give STRING the properties of BUFFER from POSITION to LENGTH. */ |
| 1638 | 1838 | ||
| 1639 | INLINE void | 1839 | INLINE void |
| 1640 | copy_intervals_to_string (string, buffer, position, length) | 1840 | copy_intervals_to_string (string, buffer, position, length) |