X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/1d14d232ddf738ffb019560444536b5a9eedc90c..c3e9438b5fde71d0464c1bd55919468880256651:/src/intervals.c diff --git a/src/intervals.c b/src/intervals.c index 09a9bc512b..8bbab5a2a2 100644 --- a/src/intervals.c +++ b/src/intervals.c @@ -1,5 +1,6 @@ /* Code for doing intervals. - Copyright (C) 1993, 1994, 1995, 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1993, 1994, 1995, 1997, 1998, 2002, 2003, 2004, + 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -15,8 +16,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ /* NOTES: @@ -75,13 +76,15 @@ create_root_interval (parent) { new->total_length = (BUF_Z (XBUFFER (parent)) - BUF_BEG (XBUFFER (parent))); + CHECK_TOTAL_LENGTH (new); BUF_INTERVALS (XBUFFER (parent)) = new; - new->position = 1; + new->position = BEG; } else if (STRINGP (parent)) { - new->total_length = XSTRING (parent)->size; - XSTRING (parent)->intervals = new; + new->total_length = SCHARS (parent); + CHECK_TOTAL_LENGTH (new); + STRING_SET_INTERVALS (parent, new); new->position = 0; } @@ -119,20 +122,21 @@ merge_properties (source, target) MERGE_INTERVAL_CACHE (source, target); o = source->plist; - while (! EQ (o, Qnil)) + while (CONSP (o)) { - sym = Fcar (o); + sym = XCAR (o); val = Fmemq (sym, target->plist); if (NILP (val)) { - o = Fcdr (o); - val = Fcar (o); + o = XCDR (o); + CHECK_CONS (o); + val = XCAR (o); target->plist = Fcons (sym, Fcons (val, target->plist)); - o = Fcdr (o); + o = XCDR (o); } else - o = Fcdr (Fcdr (o)); + o = Fcdr (XCDR (o)); } } @@ -157,13 +161,13 @@ intervals_equal (i0, i1) abort (); i1_len /= 2; i0_cdr = i0->plist; - while (!NILP (i0_cdr)) + while (CONSP (i0_cdr)) { /* Lengths of the two plists were unequal. */ if (i1_len == 0) return 0; - i0_sym = Fcar (i0_cdr); + i0_sym = XCAR (i0_cdr); i1_val = Fmemq (i0_sym, i1->plist); /* i0 has something i1 doesn't. */ @@ -171,11 +175,12 @@ intervals_equal (i0, i1) return 0; /* i0 and i1 both have sym, but it has different values in each. */ - i0_cdr = Fcdr (i0_cdr); - if (! EQ (Fcar (Fcdr (i1_val)), Fcar (i0_cdr))) + i0_cdr = XCDR (i0_cdr); + CHECK_CONS (i0_cdr); + if (!EQ (Fcar (Fcdr (i1_val)), XCAR (i0_cdr))) return 0; - i0_cdr = Fcdr (i0_cdr); + i0_cdr = XCDR (i0_cdr); i1_len--; } @@ -338,19 +343,21 @@ rotate_right (interval) /* A's total length is decreased by the length of B and its left child. */ interval->total_length -= B->total_length - LEFT_TOTAL_LENGTH (interval); + CHECK_TOTAL_LENGTH (interval); /* B must have the same total length of A. */ B->total_length = old_total; + CHECK_TOTAL_LENGTH (B); return B; } /* Assuming that a right child exists, perform the following operation: - A B - / \ / \ + A B + / \ / \ B => A - / \ / \ + / \ / \ c c */ @@ -384,9 +391,11 @@ rotate_left (interval) /* A's total length is decreased by the length of B and its right child. */ interval->total_length -= B->total_length - RIGHT_TOTAL_LENGTH (interval); + CHECK_TOTAL_LENGTH (interval); /* B must have the same total length of A. */ B->total_length = old_total; + CHECK_TOTAL_LENGTH (B); return B; } @@ -405,6 +414,7 @@ balance_an_interval (i) old_diff = LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i); if (old_diff > 0) { + /* Since the left child is longer, there must be one. */ new_diff = i->total_length - i->left->total_length + RIGHT_TOTAL_LENGTH (i->left) - LEFT_TOTAL_LENGTH (i->left); if (abs (new_diff) >= old_diff) @@ -414,6 +424,7 @@ balance_an_interval (i) } else if (old_diff < 0) { + /* Since the right child is longer, there must be one. */ new_diff = i->total_length - i->right->total_length + LEFT_TOTAL_LENGTH (i->right) - RIGHT_TOTAL_LENGTH (i->right); if (abs (new_diff) >= -old_diff) @@ -452,7 +463,7 @@ balance_possible_root_interval (interval) if (BUFFERP (parent)) BUF_INTERVALS (XBUFFER (parent)) = interval; else if (STRINGP (parent)) - XSTRING (parent)->intervals = interval; + STRING_SET_INTERVALS (parent, interval); } return interval; @@ -514,6 +525,7 @@ split_interval_right (interval, offset) { interval->right = new; new->total_length = new_length; + CHECK_TOTAL_LENGTH (new); } else { @@ -522,9 +534,10 @@ split_interval_right (interval, offset) SET_INTERVAL_PARENT (interval->right, new); interval->right = new; new->total_length = new_length + new->right->total_length; + CHECK_TOTAL_LENGTH (new); balance_an_interval (new); } - + balance_possible_root_interval (interval); return new; @@ -559,6 +572,7 @@ split_interval_left (interval, offset) { interval->left = new; new->total_length = new_length; + CHECK_TOTAL_LENGTH (new); } else { @@ -567,9 +581,10 @@ split_interval_left (interval, offset) SET_INTERVAL_PARENT (new->left, new); interval->left = new; new->total_length = new_length + new->left->total_length; + CHECK_TOTAL_LENGTH (new); balance_an_interval (new); } - + balance_possible_root_interval (interval); return new; @@ -654,8 +669,8 @@ find_interval (tree, position) else { tree->position - = (position - relative_position /* the left edge of *tree */ - + LEFT_TOTAL_LENGTH (tree)); /* the left edge of this interval */ + = (position - relative_position /* left edge of *tree. */ + + LEFT_TOTAL_LENGTH (tree)); /* left edge of this interval. */ return tree; } @@ -754,39 +769,39 @@ update_interval (i, pos) if (NULL_INTERVAL_P (i)) return NULL_INTERVAL; - while (1) + while (1) { - if (pos < i->position) + if (pos < i->position) { /* Move left. */ - if (pos >= i->position - TOTAL_LENGTH (i->left)) + if (pos >= i->position - TOTAL_LENGTH (i->left)) { i->left->position = i->position - TOTAL_LENGTH (i->left) + LEFT_TOTAL_LENGTH (i->left); i = i->left; /* Move to the left child */ } - else if (NULL_PARENT (i)) + else if (NULL_PARENT (i)) error ("Point before start of properties"); - else + else i = INTERVAL_PARENT (i); continue; } else if (pos >= INTERVAL_LAST_POS (i)) { /* Move right. */ - if (pos < INTERVAL_LAST_POS (i) + TOTAL_LENGTH (i->right)) + if (pos < INTERVAL_LAST_POS (i) + TOTAL_LENGTH (i->right)) { - i->right->position = INTERVAL_LAST_POS (i) + - LEFT_TOTAL_LENGTH (i->right); + i->right->position = INTERVAL_LAST_POS (i) + + LEFT_TOTAL_LENGTH (i->right); i = i->right; /* Move to the right child */ } - else if (NULL_PARENT (i)) - error ("Point after end of properties"); - else - i = INTERVAL_PARENT (i); + else if (NULL_PARENT (i)) + error ("Point %d after end of properties", pos); + else + i = INTERVAL_PARENT (i); continue; } - else + else return i; } } @@ -828,6 +843,7 @@ adjust_intervals_for_insertion (tree, position, length) if (relative_position <= LEFT_TOTAL_LENGTH (this)) { this->total_length += length; + CHECK_TOTAL_LENGTH (this); this = this->left; } else if (relative_position > (TOTAL_LENGTH (this) @@ -836,6 +852,7 @@ adjust_intervals_for_insertion (tree, position, length) relative_position -= (TOTAL_LENGTH (this) - RIGHT_TOTAL_LENGTH (this)); this->total_length += length; + CHECK_TOTAL_LENGTH (this); this = this->right; } else @@ -843,6 +860,7 @@ adjust_intervals_for_insertion (tree, position, length) /* If we are to use zero-length intervals as buffer pointers, then this code will have to change. */ this->total_length += length; + CHECK_TOTAL_LENGTH (this); this->position = LEFT_TOTAL_LENGTH (this) + position - relative_position + 1; return tree; @@ -874,7 +892,7 @@ adjust_intervals_for_insertion (tree, position, length) int eobp = 0; Lisp_Object parent; int offset; - + if (TOTAL_LENGTH (tree) == 0) /* Paranoia */ abort (); @@ -987,9 +1005,10 @@ adjust_intervals_for_insertion (tree, position, length) for (temp = prev ? prev : i; temp; temp = INTERVAL_PARENT_OR_NULL (temp)) { temp->total_length += length; + CHECK_TOTAL_LENGTH (temp); temp = balance_possible_root_interval (temp); } - + /* If at least one interval has sticky properties, we check the stickiness property by property. @@ -1043,10 +1062,11 @@ adjust_intervals_for_insertion (tree, position, length) for (temp = i; temp; temp = INTERVAL_PARENT_OR_NULL (temp)) { temp->total_length += length; + CHECK_TOTAL_LENGTH (temp); temp = balance_possible_root_interval (temp); } } - + return tree; } @@ -1108,19 +1128,19 @@ merge_properties_sticky (pleft, pright) rrear = textget (pright, Qrear_nonsticky); /* Go through each element of PRIGHT. */ - for (tail1 = pright; CONSP (tail1); tail1 = Fcdr (Fcdr (tail1))) + for (tail1 = pright; CONSP (tail1); tail1 = Fcdr (XCDR (tail1))) { Lisp_Object tmp; - sym = Fcar (tail1); + sym = XCAR (tail1); /* Sticky properties get special treatment. */ if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky)) continue; - rval = Fcar (Fcdr (tail1)); - for (tail2 = pleft; CONSP (tail2); tail2 = Fcdr (Fcdr (tail2))) - if (EQ (sym, Fcar (tail2))) + rval = Fcar (XCDR (tail1)); + for (tail2 = pleft; CONSP (tail2); tail2 = Fcdr (XCDR (tail2))) + if (EQ (sym, XCAR (tail2))) break; /* Indicate whether the property is explicitly defined on the left. @@ -1166,24 +1186,24 @@ merge_properties_sticky (pleft, pright) } /* Now go through each element of PLEFT. */ - for (tail2 = pleft; CONSP (tail2); tail2 = Fcdr (Fcdr (tail2))) + for (tail2 = pleft; CONSP (tail2); tail2 = Fcdr (XCDR (tail2))) { Lisp_Object tmp; - sym = Fcar (tail2); + sym = XCAR (tail2); /* Sticky properties get special treatment. */ if (EQ (sym, Qrear_nonsticky) || EQ (sym, Qfront_sticky)) continue; /* If sym is in PRIGHT, we've already considered it. */ - for (tail1 = pright; CONSP (tail1); tail1 = Fcdr (Fcdr (tail1))) - if (EQ (sym, Fcar (tail1))) + for (tail1 = pright; CONSP (tail1); tail1 = Fcdr (XCDR (tail1))) + if (EQ (sym, XCAR (tail1))) break; if (! NILP (tail1)) continue; - lval = Fcar (Fcdr (tail2)); + lval = Fcar (XCDR (tail2)); /* Even if lrear or rfront say nothing about the stickiness of SYM, Vtext_property_default_nonsticky may give default @@ -1212,7 +1232,7 @@ merge_properties_sticky (pleft, pright) cat = textget (props, Qcategory); if (! NILP (front) - && + && /* If we have inherited a front-stick category property that is t, we don't need to set up a detailed one. */ ! (! NILP (cat) && SYMBOLP (cat) @@ -1222,7 +1242,7 @@ merge_properties_sticky (pleft, pright) } -/* Delete an node I from its interval tree by merging its subtrees +/* Delete a node I from its interval tree by merging its subtrees into one subtree which is then returned. Caller is responsible for storing the resulting subtree into its parent. */ @@ -1247,6 +1267,7 @@ delete_node (i) this = this->left; this->total_length += migrate_amt; } + CHECK_TOTAL_LENGTH (this); this->left = migrate; SET_INTERVAL_PARENT (migrate, this); @@ -1280,7 +1301,7 @@ delete_interval (i) if (BUFFERP (owner)) BUF_INTERVALS (XBUFFER (owner)) = parent; else if (STRINGP (owner)) - XSTRING (owner)->intervals = parent; + STRING_SET_INTERVALS (owner, parent); else abort (); @@ -1331,6 +1352,7 @@ interval_deletion_adjustment (tree, from, amount) relative_position, amount); tree->total_length -= subtract; + CHECK_TOTAL_LENGTH (tree); return subtract; } /* Right branch */ @@ -1345,13 +1367,14 @@ interval_deletion_adjustment (tree, from, amount) relative_position, amount); tree->total_length -= subtract; + CHECK_TOTAL_LENGTH (tree); return subtract; } /* Here -- this node. */ else { /* How much can we delete from this interval? */ - int my_amount = ((tree->total_length + int my_amount = ((tree->total_length - RIGHT_TOTAL_LENGTH (tree)) - relative_position); @@ -1359,9 +1382,10 @@ interval_deletion_adjustment (tree, from, amount) amount = my_amount; tree->total_length -= amount; + CHECK_TOTAL_LENGTH (tree); if (LENGTH (tree) == 0) delete_interval (tree); - + return amount; } @@ -1402,6 +1426,7 @@ adjust_intervals_for_deletion (buffer, start, length) if (ONLY_INTERVAL_P (tree)) { tree->total_length -= length; + CHECK_TOTAL_LENGTH (tree); return; } @@ -1457,6 +1482,7 @@ merge_interval_right (i) /* Zero out this interval. */ i->total_length -= absorb; + CHECK_TOTAL_LENGTH (i); /* Find the succeeding interval. */ if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb @@ -1466,10 +1492,12 @@ merge_interval_right (i) while (! NULL_LEFT_CHILD (successor)) { successor->total_length += absorb; + CHECK_TOTAL_LENGTH (successor); successor = successor->left; } successor->total_length += absorb; + CHECK_TOTAL_LENGTH (successor); delete_interval (i); return successor; } @@ -1487,6 +1515,7 @@ merge_interval_right (i) successor = INTERVAL_PARENT (successor); successor->total_length -= absorb; + CHECK_TOTAL_LENGTH (successor); } /* This must be the rightmost or last interval and cannot @@ -1510,6 +1539,7 @@ merge_interval_left (i) /* Zero out this interval. */ i->total_length -= absorb; + CHECK_TOTAL_LENGTH (i); /* Find the preceding interval. */ if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down, @@ -1519,10 +1549,12 @@ merge_interval_left (i) while (! NULL_RIGHT_CHILD (predecessor)) { predecessor->total_length += absorb; + CHECK_TOTAL_LENGTH (predecessor); predecessor = predecessor->right; } predecessor->total_length += absorb; + CHECK_TOTAL_LENGTH (predecessor); delete_interval (i); return predecessor; } @@ -1540,6 +1572,7 @@ merge_interval_left (i) predecessor = INTERVAL_PARENT (predecessor); predecessor->total_length -= absorb; + CHECK_TOTAL_LENGTH (predecessor); } /* This must be the leftmost or first interval and cannot @@ -1680,6 +1713,7 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit) { register INTERVAL under, over, this, prev; register INTERVAL tree; + int over_used; tree = BUF_INTERVALS (buffer); @@ -1698,6 +1732,7 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit) Qnil, buf, 0); } if (! NULL_INTERVAL_P (BUF_INTERVALS (buffer))) + /* Shouldn't be necessary. -stef */ BUF_INTERVALS (buffer) = balance_an_interval (BUF_INTERVALS (buffer)); return; } @@ -1711,7 +1746,8 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit) Lisp_Object buf; XSETBUFFER (buf, buffer); BUF_INTERVALS (buffer) = reproduce_tree_obj (source, buf); - BUF_INTERVALS (buffer)->position = 1; + BUF_INTERVALS (buffer)->position = BEG; + BUF_INTERVALS (buffer)->up_obj = 1; /* Explicitly free the old tree here? */ @@ -1733,7 +1769,8 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit) about inserting properly. For now, just waste the old intervals. */ { BUF_INTERVALS (buffer) = reproduce_tree (source, INTERVAL_PARENT (tree)); - BUF_INTERVALS (buffer)->position = 1; + BUF_INTERVALS (buffer)->position = BEG; + BUF_INTERVALS (buffer)->up_obj = 1; /* Explicitly free the old tree here. */ return; @@ -1780,22 +1817,43 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit) The properties of under are the result of adjust_intervals_for_insertion, so stickiness has already been taken care of. */ - + + /* OVER is the interval we are copying from next. + OVER_USED says how many characters' worth of OVER + have already been copied into target intervals. + UNDER is the next interval in the target. */ + over_used = 0; while (! NULL_INTERVAL_P (over)) { - if (LENGTH (over) < LENGTH (under)) + /* If UNDER is longer than OVER, split it. */ + if (LENGTH (over) - over_used < LENGTH (under)) { - this = split_interval_left (under, LENGTH (over)); + this = split_interval_left (under, LENGTH (over) - over_used); copy_properties (under, this); } else this = under; - copy_properties (over, this); + + /* THIS is now the interval to copy or merge into. + OVER covers all of it. */ if (inherit) merge_properties (over, this); else copy_properties (over, this); - over = next_interval (over); + + /* If THIS and OVER end at the same place, + advance OVER to a new source interval. */ + if (LENGTH (this) == LENGTH (over) - over_used) + { + over = next_interval (over); + over_used = 0; + } + else + /* Otherwise just record that more of OVER has been used. */ + over_used += LENGTH (this); + + /* Always advance to a new target interval. */ + under = next_interval (this); } if (! NULL_INTERVAL_P (BUF_INTERVALS (buffer))) @@ -1805,7 +1863,7 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit) /* Get the value of property PROP from PLIST, which is the plist of an interval. - We check for direct properties, for categories with property PROP, + We check for direct properties, for categories with property PROP, and for PROP appearing on the default-text-properties list. */ Lisp_Object @@ -1813,18 +1871,26 @@ textget (plist, prop) Lisp_Object plist; register Lisp_Object prop; { - register Lisp_Object tail, fallback; - fallback = Qnil; + return lookup_char_property (plist, prop, 1); +} + +Lisp_Object +lookup_char_property (plist, prop, textprop) + Lisp_Object plist; + register Lisp_Object prop; + int textprop; +{ + register Lisp_Object tail, fallback = Qnil; - for (tail = plist; !NILP (tail); tail = Fcdr (Fcdr (tail))) + for (tail = plist; CONSP (tail); tail = Fcdr (XCDR (tail))) { register Lisp_Object tem; - tem = Fcar (tail); + tem = XCAR (tail); if (EQ (prop, tem)) - return Fcar (Fcdr (tail)); + return Fcar (XCDR (tail)); if (EQ (tem, Qcategory)) { - tem = Fcar (Fcdr (tail)); + tem = Fcar (XCDR (tail)); if (SYMBOLP (tem)) fallback = Fget (tem, prop); } @@ -1832,9 +1898,18 @@ textget (plist, prop) if (! NILP (fallback)) return fallback; - if (CONSP (Vdefault_text_properties)) - return Fplist_get (Vdefault_text_properties, prop); - return Qnil; + /* Check for alternative properties */ + tail = Fassq (prop, Vchar_property_alias_alist); + if (! NILP (tail)) + { + tail = XCDR (tail); + for (; NILP (fallback) && CONSP (tail); tail = XCDR (tail)) + fallback = Fplist_get (plist, XCAR (tail)); + } + + if (textprop && NILP (fallback) && CONSP (Vdefault_text_properties)) + fallback = Fplist_get (Vdefault_text_properties, prop); + return fallback; } @@ -1872,7 +1947,7 @@ temp_set_point_both (buffer, charpos, bytepos) BUF_PT (buffer) = charpos; } -/* Set point in BUFFER to CHARPOS. If the target position is +/* Set point in BUFFER to CHARPOS. If the target position is before an intangible character, move to an ok place. */ void @@ -1883,8 +1958,54 @@ set_point (buffer, charpos) set_point_both (buffer, charpos, buf_charpos_to_bytepos (buffer, charpos)); } +/* If there's an invisible character at position POS + TEST_OFFS in the + current buffer, and the invisible property has a `stickiness' such that + inserting a character at position POS would inherit the property it, + return POS + ADJ, otherwise return POS. If TEST_INTANG is non-zero, + then intangibility is required as well as invisibleness. + + TEST_OFFS should be either 0 or -1, and ADJ should be either 1 or -1. + + Note that `stickiness' is determined by overlay marker insertion types, + if the invisible property comes from an overlay. */ + +static int +adjust_for_invis_intang (pos, test_offs, adj, test_intang) + int pos, test_offs, adj, test_intang; +{ + Lisp_Object invis_propval, invis_overlay; + Lisp_Object test_pos; + + if ((adj < 0 && pos + adj < BEGV) || (adj > 0 && pos + adj > ZV)) + /* POS + ADJ would be beyond the buffer bounds, so do no adjustment. */ + return pos; + + test_pos = make_number (pos + test_offs); + + invis_propval + = get_char_property_and_overlay (test_pos, Qinvisible, Qnil, + &invis_overlay); + + if ((!test_intang + || ! NILP (Fget_char_property (test_pos, Qintangible, Qnil))) + && TEXT_PROP_MEANS_INVISIBLE (invis_propval) + /* This next test is true if the invisible property has a stickiness + such that an insertion at POS would inherit it. */ + && (NILP (invis_overlay) + /* Invisible property is from a text-property. */ + ? (text_property_stickiness (Qinvisible, make_number (pos), Qnil) + == (test_offs == 0 ? 1 : -1)) + /* Invisible property is from an overlay. */ + : (test_offs == 0 + ? XMARKER (OVERLAY_START (invis_overlay))->insertion_type == 0 + : XMARKER (OVERLAY_END (invis_overlay))->insertion_type == 1))) + pos += adj; + + return pos; +} + /* Set point in BUFFER to CHARPOS, which corresponds to byte - position BYTEPOS. If the target position is + position BYTEPOS. If the target position is before an intangible character, move to an ok place. */ void @@ -1915,8 +2036,7 @@ set_point_both (buffer, charpos, bytepos) if (charpos > BUF_ZV (buffer) || charpos < BUF_BEGV (buffer)) abort (); - have_overlays = (! NILP (buffer->overlays_before) - || ! NILP (buffer->overlays_after)); + have_overlays = (buffer->overlays_before || buffer->overlays_after); /* If we have no text properties and overlays, then we can do it quickly. */ @@ -1975,26 +2095,19 @@ set_point_both (buffer, charpos, bytepos) or end of the buffer, so don't bother checking in that case. */ && charpos != BEGV && charpos != ZV) { - Lisp_Object intangible_propval, invisible_propval; Lisp_Object pos; - int invis_p; - - XSETINT (pos, charpos); + Lisp_Object intangible_propval; if (backwards) { - /* If the preceding char is both invisible and intangible, - start backing up from just before that one. */ - - intangible_propval - = Fget_char_property (make_number (charpos - 1), - Qintangible, Qnil); - invisible_propval - = Fget_char_property (make_number (charpos - 1), Qinvisible, Qnil); - invis_p = TEXT_PROP_MEANS_INVISIBLE (invisible_propval); + /* If the preceding character is both intangible and invisible, + and the invisible property is `rear-sticky', perturb it so + that the search starts one character earlier -- this ensures + that point can never move to the end of an invisible/ + intangible/rear-sticky region. */ + charpos = adjust_for_invis_intang (charpos, -1, -1, 1); - if (! NILP (intangible_propval) && invis_p) - XSETINT (pos, --charpos); + XSETINT (pos, charpos); /* If following char is intangible, skip back over all chars with matching intangible property. */ @@ -2008,10 +2121,26 @@ set_point_both (buffer, charpos, bytepos) Qintangible, Qnil), intangible_propval)) pos = Fprevious_char_property_change (pos, Qnil); + + /* Set CHARPOS from POS, and if the final intangible character + that we skipped over is also invisible, and the invisible + property is `front-sticky', perturb it to be one character + earlier -- this ensures that point can never move to the + beginning of an invisible/intangible/front-sticky region. */ + charpos = adjust_for_invis_intang (XINT (pos), 0, -1, 0); } } else { + /* If the following character is both intangible and invisible, + and the invisible property is `front-sticky', perturb it so + that the search starts one character later -- this ensures + that point can never move to the beginning of an + invisible/intangible/front-sticky region. */ + charpos = adjust_for_invis_intang (charpos, 0, 1, 1); + + XSETINT (pos, charpos); + /* If preceding char is intangible, skip forward over all chars with matching intangible property. */ @@ -2025,22 +2154,15 @@ set_point_both (buffer, charpos, bytepos) intangible_propval)) pos = Fnext_char_property_change (pos, Qnil); - /* Is the last one invisible as well as intangible? */ - - invisible_propval - = Fget_char_property (make_number (XINT (pos) - 1), - Qinvisible, Qnil); - invis_p = TEXT_PROP_MEANS_INVISIBLE (invisible_propval); - - /* If so, advance one character more: - don't stop after an invisible, intangible character. */ - - if (invis_p && XINT (pos) < BUF_ZV (buffer)) - XSETINT (pos, XINT (pos) + 1); + /* Set CHARPOS from POS, and if the final intangible character + that we skipped over is also invisible, and the invisible + property is `rear-sticky', perturb it to be one character + later -- this ensures that point can never move to the + end of an invisible/intangible/rear-sticky region. */ + charpos = adjust_for_invis_intang (XINT (pos), -1, 1, 0); } } - charpos = XINT (pos); bytepos = buf_charpos_to_bytepos (buffer, charpos); } @@ -2154,8 +2276,12 @@ move_if_not_intangible (position) pos = Fnext_char_property_change (pos, Qnil); } + else if (position < BEGV) + position = BEGV; + else if (position > ZV) + position = ZV; - /* If the whole stretch between PT and POSITION isn't intangible, + /* If the whole stretch between PT and POSITION isn't intangible, try moving to POSITION (which means we actually move farther if POSITION is inside of intangible text). */ @@ -2184,7 +2310,7 @@ get_property_and_range (pos, prop, val, start, end, object) else if (BUFFERP (object)) i = find_interval (BUF_INTERVALS (XBUFFER (object)), pos); else if (STRINGP (object)) - i = find_interval (XSTRING (object)->intervals, pos); + i = find_interval (STRING_INTERVALS (object), pos); else abort (); @@ -2202,7 +2328,7 @@ get_property_and_range (pos, prop, val, start, end, object) *start = i->position; next = next_interval (i); - while (! NULL_INTERVAL_P (next) + while (! NULL_INTERVAL_P (next) && EQ (*val, textget (next->plist, prop))) i = next, next = next_interval (next); *end = i->position + LENGTH (i); @@ -2239,13 +2365,17 @@ get_local_map (position, buffer, type) BUF_BEGV_BYTE (buffer) = BUF_BEG_BYTE (buffer); BUF_ZV_BYTE (buffer) = BUF_Z_BYTE (buffer); - /* There are no properties at the end of the buffer, so in that case - check for a local map on the last character of the buffer instead. */ - if (position == BUF_Z (buffer) && BUF_Z (buffer) > BUF_BEG (buffer)) - --position; XSETFASTINT (lispy_position, position); XSETBUFFER (lispy_buffer, buffer); + /* First check if the CHAR has any property. This is because when + we click with the mouse, the mouse pointer is really pointing + to the CHAR after POS. */ prop = Fget_char_property (lispy_position, type, lispy_buffer); + /* If not, look at the POS's properties. This is necessary because when + editing a field with a `local-map' property, we want insertion at the end + to obey the `local-map' property. */ + if (NILP (prop)) + prop = get_pos_property (lispy_position, type, lispy_buffer); BUF_BEGV (buffer) = old_begv; BUF_ZV (buffer) = old_zv; @@ -2291,6 +2421,7 @@ copy_intervals (tree, start, length) new->position = 0; got = (LENGTH (i) - (start - i->position)); new->total_length = length; + CHECK_TOTAL_LENGTH (new); copy_properties (i, new); t = new; @@ -2321,7 +2452,7 @@ copy_intervals_to_string (string, buffer, position, length) return; SET_INTERVAL_OBJECT (interval_copy, string); - XSTRING (string)->intervals = interval_copy; + STRING_SET_INTERVALS (string, interval_copy); } /* Return 1 if strings S1 and S2 have identical properties; 0 otherwise. @@ -2333,10 +2464,10 @@ compare_string_intervals (s1, s2) { INTERVAL i1, i2; int pos = 0; - int end = XSTRING (s1)->size; + int end = SCHARS (s1); - i1 = find_interval (XSTRING (s1)->intervals, 0); - i2 = find_interval (XSTRING (s2)->intervals, 0); + i1 = find_interval (STRING_INTERVALS (s1), 0); + i2 = find_interval (STRING_INTERVALS (s2), 0); while (pos < end) { @@ -2377,6 +2508,13 @@ set_intervals_multibyte_1 (i, multi_flag, start, start_byte, end, end_byte) i->total_length = end - start; else i->total_length = end_byte - start_byte; + CHECK_TOTAL_LENGTH (i); + + if (TOTAL_LENGTH (i) == 0) + { + delete_interval (i); + return; + } /* Recursively fix the length of the subintervals. */ if (i->left) @@ -2385,8 +2523,23 @@ set_intervals_multibyte_1 (i, multi_flag, start, start_byte, end, end_byte) if (multi_flag) { + int temp; left_end_byte = start_byte + LEFT_TOTAL_LENGTH (i); left_end = BYTE_TO_CHAR (left_end_byte); + + temp = CHAR_TO_BYTE (left_end); + + /* If LEFT_END_BYTE is in the middle of a character, + adjust it and LEFT_END to a char boundary. */ + if (left_end_byte > temp) + { + left_end_byte = temp; + } + if (left_end_byte < temp) + { + left_end--; + left_end_byte = CHAR_TO_BYTE (left_end); + } } else { @@ -2403,8 +2556,24 @@ set_intervals_multibyte_1 (i, multi_flag, start, start_byte, end, end_byte) if (multi_flag) { + int temp; + right_start_byte = end_byte - RIGHT_TOTAL_LENGTH (i); right_start = BYTE_TO_CHAR (right_start_byte); + + /* If RIGHT_START_BYTE is in the middle of a character, + adjust it and RIGHT_START to a char boundary. */ + temp = CHAR_TO_BYTE (right_start); + + if (right_start_byte < temp) + { + right_start_byte = temp; + } + if (right_start_byte > temp) + { + right_start++; + right_start_byte = CHAR_TO_BYTE (right_start); + } } else { @@ -2416,6 +2585,25 @@ set_intervals_multibyte_1 (i, multi_flag, start, start_byte, end, end_byte) right_start, right_start_byte, end, end_byte); } + + /* Rounding to char boundaries can theoretically ake this interval + spurious. If so, delete one child, and copy its property list + to this interval. */ + if (LEFT_TOTAL_LENGTH (i) + RIGHT_TOTAL_LENGTH (i) >= TOTAL_LENGTH (i)) + { + if ((i)->left) + { + (i)->plist = (i)->left->plist; + (i)->left->total_length = 0; + delete_interval ((i)->left); + } + else + { + (i)->plist = (i)->right->plist; + (i)->right->total_length = 0; + delete_interval ((i)->right); + } + } } /* Update the intervals of the current buffer @@ -2430,3 +2618,6 @@ set_intervals_multibyte (multi_flag) set_intervals_multibyte_1 (BUF_INTERVALS (current_buffer), multi_flag, BEG, BEG_BYTE, Z, Z_BYTE); } + +/* arch-tag: 3d402b60-083c-4271-b4a3-ebd9a74bfe27 + (do not change this comment) */