diff options
author | Stefan Monnier <monnier@iro.umontreal.ca> | 2022-09-25 16:15:16 -0400 |
---|---|---|
committer | Stefan Monnier <monnier@iro.umontreal.ca> | 2022-09-25 16:15:16 -0400 |
commit | 650c20f1ca4e07591a727e1cfcc74b3363d15985 (patch) | |
tree | 85d11f6437cde22f410c25e0e5f71a3131ebd07d /src/textprop.c | |
parent | 8869332684c2302b5ba1ead4568bbc7ba1c0183e (diff) | |
parent | 4b85ae6a24380fb67a3315eaec9233f17a872473 (diff) | |
download | emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.gz emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.bz2 emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.zip |
Merge 'master' into noverlay
Diffstat (limited to 'src/textprop.c')
-rw-r--r-- | src/textprop.c | 494 |
1 files changed, 283 insertions, 211 deletions
diff --git a/src/textprop.c b/src/textprop.c index aebb6524e68..c2c3622d05f 100644 --- a/src/textprop.c +++ b/src/textprop.c @@ -1,6 +1,5 @@ /* Interface code for dealing with text properties. - Copyright (C) 1993-1995, 1997, 1999-2017 Free Software Foundation, - Inc. + Copyright (C) 1993-2022 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -58,14 +57,13 @@ enum property_set_type /* verify_interval_modification saves insertion hooks here to be run later by report_interval_modification. */ -static Lisp_Object interval_insert_behind_hooks; -static Lisp_Object interval_insert_in_front_hooks; - +Lisp_Object interval_insert_behind_hooks; +Lisp_Object interval_insert_in_front_hooks; /* Signal a `text-read-only' error. This function makes it easier to capture that error in GDB by putting a breakpoint on it. */ -static _Noreturn void +static AVOID text_read_only (Lisp_Object propval) { if (STRINGP (propval)) @@ -79,7 +77,7 @@ text_read_only (Lisp_Object propval) static void modify_text_properties (Lisp_Object buffer, Lisp_Object start, Lisp_Object end) { - ptrdiff_t b = XINT (start), e = XINT (end); + ptrdiff_t b = XFIXNUM (start), e = XFIXNUM (end); struct buffer *buf = XBUFFER (buffer), *old = current_buffer; set_buffer_internal (buf); @@ -89,7 +87,7 @@ modify_text_properties (Lisp_Object buffer, Lisp_Object start, Lisp_Object end) BUF_COMPUTE_UNCHANGED (buf, b - 1, e); if (MODIFF <= SAVE_MODIFF) record_first_change (); - MODIFF++; + modiff_incr (&MODIFF, 1); bset_point_before_scroll (current_buffer, Qnil); @@ -111,9 +109,6 @@ CHECK_STRING_OR_BUFFER (Lisp_Object x) to by BEGIN and END may be integers or markers; if the latter, they are coerced to integers. - When OBJECT is a string, we increment *BEGIN and *END - to make them origin-one. - Note that buffer points don't correspond to interval indices. For example, point-max is 1 greater than the index of the last character. This difference is handled in the caller, which uses @@ -135,17 +130,18 @@ validate_interval_range (Lisp_Object object, Lisp_Object *begin, { INTERVAL i; ptrdiff_t searchpos; + Lisp_Object begin0 = *begin, end0 = *end; CHECK_STRING_OR_BUFFER (object); - CHECK_NUMBER_COERCE_MARKER (*begin); - CHECK_NUMBER_COERCE_MARKER (*end); + CHECK_FIXNUM_COERCE_MARKER (*begin); + CHECK_FIXNUM_COERCE_MARKER (*end); /* If we are asked for a point, but from a subr which operates on a range, then return nothing. */ if (EQ (*begin, *end) && begin != end) return NULL; - if (XINT (*begin) > XINT (*end)) + if (XFIXNUM (*begin) > XFIXNUM (*end)) { Lisp_Object n; n = *begin; @@ -157,33 +153,30 @@ validate_interval_range (Lisp_Object object, Lisp_Object *begin, { register struct buffer *b = XBUFFER (object); - if (!(BUF_BEGV (b) <= XINT (*begin) && XINT (*begin) <= XINT (*end) - && XINT (*end) <= BUF_ZV (b))) - args_out_of_range (*begin, *end); + if (!(BUF_BEGV (b) <= XFIXNUM (*begin) && XFIXNUM (*begin) <= XFIXNUM (*end) + && XFIXNUM (*end) <= BUF_ZV (b))) + args_out_of_range (begin0, end0); i = buffer_intervals (b); /* If there's no text, there are no properties. */ if (BUF_BEGV (b) == BUF_ZV (b)) return NULL; - searchpos = XINT (*begin); + searchpos = XFIXNUM (*begin); } else { ptrdiff_t len = SCHARS (object); - if (! (0 <= XINT (*begin) && XINT (*begin) <= XINT (*end) - && XINT (*end) <= len)) - args_out_of_range (*begin, *end); - XSETFASTINT (*begin, XFASTINT (*begin)); - if (begin != end) - XSETFASTINT (*end, XFASTINT (*end)); + if (! (0 <= XFIXNUM (*begin) && XFIXNUM (*begin) <= XFIXNUM (*end) + && XFIXNUM (*end) <= len)) + args_out_of_range (begin0, end0); i = string_intervals (object); if (len == 0) return NULL; - searchpos = XINT (*begin); + searchpos = XFIXNUM (*begin); } if (!i) @@ -347,7 +340,7 @@ set_properties (Lisp_Object properties, INTERVAL interval, Lisp_Object object) for (sym = properties; PLIST_ELT_P (sym, value); sym = XCDR (value)) - if (EQ (property_value (interval->plist, XCAR (sym)), Qunbound)) + if (BASE_EQ (property_value (interval->plist, XCAR (sym)), Qunbound)) { record_property_change (interval->position, LENGTH (interval), XCAR (sym), Qnil, @@ -365,12 +358,15 @@ set_properties (Lisp_Object properties, INTERVAL interval, Lisp_Object object) OBJECT should be the string or buffer the interval is in. + If DESTRUCTIVE, the function is allowed to reuse list values in the + properties. + Return true if this changes I (i.e., if any members of PLIST are actually added to I's plist) */ static bool add_properties (Lisp_Object plist, INTERVAL i, Lisp_Object object, - enum property_set_type set_type) + enum property_set_type set_type, bool destructive) { Lisp_Object tail1, tail2, sym1, val1; bool changed = false; @@ -421,7 +417,15 @@ add_properties (Lisp_Object plist, INTERVAL i, Lisp_Object object, if (set_type == TEXT_PROPERTY_PREPEND) Fsetcar (this_cdr, Fcons (val1, Fcar (this_cdr))); else - nconc2 (Fcar (this_cdr), list1 (val1)); + { + /* Appending. */ + if (destructive) + nconc2 (Fcar (this_cdr), list1 (val1)); + else + Fsetcar (this_cdr, CALLN (Fappend, + Fcar (this_cdr), + list1 (val1))); + } else { /* The previous value is a single value, so make it into a list. */ @@ -544,7 +548,7 @@ interval_of (ptrdiff_t position, Lisp_Object object) } if (!(beg <= position && position <= end)) - args_out_of_range (make_number (position), make_number (position)); + args_out_of_range (make_fixnum (position), make_fixnum (position)); if (beg == end || !i) return NULL; @@ -556,8 +560,16 @@ DEFUN ("text-properties-at", Ftext_properties_at, doc: /* Return the list of properties of the character at POSITION in OBJECT. If the optional second argument OBJECT is a buffer (or nil, which means the current buffer), POSITION is a buffer position (integer or marker). + If OBJECT is a string, POSITION is a 0-based index into it. -If POSITION is at the end of OBJECT, the value is nil. */) + +If POSITION is at the end of OBJECT, the value is nil, but note that +buffer narrowing does not affect the value. That is, if OBJECT is a +buffer or nil, and the buffer is narrowed and POSITION is at the end +of the narrowed buffer, the result may be non-nil. + +If you want to display the text properties at point in a human-readable +form, use the `describe-text-properties' command. */) (Lisp_Object position, Lisp_Object object) { register INTERVAL i; @@ -572,7 +584,7 @@ If POSITION is at the end of OBJECT, the value is nil. */) it means it's the end of OBJECT. There are no properties at the very end, since no character follows. */ - if (XINT (position) == LENGTH (i) + i->position) + if (XFIXNUM (position) == LENGTH (i) + i->position) return Qnil; return i->plist; @@ -582,7 +594,11 @@ DEFUN ("get-text-property", Fget_text_property, Sget_text_property, 2, 3, 0, doc: /* Return the value of POSITION's property PROP, in OBJECT. OBJECT should be a buffer or a string; if omitted or nil, it defaults to the current buffer. -If POSITION is at the end of OBJECT, the value is nil. */) + +If POSITION is at the end of OBJECT, the value is nil, but note that +buffer narrowing does not affect the value. That is, if the buffer is +narrowed and POSITION is at the end of the narrowed buffer, the result +may be non-nil. */) (Lisp_Object position, Lisp_Object prop, Lisp_Object object) { return textget (Ftext_properties_at (position, object), prop); @@ -604,7 +620,7 @@ get_char_property_and_overlay (Lisp_Object position, register Lisp_Object prop, { struct window *w = 0; - CHECK_NUMBER_COERCE_MARKER (position); + EMACS_INT pos = fix_position (position); if (NILP (object)) XSETBUFFER (object, current_buffer); @@ -623,11 +639,11 @@ get_char_property_and_overlay (Lisp_Object position, register Lisp_Object prop, struct sortvec *result = NULL; Lisp_Object result_tem = Qnil; - if (XINT (position) < BUF_BEGV (b) || XINT (position) > BUF_ZV (b)) + if (! (BUF_BEGV (b) <= pos + && pos <= BUF_ZV (b))) xsignal1 (Qargs_out_of_range, position); - buffer_overlay_iter_start(b, XINT (position), XINT (position) + 1, - ITREE_ASCENDING); + buffer_overlay_iter_start (b, pos, pos + 1, ITREE_ASCENDING); /* Now check the overlays in order of decreasing priority. */ while ((node = buffer_overlay_iter_next (b))) @@ -661,7 +677,7 @@ get_char_property_and_overlay (Lisp_Object position, register Lisp_Object prop, /* Not a buffer, or no appropriate overlay, so fall through to the simpler case. */ - return Fget_text_property (position, prop, object); + return Fget_text_property (make_fixnum (pos), prop, object); } DEFUN ("get-char-property", Fget_char_property, Sget_char_property, 2, 3, 0, @@ -720,8 +736,8 @@ before LIMIT. LIMIT is a no-op if it is greater than (point-max). */) temp = Fnext_overlay_change (position); if (! NILP (limit)) { - CHECK_NUMBER_COERCE_MARKER (limit); - if (XINT (limit) < XINT (temp)) + CHECK_FIXNUM_COERCE_MARKER (limit); + if (XFIXNUM (limit) < XFIXNUM (temp)) temp = limit; } return Fnext_property_change (position, Qnil, temp); @@ -746,8 +762,8 @@ before LIMIT. LIMIT is a no-op if it is less than (point-min). */) temp = Fprevious_overlay_change (position); if (! NILP (limit)) { - CHECK_NUMBER_COERCE_MARKER (limit); - if (XINT (limit) > XINT (temp)) + CHECK_FIXNUM_COERCE_MARKER (limit); + if (XFIXNUM (limit) > XFIXNUM (temp)) temp = limit; } return Fprevious_property_change (position, Qnil, temp); @@ -764,14 +780,13 @@ the current buffer), POSITION is a buffer position (integer or marker). If OBJECT is a string, POSITION is a 0-based index into it. In a string, scan runs to the end of the string, unless LIMIT is non-nil. -In a buffer, if LIMIT is nil or omitted, it runs to (point-max), and the -value cannot exceed that. +In a buffer, scan runs to end of buffer, unless LIMIT is non-nil. If the optional fourth argument LIMIT is non-nil, don't search past position LIMIT; return LIMIT if nothing is found before LIMIT. +However, if OBJECT is a buffer and LIMIT is beyond the end of the +buffer, this function returns `point-max', not LIMIT. -The property values are compared with `eq'. -If the property is constant all the way to the end of OBJECT, return the -last valid position in OBJECT. */) +The property values are compared with `eq'. */) (Lisp_Object position, Lisp_Object prop, Lisp_Object object, Lisp_Object limit) { if (STRINGP (object)) @@ -780,10 +795,10 @@ last valid position in OBJECT. */) if (NILP (position)) { if (NILP (limit)) - position = make_number (SCHARS (object)); + position = make_fixnum (SCHARS (object)); else { - CHECK_NUMBER (limit); + CHECK_FIXNUM (limit); position = limit; } } @@ -791,7 +806,7 @@ last valid position in OBJECT. */) else { Lisp_Object initial_value, value; - ptrdiff_t count = SPECPDL_INDEX (); + specpdl_ref count = SPECPDL_INDEX (); if (! NILP (object)) CHECK_BUFFER (object); @@ -802,26 +817,26 @@ last valid position in OBJECT. */) Fset_buffer (object); } - CHECK_NUMBER_COERCE_MARKER (position); + CHECK_FIXNUM_COERCE_MARKER (position); initial_value = Fget_char_property (position, prop, object); if (NILP (limit)) XSETFASTINT (limit, ZV); else - CHECK_NUMBER_COERCE_MARKER (limit); + CHECK_FIXNUM_COERCE_MARKER (limit); - if (XFASTINT (position) >= XFASTINT (limit)) + if (XFIXNUM (position) >= XFIXNUM (limit)) { position = limit; - if (XFASTINT (position) > ZV) + if (XFIXNUM (position) > ZV) XSETFASTINT (position, ZV); } else while (true) { position = Fnext_char_property_change (position, limit); - if (XFASTINT (position) >= XFASTINT (limit)) + if (XFIXNAT (position) >= XFIXNAT (limit)) { position = limit; break; @@ -830,9 +845,12 @@ last valid position in OBJECT. */) value = Fget_char_property (position, prop, object); if (!EQ (value, initial_value)) break; + + if (XFIXNAT (position) >= ZV) + break; } - unbind_to (count, Qnil); + position = unbind_to (count, position); } return position; @@ -865,17 +883,17 @@ first valid position in OBJECT. */) if (NILP (position)) { if (NILP (limit)) - position = make_number (0); + position = make_fixnum (0); else { - CHECK_NUMBER (limit); + CHECK_FIXNUM (limit); position = limit; } } } else { - ptrdiff_t count = SPECPDL_INDEX (); + specpdl_ref count = SPECPDL_INDEX (); if (! NILP (object)) CHECK_BUFFER (object); @@ -886,30 +904,31 @@ first valid position in OBJECT. */) Fset_buffer (object); } - CHECK_NUMBER_COERCE_MARKER (position); + CHECK_FIXNUM_COERCE_MARKER (position); if (NILP (limit)) XSETFASTINT (limit, BEGV); else - CHECK_NUMBER_COERCE_MARKER (limit); + CHECK_FIXNUM_COERCE_MARKER (limit); - if (XFASTINT (position) <= XFASTINT (limit)) + if (XFIXNUM (position) <= XFIXNUM (limit)) { position = limit; - if (XFASTINT (position) < BEGV) + if (XFIXNUM (position) < BEGV) XSETFASTINT (position, BEGV); } else { Lisp_Object initial_value - = Fget_char_property (make_number (XFASTINT (position) - 1), + = Fget_char_property (make_fixnum (XFIXNUM (position) + - (0 <= XFIXNUM (position))), prop, object); while (true) { position = Fprevious_char_property_change (position, limit); - if (XFASTINT (position) <= XFASTINT (limit)) + if (XFIXNAT (position) <= XFIXNAT (limit)) { position = limit; break; @@ -917,7 +936,7 @@ first valid position in OBJECT. */) else { Lisp_Object value - = Fget_char_property (make_number (XFASTINT (position) - 1), + = Fget_char_property (make_fixnum (XFIXNAT (position) - 1), prop, object); if (!EQ (value, initial_value)) @@ -926,7 +945,7 @@ first valid position in OBJECT. */) } } - unbind_to (count, Qnil); + position = unbind_to (count, position); } return position; @@ -954,7 +973,7 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT. */) XSETBUFFER (object, current_buffer); if (!NILP (limit) && !EQ (limit, Qt)) - CHECK_NUMBER_COERCE_MARKER (limit); + CHECK_FIXNUM_COERCE_MARKER (limit); i = validate_interval_range (object, &position, &position, soft); @@ -982,19 +1001,19 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT. */) next = next_interval (i); while (next && intervals_equal (i, next) - && (NILP (limit) || next->position < XFASTINT (limit))) + && (NILP (limit) || next->position < XFIXNUM (limit))) next = next_interval (next); if (!next || (next->position - >= (INTEGERP (limit) - ? XFASTINT (limit) + >= (FIXNUMP (limit) + ? XFIXNUM (limit) : (STRINGP (object) ? SCHARS (object) : BUF_ZV (XBUFFER (object)))))) return limit; else - return make_number (next->position); + return make_fixnum (next->position); } DEFUN ("next-single-property-change", Fnext_single_property_change, @@ -1021,7 +1040,7 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT. */) XSETBUFFER (object, current_buffer); if (!NILP (limit)) - CHECK_NUMBER_COERCE_MARKER (limit); + CHECK_FIXNUM_COERCE_MARKER (limit); i = validate_interval_range (object, &position, &position, soft); if (!i) @@ -1031,19 +1050,19 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT. */) next = next_interval (i); while (next && EQ (here_val, textget (next->plist, prop)) - && (NILP (limit) || next->position < XFASTINT (limit))) + && (NILP (limit) || next->position < XFIXNUM (limit))) next = next_interval (next); if (!next || (next->position - >= (INTEGERP (limit) - ? XFASTINT (limit) + >= (FIXNUMP (limit) + ? XFIXNUM (limit) : (STRINGP (object) ? SCHARS (object) : BUF_ZV (XBUFFER (object)))))) return limit; else - return make_number (next->position); + return make_fixnum (next->position); } DEFUN ("previous-property-change", Fprevious_property_change, @@ -1068,30 +1087,30 @@ back past position LIMIT; return LIMIT if nothing is found until LIMIT. */) XSETBUFFER (object, current_buffer); if (!NILP (limit)) - CHECK_NUMBER_COERCE_MARKER (limit); + CHECK_FIXNUM_COERCE_MARKER (limit); i = validate_interval_range (object, &position, &position, soft); if (!i) return limit; /* Start with the interval containing the char before point. */ - if (i->position == XFASTINT (position)) + if (i->position == XFIXNAT (position)) i = previous_interval (i); previous = previous_interval (i); while (previous && intervals_equal (previous, i) && (NILP (limit) - || (previous->position + LENGTH (previous) > XFASTINT (limit)))) + || (previous->position + LENGTH (previous) > XFIXNUM (limit)))) previous = previous_interval (previous); if (!previous || (previous->position + LENGTH (previous) - <= (INTEGERP (limit) - ? XFASTINT (limit) + <= (FIXNUMP (limit) + ? XFIXNUM (limit) : (STRINGP (object) ? 0 : BUF_BEGV (XBUFFER (object)))))) return limit; else - return make_number (previous->position + LENGTH (previous)); + return make_fixnum (previous->position + LENGTH (previous)); } DEFUN ("previous-single-property-change", Fprevious_single_property_change, @@ -1118,12 +1137,12 @@ back past position LIMIT; return LIMIT if nothing is found until LIMIT. */) XSETBUFFER (object, current_buffer); if (!NILP (limit)) - CHECK_NUMBER_COERCE_MARKER (limit); + CHECK_FIXNUM_COERCE_MARKER (limit); i = validate_interval_range (object, &position, &position, soft); /* Start with the interval containing the char before point. */ - if (i && i->position == XFASTINT (position)) + if (i && i->position == XFIXNAT (position)) i = previous_interval (i); if (!i) @@ -1134,17 +1153,17 @@ back past position LIMIT; return LIMIT if nothing is found until LIMIT. */) while (previous && EQ (here_val, textget (previous->plist, prop)) && (NILP (limit) - || (previous->position + LENGTH (previous) > XFASTINT (limit)))) + || (previous->position + LENGTH (previous) > XFIXNUM (limit)))) previous = previous_interval (previous); if (!previous || (previous->position + LENGTH (previous) - <= (INTEGERP (limit) - ? XFASTINT (limit) + <= (FIXNUMP (limit) + ? XFIXNUM (limit) : (STRINGP (object) ? 0 : BUF_BEGV (XBUFFER (object)))))) return limit; else - return make_number (previous->position + LENGTH (previous)); + return make_fixnum (previous->position + LENGTH (previous)); } /* Used by add-text-properties and add-face-text-property. */ @@ -1152,7 +1171,21 @@ back past position LIMIT; return LIMIT if nothing is found until LIMIT. */) static Lisp_Object add_text_properties_1 (Lisp_Object start, Lisp_Object end, Lisp_Object properties, Lisp_Object object, - enum property_set_type set_type) { + enum property_set_type set_type, + bool destructive) { + /* Ensure we run the modification hooks for the right buffer, + without switching buffers twice (bug 36190). FIXME: Switching + buffers is slow and often unnecessary. */ + if (BUFFERP (object) && XBUFFER (object) != current_buffer) + { + specpdl_ref count = SPECPDL_INDEX (); + record_unwind_current_buffer (); + set_buffer_internal (XBUFFER (object)); + return unbind_to (count, add_text_properties_1 (start, end, properties, + object, set_type, + destructive)); + } + INTERVAL i, unchanged; ptrdiff_t s, len; bool modified = false; @@ -1170,8 +1203,8 @@ add_text_properties_1 (Lisp_Object start, Lisp_Object end, if (!i) return Qnil; - s = XINT (start); - len = XINT (end) - s; + s = XFIXNUM (start); + len = XFIXNUM (end) - s; /* If this interval already has the properties, we can skip it. */ if (interval_has_all_properties (properties, i)) @@ -1227,8 +1260,8 @@ add_text_properties_1 (Lisp_Object start, Lisp_Object end, if (interval_has_all_properties (properties, i)) { if (BUFFERP (object)) - signal_after_change (XINT (start), XINT (end) - XINT (start), - XINT (end) - XINT (start)); + signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start), + XFIXNUM (end) - XFIXNUM (start)); eassert (modified); return Qt; @@ -1236,10 +1269,10 @@ add_text_properties_1 (Lisp_Object start, Lisp_Object end, if (LENGTH (i) == len) { - add_properties (properties, i, object, set_type); + add_properties (properties, i, object, set_type, destructive); if (BUFFERP (object)) - signal_after_change (XINT (start), XINT (end) - XINT (start), - XINT (end) - XINT (start)); + signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start), + XFIXNUM (end) - XFIXNUM (start)); return Qt; } @@ -1247,15 +1280,15 @@ add_text_properties_1 (Lisp_Object start, Lisp_Object end, unchanged = i; i = split_interval_left (unchanged, len); copy_properties (unchanged, i); - add_properties (properties, i, object, set_type); + add_properties (properties, i, object, set_type, destructive); if (BUFFERP (object)) - signal_after_change (XINT (start), XINT (end) - XINT (start), - XINT (end) - XINT (start)); + signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start), + XFIXNUM (end) - XFIXNUM (start)); return Qt; } len -= LENGTH (i); - modified |= add_properties (properties, i, object, set_type); + modified |= add_properties (properties, i, object, set_type, destructive); i = next_interval (i); } } @@ -1275,7 +1308,7 @@ Return t if any property value actually changed, nil otherwise. */) Lisp_Object object) { return add_text_properties_1 (start, end, properties, object, - TEXT_PROPERTY_REPLACE); + TEXT_PROPERTY_REPLACE, true); } /* Callers note, this can GC when OBJECT is a buffer (or nil). */ @@ -1337,7 +1370,8 @@ into it. */) add_text_properties_1 (start, end, properties, object, (NILP (append) ? TEXT_PROPERTY_PREPEND - : TEXT_PROPERTY_APPEND)); + : TEXT_PROPERTY_APPEND), + false); return Qnil; } @@ -1354,11 +1388,21 @@ Lisp_Object set_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object properties, Lisp_Object object, Lisp_Object coherent_change_p) { - register INTERVAL i; - Lisp_Object ostart, oend; + /* Ensure we run the modification hooks for the right buffer, + without switching buffers twice (bug 36190). FIXME: Switching + buffers is slow and often unnecessary. */ + if (BUFFERP (object) && XBUFFER (object) != current_buffer) + { + specpdl_ref count = SPECPDL_INDEX (); + record_unwind_current_buffer (); + set_buffer_internal (XBUFFER (object)); + return unbind_to (count, + set_text_properties (start, end, properties, + object, coherent_change_p)); + } - ostart = start; - oend = end; + INTERVAL i; + bool first_time = true; properties = validate_plist (properties); @@ -1368,8 +1412,8 @@ set_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object properties, /* If we want no properties for a whole string, get rid of its intervals. */ if (NILP (properties) && STRINGP (object) - && XFASTINT (start) == 0 - && XFASTINT (end) == SCHARS (object)) + && BASE_EQ (start, make_fixnum (0)) + && BASE_EQ (end, make_fixnum (SCHARS (object)))) { if (!string_intervals (object)) return Qnil; @@ -1378,6 +1422,7 @@ set_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object properties, return Qt; } + retry: i = validate_interval_range (object, &start, &end, soft); if (!i) @@ -1386,59 +1431,73 @@ set_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object properties, if (NILP (properties)) return Qnil; - /* Restore the original START and END values - because validate_interval_range increments them for strings. */ - start = ostart; - end = oend; - i = validate_interval_range (object, &start, &end, hard); /* This can return if start == end. */ if (!i) return Qnil; } - if (BUFFERP (object) && !NILP (coherent_change_p)) - modify_text_properties (object, start, end); + if (BUFFERP (object) && !NILP (coherent_change_p) && first_time) + { + ptrdiff_t prev_length = LENGTH (i); + ptrdiff_t prev_pos = i->position; + + modify_text_properties (object, start, end); + /* If someone called us recursively as a side effect of + modify_text_properties, and changed the intervals behind our + back, we cannot continue with I, because its data changed. + So we restart the interval analysis anew. */ + if (LENGTH (i) != prev_length || i->position != prev_pos) + { + first_time = false; + goto retry; + } + } set_text_properties_1 (start, end, properties, object, i); if (BUFFERP (object) && !NILP (coherent_change_p)) - signal_after_change (XINT (start), XINT (end) - XINT (start), - XINT (end) - XINT (start)); + signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start), + XFIXNUM (end) - XFIXNUM (start)); return Qt; } /* Replace properties of text from START to END with new list of properties PROPERTIES. OBJECT is the buffer or string containing the text. This does not obey any hooks. - You should provide the interval that START is located in as I. - START and END can be in any order. */ + I is the interval that START is located in. */ void -set_text_properties_1 (Lisp_Object start, Lisp_Object end, Lisp_Object properties, Lisp_Object object, INTERVAL i) +set_text_properties_1 (Lisp_Object start, Lisp_Object end, + Lisp_Object properties, Lisp_Object object, INTERVAL i) { - register INTERVAL prev_changed = NULL; - register ptrdiff_t s, len; - INTERVAL unchanged; - - if (XINT (start) < XINT (end)) - { - s = XINT (start); - len = XINT (end) - s; - } - else if (XINT (end) < XINT (start)) + /* Ensure we run the modification hooks for the right buffer, + without switching buffers twice (bug 36190). FIXME: Switching + buffers is slow and often unnecessary. */ + if (BUFFERP (object) && XBUFFER (object) != current_buffer) { - s = XINT (end); - len = XINT (start) - s; + specpdl_ref count = SPECPDL_INDEX (); + record_unwind_current_buffer (); + set_buffer_internal (XBUFFER (object)); + + set_text_properties_1 (start, end, properties, object, i); + unbind_to (count, Qnil); + return; } - else + + INTERVAL prev_changed = NULL; + ptrdiff_t s = XFIXNUM (start); + ptrdiff_t len = XFIXNUM (end) - s; + + if (len == 0) return; + eassert (0 < len); eassert (i); if (i->position != s) { - unchanged = i; + INTERVAL unchanged = i; i = split_interval_right (unchanged, s - unchanged->position); if (LENGTH (i) > len) @@ -1508,6 +1567,19 @@ Return t if any property was actually removed, nil otherwise. Use `set-text-properties' if you want to remove all text properties. */) (Lisp_Object start, Lisp_Object end, Lisp_Object properties, Lisp_Object object) { + /* Ensure we run the modification hooks for the right buffer, + without switching buffers twice (bug 36190). FIXME: Switching + buffers is slow and often unnecessary. */ + if (BUFFERP (object) && XBUFFER (object) != current_buffer) + { + specpdl_ref count = SPECPDL_INDEX (); + record_unwind_current_buffer (); + set_buffer_internal (XBUFFER (object)); + return unbind_to (count, + Fremove_text_properties (start, end, properties, + object)); + } + INTERVAL i, unchanged; ptrdiff_t s, len; bool modified = false; @@ -1521,8 +1593,8 @@ Use `set-text-properties' if you want to remove all text properties. */) if (!i) return Qnil; - s = XINT (start); - len = XINT (end) - s; + s = XFIXNUM (start); + len = XFIXNUM (end) - s; /* If there are no properties on this entire interval, return. */ if (! interval_has_some_properties (properties, i)) @@ -1579,8 +1651,8 @@ Use `set-text-properties' if you want to remove all text properties. */) { eassert (modified); if (BUFFERP (object)) - signal_after_change (XINT (start), XINT (end) - XINT (start), - XINT (end) - XINT (start)); + signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start), + XFIXNUM (end) - XFIXNUM (start)); return Qt; } @@ -1588,8 +1660,8 @@ Use `set-text-properties' if you want to remove all text properties. */) { remove_properties (properties, Qnil, i, object); if (BUFFERP (object)) - signal_after_change (XINT (start), XINT (end) - XINT (start), - XINT (end) - XINT (start)); + signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start), + XFIXNUM (end) - XFIXNUM (start)); return Qt; } @@ -1599,8 +1671,8 @@ Use `set-text-properties' if you want to remove all text properties. */) copy_properties (unchanged, i); remove_properties (properties, Qnil, i, object); if (BUFFERP (object)) - signal_after_change (XINT (start), XINT (end) - XINT (start), - XINT (end) - XINT (start)); + signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start), + XFIXNUM (end) - XFIXNUM (start)); return Qt; } @@ -1620,6 +1692,20 @@ markers). If OBJECT is a string, START and END are 0-based indices into it. Return t if any property was actually removed, nil otherwise. */) (Lisp_Object start, Lisp_Object end, Lisp_Object list_of_properties, Lisp_Object object) { + /* Ensure we run the modification hooks for the right buffer, + without switching buffers twice (bug 36190). FIXME: Switching + buffers is slow and often unnecessary. */ + if (BUFFERP (object) && XBUFFER (object) != current_buffer) + { + specpdl_ref count = SPECPDL_INDEX (); + record_unwind_current_buffer (); + set_buffer_internal (XBUFFER (object)); + return unbind_to (count, + Fremove_list_of_text_properties (start, end, + list_of_properties, + object)); + } + INTERVAL i, unchanged; ptrdiff_t s, len; bool modified = false; @@ -1633,8 +1719,8 @@ Return t if any property was actually removed, nil otherwise. */) if (!i) return Qnil; - s = XINT (start); - len = XINT (end) - s; + s = XFIXNUM (start); + len = XFIXNUM (end) - s; /* If there are no properties on the interval, return. */ if (! interval_has_some_properties_list (properties, i)) @@ -1677,9 +1763,9 @@ Return t if any property was actually removed, nil otherwise. */) if (modified) { if (BUFFERP (object)) - signal_after_change (XINT (start), - XINT (end) - XINT (start), - XINT (end) - XINT (start)); + signal_after_change (XFIXNUM (start), + XFIXNUM (end) - XFIXNUM (start), + XFIXNUM (end) - XFIXNUM (start)); return Qt; } else @@ -1691,8 +1777,8 @@ Return t if any property was actually removed, nil otherwise. */) modify_text_properties (object, start, end); remove_properties (Qnil, properties, i, object); if (BUFFERP (object)) - signal_after_change (XINT (start), XINT (end) - XINT (start), - XINT (end) - XINT (start)); + signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start), + XFIXNUM (end) - XFIXNUM (start)); return Qt; } else @@ -1704,8 +1790,8 @@ Return t if any property was actually removed, nil otherwise. */) modify_text_properties (object, start, end); remove_properties (Qnil, properties, i, object); if (BUFFERP (object)) - signal_after_change (XINT (start), XINT (end) - XINT (start), - XINT (end) - XINT (start)); + signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start), + XFIXNUM (end) - XFIXNUM (start)); return Qt; } } @@ -1723,9 +1809,9 @@ Return t if any property was actually removed, nil otherwise. */) if (modified) { if (BUFFERP (object)) - signal_after_change (XINT (start), - XINT (end) - XINT (start), - XINT (end) - XINT (start)); + signal_after_change (XFIXNUM (start), + XFIXNUM (end) - XFIXNUM (start), + XFIXNUM (end) - XFIXNUM (start)); return Qt; } else @@ -1752,7 +1838,7 @@ markers). If OBJECT is a string, START and END are 0-based indices into it. */ i = validate_interval_range (object, &start, &end, soft); if (!i) return (!NILP (value) || EQ (start, end) ? Qnil : start); - e = XINT (end); + e = XFIXNUM (end); while (i) { @@ -1761,9 +1847,9 @@ markers). If OBJECT is a string, START and END are 0-based indices into it. */ if (EQ (textget (i->plist, property), value)) { pos = i->position; - if (pos < XINT (start)) - pos = XINT (start); - return make_number (pos); + if (pos < XFIXNUM (start)) + pos = XFIXNUM (start); + return make_fixnum (pos); } i = next_interval (i); } @@ -1788,8 +1874,8 @@ markers). If OBJECT is a string, START and END are 0-based indices into it. */ i = validate_interval_range (object, &start, &end, soft); if (!i) return (NILP (value) || EQ (start, end)) ? Qnil : start; - s = XINT (start); - e = XINT (end); + s = XFIXNUM (start); + e = XFIXNUM (end); while (i) { @@ -1799,7 +1885,7 @@ markers). If OBJECT is a string, START and END are 0-based indices into it. */ { if (i->position > s) s = i->position; - return make_number (s); + return make_fixnum (s); } i = next_interval (i); } @@ -1817,7 +1903,7 @@ int text_property_stickiness (Lisp_Object prop, Lisp_Object pos, Lisp_Object buffer) { bool ignore_previous_character; - Lisp_Object prev_pos = make_number (XINT (pos) - 1); + Lisp_Object prev_pos = make_fixnum (XFIXNUM (pos) - 1); Lisp_Object front_sticky; bool is_rear_sticky = true, is_front_sticky = false; /* defaults */ Lisp_Object defalt = Fassq (prop, Vtext_property_default_nonsticky); @@ -1825,7 +1911,7 @@ text_property_stickiness (Lisp_Object prop, Lisp_Object pos, Lisp_Object buffer) if (NILP (buffer)) XSETBUFFER (buffer, current_buffer); - ignore_previous_character = XINT (pos) <= BUF_BEGV (XBUFFER (buffer)); + ignore_previous_character = XFIXNUM (pos) <= BUF_BEGV (XBUFFER (buffer)); if (ignore_previous_character || (CONSP (defalt) && !NILP (XCDR (defalt)))) is_rear_sticky = false; @@ -1886,45 +1972,30 @@ Lisp_Object copy_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object src, Lisp_Object pos, Lisp_Object dest, Lisp_Object prop) { - INTERVAL i; - Lisp_Object res; - Lisp_Object stuff; - Lisp_Object plist; - ptrdiff_t s, e, e2, p, len; - bool modified = false; - - i = validate_interval_range (src, &start, &end, soft); + INTERVAL i = validate_interval_range (src, &start, &end, soft); if (!i) return Qnil; - CHECK_NUMBER_COERCE_MARKER (pos); - { - Lisp_Object dest_start, dest_end; + CHECK_FIXNUM_COERCE_MARKER (pos); - e = XINT (pos) + (XINT (end) - XINT (start)); - if (MOST_POSITIVE_FIXNUM < e) - args_out_of_range (pos, end); - dest_start = pos; - XSETFASTINT (dest_end, e); - /* Apply this to a copy of pos; it will try to increment its arguments, - which we don't want. */ - validate_interval_range (dest, &dest_start, &dest_end, soft); - } + EMACS_INT dest_e = XFIXNUM (pos) + (XFIXNUM (end) - XFIXNUM (start)); + if (MOST_POSITIVE_FIXNUM < dest_e) + args_out_of_range (pos, end); + Lisp_Object dest_end = make_fixnum (dest_e); + validate_interval_range (dest, &pos, &dest_end, soft); - s = XINT (start); - e = XINT (end); - p = XINT (pos); + ptrdiff_t s = XFIXNUM (start), e = XFIXNUM (end), p = XFIXNUM (pos); - stuff = Qnil; + Lisp_Object stuff = Qnil; while (s < e) { - e2 = i->position + LENGTH (i); + ptrdiff_t e2 = i->position + LENGTH (i); if (e2 > e) e2 = e; - len = e2 - s; + ptrdiff_t len = e2 - s; - plist = i->plist; + Lisp_Object plist = i->plist; if (! NILP (prop)) while (! NILP (plist)) { @@ -1938,7 +2009,7 @@ copy_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object src, if (! NILP (plist)) /* Must defer modifications to the interval tree in case src and dest refer to the same string or buffer. */ - stuff = Fcons (list3 (make_number (p), make_number (p + len), plist), + stuff = Fcons (list3 (make_fixnum (p), make_fixnum (p + len), plist), stuff); i = next_interval (i); @@ -1949,9 +2020,11 @@ copy_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object src, s = i->position; } + bool modified = false; + while (! NILP (stuff)) { - res = Fcar (stuff); + Lisp_Object res = Fcar (stuff); res = Fadd_text_properties (Fcar (res), Fcar (Fcdr (res)), Fcar (Fcdr (Fcdr (res))), dest); if (! NILP (res)) @@ -1981,8 +2054,8 @@ text_property_list (Lisp_Object object, Lisp_Object start, Lisp_Object end, Lisp i = validate_interval_range (object, &start, &end, soft); if (i) { - ptrdiff_t s = XINT (start); - ptrdiff_t e = XINT (end); + ptrdiff_t s = XFIXNUM (start); + ptrdiff_t e = XFIXNUM (end); while (s < e) { @@ -2005,7 +2078,7 @@ text_property_list (Lisp_Object object, Lisp_Object start, Lisp_Object end, Lisp } if (!NILP (plist)) - result = Fcons (list3 (make_number (s), make_number (s + len), + result = Fcons (list3 (make_fixnum (s), make_fixnum (s + len), plist), result); @@ -2033,8 +2106,8 @@ add_text_properties_from_list (Lisp_Object object, Lisp_Object list, Lisp_Object Lisp_Object item, start, end, plist; item = XCAR (list); - start = make_number (XINT (XCAR (item)) + XINT (delta)); - end = make_number (XINT (XCAR (XCDR (item))) + XINT (delta)); + start = make_fixnum (XFIXNUM (XCAR (item)) + XFIXNUM (delta)); + end = make_fixnum (XFIXNUM (XCAR (XCDR (item))) + XFIXNUM (delta)); plist = XCAR (XCDR (XCDR (item))); Fadd_text_properties (start, end, plist, object); @@ -2052,7 +2125,7 @@ Lisp_Object extend_property_ranges (Lisp_Object list, Lisp_Object old_end, Lisp_Object new_end) { Lisp_Object prev = Qnil, head = list; - ptrdiff_t max = XINT (new_end); + ptrdiff_t max = XFIXNUM (new_end); for (; CONSP (list); prev = list, list = XCDR (list)) { @@ -2061,9 +2134,9 @@ extend_property_ranges (Lisp_Object list, Lisp_Object old_end, Lisp_Object new_e item = XCAR (list); beg = XCAR (item); - end = XINT (XCAR (XCDR (item))); + end = XFIXNUM (XCAR (XCDR (item))); - if (XINT (beg) >= max) + if (XFIXNUM (beg) >= max) { /* The start-point is past the end of the new string. Discard this property. */ @@ -2072,7 +2145,7 @@ extend_property_ranges (Lisp_Object list, Lisp_Object old_end, Lisp_Object new_e else XSETCDR (prev, XCDR (list)); } - else if ((end == XINT (old_end) && end != max) + else if ((end == XFIXNUM (old_end) && end != max) || end > max) { /* Either the end-point is past the end of the new string, @@ -2181,7 +2254,7 @@ verify_interval_modification (struct buffer *buf, tem = textget (i->plist, Qfront_sticky); if (TMEM (Qread_only, tem) - || (NILP (Fplist_get (i->plist, Qread_only)) + || (NILP (plist_get (i->plist, Qread_only)) && TMEM (Qcategory, tem))) text_read_only (after); } @@ -2201,7 +2274,7 @@ verify_interval_modification (struct buffer *buf, tem = textget (prev->plist, Qrear_nonsticky); if (! TMEM (Qread_only, tem) - && (! NILP (Fplist_get (prev->plist,Qread_only)) + && (! NILP (plist_get (prev->plist,Qread_only)) || ! TMEM (Qcategory, tem))) text_read_only (before); } @@ -2220,13 +2293,13 @@ verify_interval_modification (struct buffer *buf, tem = textget (i->plist, Qfront_sticky); if (TMEM (Qread_only, tem) - || (NILP (Fplist_get (i->plist, Qread_only)) + || (NILP (plist_get (i->plist, Qread_only)) && TMEM (Qcategory, tem))) text_read_only (after); tem = textget (prev->plist, Qrear_nonsticky); if (! TMEM (Qread_only, tem) - && (! NILP (Fplist_get (prev->plist, Qread_only)) + && (! NILP (plist_get (prev->plist, Qread_only)) || ! TMEM (Qcategory, tem))) text_read_only (after); } @@ -2275,10 +2348,10 @@ verify_interval_modification (struct buffer *buf, if (!inhibit_modification_hooks) { hooks = Fnreverse (hooks); - while (! EQ (hooks, Qnil)) + while (! NILP (hooks)) { - call_mod_hooks (Fcar (hooks), make_number (start), - make_number (end)); + call_mod_hooks (Fcar (hooks), make_fixnum (start), + make_fixnum (end)); hooks = Fcdr (hooks); } } @@ -2346,11 +2419,10 @@ inherits it if NONSTICKINESS is nil. The `front-sticky' and Vtext_property_default_nonsticky = list2 (Fcons (Qsyntax_table, Qt), Fcons (Qdisplay, Qt)); - staticpro (&interval_insert_behind_hooks); - staticpro (&interval_insert_in_front_hooks); interval_insert_behind_hooks = Qnil; interval_insert_in_front_hooks = Qnil; - + staticpro (&interval_insert_behind_hooks); + staticpro (&interval_insert_in_front_hooks); /* Common attributes one might give text. */ |