/src/textprop.c
C | 2251 lines | 1501 code | 329 blank | 421 comment | 357 complexity | a794ac02739f81cde9f6009352973b8a MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0, AGPL-3.0
Large files files are truncated, but you can click here to view the full file
- /* Interface code for dealing with text properties.
- Copyright (C) 1993, 1994, 1995, 1997, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
- This file is part of GNU Emacs.
- GNU Emacs is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- GNU Emacs is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
- #include <config.h>
- #include "lisp.h"
- #include "intervals.h"
- #include "buffer.h"
- #include "window.h"
- #ifndef NULL
- #define NULL (void *)0
- #endif
- /* Test for membership, allowing for t (actually any non-cons) to mean the
- universal set. */
- #define TMEM(sym, set) (CONSP (set) ? ! NILP (Fmemq (sym, set)) : ! NILP (set))
- /* NOTES: previous- and next- property change will have to skip
- zero-length intervals if they are implemented. This could be done
- inside next_interval and previous_interval.
- set_properties needs to deal with the interval property cache.
- It is assumed that for any interval plist, a property appears
- only once on the list. Although some code i.e., remove_properties,
- handles the more general case, the uniqueness of properties is
- necessary for the system to remain consistent. This requirement
- is enforced by the subrs installing properties onto the intervals. */
- /* Types of hooks. */
- Lisp_Object Qmouse_left;
- Lisp_Object Qmouse_entered;
- Lisp_Object Qpoint_left;
- Lisp_Object Qpoint_entered;
- Lisp_Object Qcategory;
- Lisp_Object Qlocal_map;
- /* Visual properties text (including strings) may have. */
- Lisp_Object Qforeground, Qbackground, Qfont, Qunderline, Qstipple;
- Lisp_Object Qinvisible, Qread_only, Qintangible, Qmouse_face;
- Lisp_Object Qminibuffer_prompt;
- /* Sticky properties */
- Lisp_Object Qfront_sticky, Qrear_nonsticky;
- /* If o1 is a cons whose cdr is a cons, return non-zero and set o2 to
- the o1's cdr. Otherwise, return zero. This is handy for
- traversing plists. */
- #define PLIST_ELT_P(o1, o2) (CONSP (o1) && ((o2)=XCDR (o1), CONSP (o2)))
- Lisp_Object Vinhibit_point_motion_hooks;
- Lisp_Object Vdefault_text_properties;
- Lisp_Object Vchar_property_alias_alist;
- Lisp_Object Vtext_property_default_nonsticky;
- /* verify_interval_modification saves insertion hooks here
- to be run later by report_interval_modification. */
- Lisp_Object interval_insert_behind_hooks;
- Lisp_Object interval_insert_in_front_hooks;
- static void text_read_only P_ ((Lisp_Object)) NO_RETURN;
- /* Signal a `text-read-only' error. This function makes it easier
- to capture that error in GDB by putting a breakpoint on it. */
- static void
- text_read_only (propval)
- Lisp_Object propval;
- {
- if (STRINGP (propval))
- xsignal1 (Qtext_read_only, propval);
- xsignal0 (Qtext_read_only);
- }
- /* Extract the interval at the position pointed to by BEGIN from
- OBJECT, a string or buffer. Additionally, check that the positions
- pointed to by BEGIN and END are within the bounds of OBJECT, and
- reverse them if *BEGIN is greater than *END. The objects pointed
- 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
- the validated points to determine a length, and operates on that.
- Exceptions are Ftext_properties_at, Fnext_property_change, and
- Fprevious_property_change which call this function with BEGIN == END.
- Handle this case specially.
- If FORCE is soft (0), it's OK to return NULL_INTERVAL. Otherwise,
- create an interval tree for OBJECT if one doesn't exist, provided
- the object actually contains text. In the current design, if there
- is no text, there can be no text properties. */
- #define soft 0
- #define hard 1
- INTERVAL
- validate_interval_range (object, begin, end, force)
- Lisp_Object object, *begin, *end;
- int force;
- {
- register INTERVAL i;
- int searchpos;
- CHECK_STRING_OR_BUFFER (object);
- CHECK_NUMBER_COERCE_MARKER (*begin);
- CHECK_NUMBER_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_INTERVAL;
- if (XINT (*begin) > XINT (*end))
- {
- Lisp_Object n;
- n = *begin;
- *begin = *end;
- *end = n;
- }
- if (BUFFERP (object))
- {
- 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);
- i = BUF_INTERVALS (b);
- /* If there's no text, there are no properties. */
- if (BUF_BEGV (b) == BUF_ZV (b))
- return NULL_INTERVAL;
- searchpos = XINT (*begin);
- }
- else
- {
- int 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));
- i = STRING_INTERVALS (object);
- if (len == 0)
- return NULL_INTERVAL;
- searchpos = XINT (*begin);
- }
- if (NULL_INTERVAL_P (i))
- return (force ? create_root_interval (object) : i);
- return find_interval (i, searchpos);
- }
- /* Validate LIST as a property list. If LIST is not a list, then
- make one consisting of (LIST nil). Otherwise, verify that LIST
- is even numbered and thus suitable as a plist. */
- static Lisp_Object
- validate_plist (list)
- Lisp_Object list;
- {
- if (NILP (list))
- return Qnil;
- if (CONSP (list))
- {
- register int i;
- register Lisp_Object tail;
- for (i = 0, tail = list; CONSP (tail); i++)
- {
- tail = XCDR (tail);
- QUIT;
- }
- if (i & 1)
- error ("Odd length text property list");
- return list;
- }
- return Fcons (list, Fcons (Qnil, Qnil));
- }
- /* Return nonzero if interval I has all the properties,
- with the same values, of list PLIST. */
- static int
- interval_has_all_properties (plist, i)
- Lisp_Object plist;
- INTERVAL i;
- {
- register Lisp_Object tail1, tail2, sym1;
- register int found;
- /* Go through each element of PLIST. */
- for (tail1 = plist; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
- {
- sym1 = XCAR (tail1);
- found = 0;
- /* Go through I's plist, looking for sym1 */
- for (tail2 = i->plist; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
- if (EQ (sym1, XCAR (tail2)))
- {
- /* Found the same property on both lists. If the
- values are unequal, return zero. */
- if (! EQ (Fcar (XCDR (tail1)), Fcar (XCDR (tail2))))
- return 0;
- /* Property has same value on both lists; go to next one. */
- found = 1;
- break;
- }
- if (! found)
- return 0;
- }
- return 1;
- }
- /* Return nonzero if the plist of interval I has any of the
- properties of PLIST, regardless of their values. */
- static INLINE int
- interval_has_some_properties (plist, i)
- Lisp_Object plist;
- INTERVAL i;
- {
- register Lisp_Object tail1, tail2, sym;
- /* Go through each element of PLIST. */
- for (tail1 = plist; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
- {
- sym = XCAR (tail1);
- /* Go through i's plist, looking for tail1 */
- for (tail2 = i->plist; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
- if (EQ (sym, XCAR (tail2)))
- return 1;
- }
- return 0;
- }
- /* Return nonzero if the plist of interval I has any of the
- property names in LIST, regardless of their values. */
- static INLINE int
- interval_has_some_properties_list (list, i)
- Lisp_Object list;
- INTERVAL i;
- {
- register Lisp_Object tail1, tail2, sym;
- /* Go through each element of LIST. */
- for (tail1 = list; CONSP (tail1); tail1 = XCDR (tail1))
- {
- sym = Fcar (tail1);
- /* Go through i's plist, looking for tail1 */
- for (tail2 = i->plist; CONSP (tail2); tail2 = XCDR (XCDR (tail2)))
- if (EQ (sym, XCAR (tail2)))
- return 1;
- }
- return 0;
- }
- /* Changing the plists of individual intervals. */
- /* Return the value of PROP in property-list PLIST, or Qunbound if it
- has none. */
- static Lisp_Object
- property_value (plist, prop)
- Lisp_Object plist, prop;
- {
- Lisp_Object value;
- while (PLIST_ELT_P (plist, value))
- if (EQ (XCAR (plist), prop))
- return XCAR (value);
- else
- plist = XCDR (value);
- return Qunbound;
- }
- /* Set the properties of INTERVAL to PROPERTIES,
- and record undo info for the previous values.
- OBJECT is the string or buffer that INTERVAL belongs to. */
- static void
- set_properties (properties, interval, object)
- Lisp_Object properties, object;
- INTERVAL interval;
- {
- Lisp_Object sym, value;
- if (BUFFERP (object))
- {
- /* For each property in the old plist which is missing from PROPERTIES,
- or has a different value in PROPERTIES, make an undo record. */
- for (sym = interval->plist;
- PLIST_ELT_P (sym, value);
- sym = XCDR (value))
- if (! EQ (property_value (properties, XCAR (sym)),
- XCAR (value)))
- {
- record_property_change (interval->position, LENGTH (interval),
- XCAR (sym), XCAR (value),
- object);
- }
- /* For each new property that has no value at all in the old plist,
- make an undo record binding it to nil, so it will be removed. */
- for (sym = properties;
- PLIST_ELT_P (sym, value);
- sym = XCDR (value))
- if (EQ (property_value (interval->plist, XCAR (sym)), Qunbound))
- {
- record_property_change (interval->position, LENGTH (interval),
- XCAR (sym), Qnil,
- object);
- }
- }
- /* Store new properties. */
- interval->plist = Fcopy_sequence (properties);
- }
- /* Add the properties of PLIST to the interval I, or set
- the value of I's property to the value of the property on PLIST
- if they are different.
- OBJECT should be the string or buffer the interval is in.
- Return nonzero if this changes I (i.e., if any members of PLIST
- are actually added to I's plist) */
- static int
- add_properties (plist, i, object)
- Lisp_Object plist;
- INTERVAL i;
- Lisp_Object object;
- {
- Lisp_Object tail1, tail2, sym1, val1;
- register int changed = 0;
- register int found;
- struct gcpro gcpro1, gcpro2, gcpro3;
- tail1 = plist;
- sym1 = Qnil;
- val1 = Qnil;
- /* No need to protect OBJECT, because we can GC only in the case
- where it is a buffer, and live buffers are always protected.
- I and its plist are also protected, via OBJECT. */
- GCPRO3 (tail1, sym1, val1);
- /* Go through each element of PLIST. */
- for (tail1 = plist; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
- {
- sym1 = XCAR (tail1);
- val1 = Fcar (XCDR (tail1));
- found = 0;
- /* Go through I's plist, looking for sym1 */
- for (tail2 = i->plist; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
- if (EQ (sym1, XCAR (tail2)))
- {
- /* No need to gcpro, because tail2 protects this
- and it must be a cons cell (we get an error otherwise). */
- register Lisp_Object this_cdr;
- this_cdr = XCDR (tail2);
- /* Found the property. Now check its value. */
- found = 1;
- /* The properties have the same value on both lists.
- Continue to the next property. */
- if (EQ (val1, Fcar (this_cdr)))
- break;
- /* Record this change in the buffer, for undo purposes. */
- if (BUFFERP (object))
- {
- record_property_change (i->position, LENGTH (i),
- sym1, Fcar (this_cdr), object);
- }
- /* I's property has a different value -- change it */
- Fsetcar (this_cdr, val1);
- changed++;
- break;
- }
- if (! found)
- {
- /* Record this change in the buffer, for undo purposes. */
- if (BUFFERP (object))
- {
- record_property_change (i->position, LENGTH (i),
- sym1, Qnil, object);
- }
- i->plist = Fcons (sym1, Fcons (val1, i->plist));
- changed++;
- }
- }
- UNGCPRO;
- return changed;
- }
- /* For any members of PLIST, or LIST,
- which are properties of I, remove them from I's plist.
- (If PLIST is non-nil, use that, otherwise use LIST.)
- OBJECT is the string or buffer containing I. */
- static int
- remove_properties (plist, list, i, object)
- Lisp_Object plist, list;
- INTERVAL i;
- Lisp_Object object;
- {
- register Lisp_Object tail1, tail2, sym, current_plist;
- register int changed = 0;
- /* Nonzero means tail1 is a plist, otherwise it is a list. */
- int use_plist;
- current_plist = i->plist;
- if (! NILP (plist))
- tail1 = plist, use_plist = 1;
- else
- tail1 = list, use_plist = 0;
- /* Go through each element of LIST or PLIST. */
- while (CONSP (tail1))
- {
- sym = XCAR (tail1);
- /* First, remove the symbol if it's at the head of the list */
- while (CONSP (current_plist) && EQ (sym, XCAR (current_plist)))
- {
- if (BUFFERP (object))
- record_property_change (i->position, LENGTH (i),
- sym, XCAR (XCDR (current_plist)),
- object);
- current_plist = XCDR (XCDR (current_plist));
- changed++;
- }
- /* Go through I's plist, looking for SYM. */
- tail2 = current_plist;
- while (! NILP (tail2))
- {
- register Lisp_Object this;
- this = XCDR (XCDR (tail2));
- if (CONSP (this) && EQ (sym, XCAR (this)))
- {
- if (BUFFERP (object))
- record_property_change (i->position, LENGTH (i),
- sym, XCAR (XCDR (this)), object);
- Fsetcdr (XCDR (tail2), XCDR (XCDR (this)));
- changed++;
- }
- tail2 = this;
- }
- /* Advance thru TAIL1 one way or the other. */
- tail1 = XCDR (tail1);
- if (use_plist && CONSP (tail1))
- tail1 = XCDR (tail1);
- }
- if (changed)
- i->plist = current_plist;
- return changed;
- }
- #if 0
- /* Remove all properties from interval I. Return non-zero
- if this changes the interval. */
- static INLINE int
- erase_properties (i)
- INTERVAL i;
- {
- if (NILP (i->plist))
- return 0;
- i->plist = Qnil;
- return 1;
- }
- #endif
- /* Returns the interval of POSITION in OBJECT.
- POSITION is BEG-based. */
- INTERVAL
- interval_of (position, object)
- int position;
- Lisp_Object object;
- {
- register INTERVAL i;
- int beg, end;
- if (NILP (object))
- XSETBUFFER (object, current_buffer);
- else if (EQ (object, Qt))
- return NULL_INTERVAL;
- CHECK_STRING_OR_BUFFER (object);
- if (BUFFERP (object))
- {
- register struct buffer *b = XBUFFER (object);
- beg = BUF_BEGV (b);
- end = BUF_ZV (b);
- i = BUF_INTERVALS (b);
- }
- else
- {
- beg = 0;
- end = SCHARS (object);
- i = STRING_INTERVALS (object);
- }
- if (!(beg <= position && position <= end))
- args_out_of_range (make_number (position), make_number (position));
- if (beg == end || NULL_INTERVAL_P (i))
- return NULL_INTERVAL;
- return find_interval (i, position);
- }
- DEFUN ("text-properties-at", Ftext_properties_at,
- Stext_properties_at, 1, 2, 0,
- 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. */)
- (position, object)
- Lisp_Object position, object;
- {
- register INTERVAL i;
- if (NILP (object))
- XSETBUFFER (object, current_buffer);
- i = validate_interval_range (object, &position, &position, soft);
- if (NULL_INTERVAL_P (i))
- return Qnil;
- /* If POSITION is at the end of the interval,
- 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)
- return Qnil;
- return i->plist;
- }
- 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 is optional and defaults to the current buffer.
- If POSITION is at the end of OBJECT, the value is nil. */)
- (position, prop, object)
- Lisp_Object position, object;
- Lisp_Object prop;
- {
- return textget (Ftext_properties_at (position, object), prop);
- }
- /* Return the value of char's property PROP, in OBJECT at POSITION.
- OBJECT is optional and defaults to the current buffer.
- If OVERLAY is non-0, then in the case that the returned property is from
- an overlay, the overlay found is returned in *OVERLAY, otherwise nil is
- returned in *OVERLAY.
- If POSITION is at the end of OBJECT, the value is nil.
- If OBJECT is a buffer, then overlay properties are considered as well as
- text properties.
- If OBJECT is a window, then that window's buffer is used, but
- window-specific overlays are considered only if they are associated
- with OBJECT. */
- Lisp_Object
- get_char_property_and_overlay (position, prop, object, overlay)
- Lisp_Object position, object;
- register Lisp_Object prop;
- Lisp_Object *overlay;
- {
- struct window *w = 0;
- CHECK_NUMBER_COERCE_MARKER (position);
- if (NILP (object))
- XSETBUFFER (object, current_buffer);
- if (WINDOWP (object))
- {
- w = XWINDOW (object);
- object = w->buffer;
- }
- if (BUFFERP (object))
- {
- int noverlays;
- Lisp_Object *overlay_vec;
- struct buffer *obuf = current_buffer;
- if (XINT (position) < BUF_BEGV (XBUFFER (object))
- || XINT (position) > BUF_ZV (XBUFFER (object)))
- xsignal1 (Qargs_out_of_range, position);
- set_buffer_temp (XBUFFER (object));
- GET_OVERLAYS_AT (XINT (position), overlay_vec, noverlays, NULL, 0);
- noverlays = sort_overlays (overlay_vec, noverlays, w);
- set_buffer_temp (obuf);
- /* Now check the overlays in order of decreasing priority. */
- while (--noverlays >= 0)
- {
- Lisp_Object tem = Foverlay_get (overlay_vec[noverlays], prop);
- if (!NILP (tem))
- {
- if (overlay)
- /* Return the overlay we got the property from. */
- *overlay = overlay_vec[noverlays];
- return tem;
- }
- }
- }
- if (overlay)
- /* Indicate that the return value is not from an overlay. */
- *overlay = Qnil;
- /* Not a buffer, or no appropriate overlay, so fall through to the
- simpler case. */
- return Fget_text_property (position, prop, object);
- }
- DEFUN ("get-char-property", Fget_char_property, Sget_char_property, 2, 3, 0,
- doc: /* Return the value of POSITION's property PROP, in OBJECT.
- Both overlay properties and text properties are checked.
- OBJECT is optional and defaults to the current buffer.
- If POSITION is at the end of OBJECT, the value is nil.
- If OBJECT is a buffer, then overlay properties are considered as well as
- text properties.
- If OBJECT is a window, then that window's buffer is used, but window-specific
- overlays are considered only if they are associated with OBJECT. */)
- (position, prop, object)
- Lisp_Object position, object;
- register Lisp_Object prop;
- {
- return get_char_property_and_overlay (position, prop, object, 0);
- }
- DEFUN ("get-char-property-and-overlay", Fget_char_property_and_overlay,
- Sget_char_property_and_overlay, 2, 3, 0,
- doc: /* Like `get-char-property', but with extra overlay information.
- The value is a cons cell. Its car is the return value of `get-char-property'
- with the same arguments--that is, the value of POSITION's property
- PROP in OBJECT. Its cdr is the overlay in which the property was
- found, or nil, if it was found as a text property or not found at all.
- OBJECT is optional and defaults to the current buffer. OBJECT may be
- a string, a buffer or a window. For strings, the cdr of the return
- value is always nil, since strings do not have overlays. If OBJECT is
- a window, then that window's buffer is used, but window-specific
- overlays are considered only if they are associated with OBJECT. If
- POSITION is at the end of OBJECT, both car and cdr are nil. */)
- (position, prop, object)
- Lisp_Object position, object;
- register Lisp_Object prop;
- {
- Lisp_Object overlay;
- Lisp_Object val
- = get_char_property_and_overlay (position, prop, object, &overlay);
- return Fcons (val, overlay);
- }
- DEFUN ("next-char-property-change", Fnext_char_property_change,
- Snext_char_property_change, 1, 2, 0,
- doc: /* Return the position of next text property or overlay change.
- This scans characters forward in the current buffer from POSITION till
- it finds a change in some text property, or the beginning or end of an
- overlay, and returns the position of that.
- If none is found up to (point-max), the function returns (point-max).
- If the optional second argument LIMIT is non-nil, don't search
- past position LIMIT; return LIMIT if nothing is found before LIMIT.
- LIMIT is a no-op if it is greater than (point-max). */)
- (position, limit)
- Lisp_Object position, limit;
- {
- Lisp_Object temp;
- temp = Fnext_overlay_change (position);
- if (! NILP (limit))
- {
- CHECK_NUMBER_COERCE_MARKER (limit);
- if (XINT (limit) < XINT (temp))
- temp = limit;
- }
- return Fnext_property_change (position, Qnil, temp);
- }
- DEFUN ("previous-char-property-change", Fprevious_char_property_change,
- Sprevious_char_property_change, 1, 2, 0,
- doc: /* Return the position of previous text property or overlay change.
- Scans characters backward in the current buffer from POSITION till it
- finds a change in some text property, or the beginning or end of an
- overlay, and returns the position of that.
- If none is found since (point-min), the function returns (point-min).
- If the optional second argument LIMIT is non-nil, don't search
- past position LIMIT; return LIMIT if nothing is found before LIMIT.
- LIMIT is a no-op if it is less than (point-min). */)
- (position, limit)
- Lisp_Object position, limit;
- {
- Lisp_Object temp;
- temp = Fprevious_overlay_change (position);
- if (! NILP (limit))
- {
- CHECK_NUMBER_COERCE_MARKER (limit);
- if (XINT (limit) > XINT (temp))
- temp = limit;
- }
- return Fprevious_property_change (position, Qnil, temp);
- }
- DEFUN ("next-single-char-property-change", Fnext_single_char_property_change,
- Snext_single_char_property_change, 2, 4, 0,
- doc: /* Return the position of next text property or overlay change for a specific property.
- Scans characters forward from POSITION till it finds
- a change in the PROP property, then returns the position of the change.
- If the optional third 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.
- In a string, scan runs to the end of the string.
- In a buffer, it runs to (point-max), and the value cannot exceed that.
- 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.
- If the optional fourth argument LIMIT is non-nil, don't search
- past position LIMIT; return LIMIT if nothing is found before LIMIT. */)
- (position, prop, object, limit)
- Lisp_Object prop, position, object, limit;
- {
- if (STRINGP (object))
- {
- position = Fnext_single_property_change (position, prop, object, limit);
- if (NILP (position))
- {
- if (NILP (limit))
- position = make_number (SCHARS (object));
- else
- {
- CHECK_NUMBER (limit);
- position = limit;
- }
- }
- }
- else
- {
- Lisp_Object initial_value, value;
- int count = SPECPDL_INDEX ();
- if (! NILP (object))
- CHECK_BUFFER (object);
- if (BUFFERP (object) && current_buffer != XBUFFER (object))
- {
- record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
- Fset_buffer (object);
- }
- CHECK_NUMBER_COERCE_MARKER (position);
- initial_value = Fget_char_property (position, prop, object);
- if (NILP (limit))
- XSETFASTINT (limit, ZV);
- else
- CHECK_NUMBER_COERCE_MARKER (limit);
- if (XFASTINT (position) >= XFASTINT (limit))
- {
- position = limit;
- if (XFASTINT (position) > ZV)
- XSETFASTINT (position, ZV);
- }
- else
- while (1)
- {
- position = Fnext_char_property_change (position, limit);
- if (XFASTINT (position) >= XFASTINT (limit))
- {
- position = limit;
- break;
- }
- value = Fget_char_property (position, prop, object);
- if (!EQ (value, initial_value))
- break;
- }
- unbind_to (count, Qnil);
- }
- return position;
- }
- DEFUN ("previous-single-char-property-change",
- Fprevious_single_char_property_change,
- Sprevious_single_char_property_change, 2, 4, 0,
- doc: /* Return the position of previous text property or overlay change for a specific property.
- Scans characters backward from POSITION till it finds
- a change in the PROP property, then returns the position of the change.
- If the optional third 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.
- In a string, scan runs to the start of the string.
- In a buffer, it runs to (point-min), and the value cannot be less than that.
- The property values are compared with `eq'.
- If the property is constant all the way to the start of OBJECT, return the
- first valid position in OBJECT.
- If the optional fourth argument LIMIT is non-nil, don't search
- back past position LIMIT; return LIMIT if nothing is found before LIMIT. */)
- (position, prop, object, limit)
- Lisp_Object prop, position, object, limit;
- {
- if (STRINGP (object))
- {
- position = Fprevious_single_property_change (position, prop, object, limit);
- if (NILP (position))
- {
- if (NILP (limit))
- position = make_number (0);
- else
- {
- CHECK_NUMBER (limit);
- position = limit;
- }
- }
- }
- else
- {
- int count = SPECPDL_INDEX ();
- if (! NILP (object))
- CHECK_BUFFER (object);
- if (BUFFERP (object) && current_buffer != XBUFFER (object))
- {
- record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
- Fset_buffer (object);
- }
- CHECK_NUMBER_COERCE_MARKER (position);
- if (NILP (limit))
- XSETFASTINT (limit, BEGV);
- else
- CHECK_NUMBER_COERCE_MARKER (limit);
- if (XFASTINT (position) <= XFASTINT (limit))
- {
- position = limit;
- if (XFASTINT (position) < BEGV)
- XSETFASTINT (position, BEGV);
- }
- else
- {
- Lisp_Object initial_value
- = Fget_char_property (make_number (XFASTINT (position) - 1),
- prop, object);
- while (1)
- {
- position = Fprevious_char_property_change (position, limit);
- if (XFASTINT (position) <= XFASTINT (limit))
- {
- position = limit;
- break;
- }
- else
- {
- Lisp_Object value
- = Fget_char_property (make_number (XFASTINT (position) - 1),
- prop, object);
- if (!EQ (value, initial_value))
- break;
- }
- }
- }
- unbind_to (count, Qnil);
- }
- return position;
- }
- DEFUN ("next-property-change", Fnext_property_change,
- Snext_property_change, 1, 3, 0,
- doc: /* Return the position of next property change.
- Scans characters forward from POSITION in OBJECT till it finds
- a change in some text property, then returns the position of the change.
- 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.
- Return nil if the property is constant all the way to the end of OBJECT.
- If the value is non-nil, it is a position greater than POSITION, never equal.
- If the optional third argument LIMIT is non-nil, don't search
- past position LIMIT; return LIMIT if nothing is found before LIMIT. */)
- (position, object, limit)
- Lisp_Object position, object, limit;
- {
- register INTERVAL i, next;
- if (NILP (object))
- XSETBUFFER (object, current_buffer);
- if (!NILP (limit) && !EQ (limit, Qt))
- CHECK_NUMBER_COERCE_MARKER (limit);
- i = validate_interval_range (object, &position, &position, soft);
- /* If LIMIT is t, return start of next interval--don't
- bother checking further intervals. */
- if (EQ (limit, Qt))
- {
- if (NULL_INTERVAL_P (i))
- next = i;
- else
- next = next_interval (i);
- if (NULL_INTERVAL_P (next))
- XSETFASTINT (position, (STRINGP (object)
- ? SCHARS (object)
- : BUF_ZV (XBUFFER (object))));
- else
- XSETFASTINT (position, next->position);
- return position;
- }
- if (NULL_INTERVAL_P (i))
- return limit;
- next = next_interval (i);
- while (!NULL_INTERVAL_P (next) && intervals_equal (i, next)
- && (NILP (limit) || next->position < XFASTINT (limit)))
- next = next_interval (next);
- if (NULL_INTERVAL_P (next)
- || (next->position
- >= (INTEGERP (limit)
- ? XFASTINT (limit)
- : (STRINGP (object)
- ? SCHARS (object)
- : BUF_ZV (XBUFFER (object))))))
- return limit;
- else
- return make_number (next->position);
- }
- /* Return 1 if there's a change in some property between BEG and END. */
- int
- property_change_between_p (beg, end)
- int beg, end;
- {
- register INTERVAL i, next;
- Lisp_Object object, pos;
- XSETBUFFER (object, current_buffer);
- XSETFASTINT (pos, beg);
- i = validate_interval_range (object, &pos, &pos, soft);
- if (NULL_INTERVAL_P (i))
- return 0;
- next = next_interval (i);
- while (! NULL_INTERVAL_P (next) && intervals_equal (i, next))
- {
- next = next_interval (next);
- if (NULL_INTERVAL_P (next))
- return 0;
- if (next->position >= end)
- return 0;
- }
- if (NULL_INTERVAL_P (next))
- return 0;
- return 1;
- }
- DEFUN ("next-single-property-change", Fnext_single_property_change,
- Snext_single_property_change, 2, 4, 0,
- doc: /* Return the position of next property change for a specific property.
- Scans characters forward from POSITION till it finds
- a change in the PROP property, then returns the position of the change.
- If the optional third 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.
- The property values are compared with `eq'.
- Return nil if the property is constant all the way to the end of OBJECT.
- If the value is non-nil, it is a position greater than POSITION, never equal.
- If the optional fourth argument LIMIT is non-nil, don't search
- past position LIMIT; return LIMIT if nothing is found before LIMIT. */)
- (position, prop, object, limit)
- Lisp_Object position, prop, object, limit;
- {
- register INTERVAL i, next;
- register Lisp_Object here_val;
- if (NILP (object))
- XSETBUFFER (object, current_buffer);
- if (!NILP (limit))
- CHECK_NUMBER_COERCE_MARKER (limit);
- i = validate_interval_range (object, &position, &position, soft);
- if (NULL_INTERVAL_P (i))
- return limit;
- here_val = textget (i->plist, prop);
- next = next_interval (i);
- while (! NULL_INTERVAL_P (next)
- && EQ (here_val, textget (next->plist, prop))
- && (NILP (limit) || next->position < XFASTINT (limit)))
- next = next_interval (next);
- if (NULL_INTERVAL_P (next)
- || (next->position
- >= (INTEGERP (limit)
- ? XFASTINT (limit)
- : (STRINGP (object)
- ? SCHARS (object)
- : BUF_ZV (XBUFFER (object))))))
- return limit;
- else
- return make_number (next->position);
- }
- DEFUN ("previous-property-change", Fprevious_property_change,
- Sprevious_property_change, 1, 3, 0,
- doc: /* Return the position of previous property change.
- Scans characters backwards from POSITION in OBJECT till it finds
- a change in some text property, then returns the position of the change.
- 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.
- Return nil if the property is constant all the way to the start of OBJECT.
- If the value is non-nil, it is a position less than POSITION, never equal.
- If the optional third argument LIMIT is non-nil, don't search
- back past position LIMIT; return LIMIT if nothing is found until LIMIT. */)
- (position, object, limit)
- Lisp_Object position, object, limit;
- {
- register INTERVAL i, previous;
- if (NILP (object))
- XSETBUFFER (object, current_buffer);
- if (!NILP (limit))
- CHECK_NUMBER_COERCE_MARKER (limit);
- i = validate_interval_range (object, &position, &position, soft);
- if (NULL_INTERVAL_P (i))
- return limit;
- /* Start with the interval containing the char before point. */
- if (i->position == XFASTINT (position))
- i = previous_interval (i);
- previous = previous_interval (i);
- while (!NULL_INTERVAL_P (previous) && intervals_equal (previous, i)
- && (NILP (limit)
- || (previous->position + LENGTH (previous) > XFASTINT (limit))))
- previous = previous_interval (previous);
- if (NULL_INTERVAL_P (previous)
- || (previous->position + LENGTH (previous)
- <= (INTEGERP (limit)
- ? XFASTINT (limit)
- : (STRINGP (object) ? 0 : BUF_BEGV (XBUFFER (object))))))
- return limit;
- else
- return make_number (previous->position + LENGTH (previous));
- }
- DEFUN ("previous-single-property-change", Fprevious_single_property_change,
- Sprevious_single_property_change, 2, 4, 0,
- doc: /* Return the position of previous property change for a specific property.
- Scans characters backward from POSITION till it finds
- a change in the PROP property, then returns the position of the change.
- If the optional third 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.
- The property values are compared with `eq'.
- Return nil if the property is constant all the way to the start of OBJECT.
- If the value is non-nil, it is a position less than POSITION, never equal.
- If the optional fourth argument LIMIT is non-nil, don't search
- back past position LIMIT; return LIMIT if nothing is found until LIMIT. */)
- (position, prop, object, limit)
- Lisp_Object position, prop, object, limit;
- {
- register INTERVAL i, previous;
- register Lisp_Object here_val;
- if (NILP (object))
- XSETBUFFER (object, current_buffer);
- if (!NILP (limit))
- CHECK_NUMBER_COERCE_MARKER (limit);
- i = validate_interval_range (object, &position, &position, soft);
- /* Start with the interval containing the char before point. */
- if (!NULL_INTERVAL_P (i) && i->position == XFASTINT (position))
- i = previous_interval (i);
- if (NULL_INTERVAL_P (i))
- return limit;
- here_val = textget (i->plist, prop);
- previous = previous_interval (i);
- while (!NULL_INTERVAL_P (previous)
- && EQ (here_val, textget (previous->plist, prop))
- && (NILP (limit)
- || (previous->position + LENGTH (previous) > XFASTINT (limit))))
- previous = previous_interval (previous);
- if (NULL_INTERVAL_P (previous)
- || (previous->position + LENGTH (previous)
- <= (INTEGERP (limit)
- ? XFASTINT (limit)
- : (STRINGP (object) ? 0 : BUF_BEGV (XBUFFER (object))))))
- return limit;
- else
- return make_number (previous->position + LENGTH (previous));
- }
- /* Callers note, this can GC when OBJECT is a buffer (or nil). */
- DEFUN ("add-text-properties", Fadd_text_properties,
- Sadd_text_properties, 3, 4, 0,
- doc: /* Add properties to the text from START to END.
- The third argument PROPERTIES is a property list
- specifying the property values to add. If the optional fourth argument
- OBJECT is a buffer (or nil, which means the current buffer),
- START and END are buffer positions (integers or markers).
- If OBJECT is a string, START and END are 0-based indices into it.
- Return t if any property value actually changed, nil otherwise. */)
- (start, end, properties, object)
- Lisp_Object start, end, properties, object;
- {
- register INTERVAL i, unchanged;
- register int s, len, modified = 0;
- struct gcpro gcpro1;
- properties = validate_plist (properties);
- if (NILP (properties))
- return Qnil;
- if (NILP (object))
- XSETBUFFER (object, current_buffer);
- i = validate_interval_range (object, &start, &end, hard);
- if (NULL_INTERVAL_P (i))
- return Qnil;
- s = XINT (start);
- len = XINT (end) - s;
- /* No need to protect OBJECT, because we GC only if it's a buffer,
- and live buffers are always protected. */
- GCPRO1 (properties);
- /* If we're not starting on an interval boundary, we have to
- split this interval. */
- if (i->position != s)
- {
- /* If this interval already has the properties, we can
- skip it. */
- if (interval_has_all_properties (properties, i))
- {
- int got = (LENGTH (i) - (s - i->position));
- if (got >= len)
- RETURN_UNGCPRO (Qnil);
- len -= got;
- i = next_interval (i);
- }
- else
- {
- unchanged = i;
- i = split_interval_right (unchanged, s - unchanged->position);
- copy_properties (unchanged, i);
- }
- }
- if (BUFFERP (object))
- modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
- /* We are at the beginning of interval I, with LEN chars to scan. */
- for (;;)
- {
- if (i == 0)
- abort ();
- if (LENGTH (i) >= len)
- {
- /* We can UNGCPRO safely here, because there will be just
- one more chance to gc, in the next call to add_properties,
- and after that we will not need PROPERTIES or OBJECT again. */
- UNGCPRO;
- if (interval_has_all_properties (properties, i))
- {
- if (BUFFERP (object))
- signal_after_change (XINT (start), XINT (end) - XINT (start),
- XINT (end) - XINT (start));
- return modified ? Qt : Qnil;
- }
- if (LENGTH (i) == len)
- {
- add_properties (properties, i, object);
- if (BUFFERP (object))
- signal_after_change (XINT (start), XINT (end) - XINT (start),
- XINT (end) - XINT (start));
- return Qt;
- }
- /* i doesn't have the properties, and goes past the change limit */
- unchanged = i;
- i = split_interval_left (unchanged, len);
- copy_properties (unchanged, i);
- add_properties (properties, i, object);
- if (BUFFERP (object))
- signal_after_change (XINT (start), XINT (end) - XINT (start),
- XINT (end) - XINT (start));
- return Qt;
- }
- len -= LENGTH (i);
- modified += add_properties (properties, i, object);
- i = next_interval (i);
- }
- }
- /* Callers note, this can GC when OBJECT is a buffer (or nil). */
- DEFUN ("put-text-property", Fput_text_property,
- Sput_text_property, 4, 5, 0,
- doc: /* Set one property of the text from START to END.
- The third and fourth arguments PROPERTY and VALUE
- specify the property to add.
- If the optional fifth argument OBJECT is a buffer (or nil, which means
- the current buffer), START and END are buffer positions (integers or
- markers). If OBJECT is a string, START and END are 0-based indices into it. */)
- (start, end, property, value, object)
- Lisp_Object start, end, property, value, object;
- {
- Fadd_text_properties (start, end,
- Fcons (property, Fcons (value, Qnil)),
- object);
- return Qnil;
- }
- DEFUN ("set-text-properties", Fset_text_properties,
- Sset_text_properties, 3, 4, 0,
- doc: /* Completely replace properties of text from START to END.
- The third argument PROPERTIES is the new property list.
- If the optional fourth argument OBJECT is a buffer (or nil, which means
- the current buffer), START and END are buffer positions (integers or
- markers). If OBJECT is a string, START and END are 0-based indices into it.
- If PROPERTIES is nil, the effect is to remove all properties from
- the designated part of OBJECT. */)
- (start, end, properties, object)
- Lisp_Object start, end, properties, object;
- {
- return set_text_properties (start, end, properties, object, Qt);
- }
- /* Replace properties of text from START to END with new list of
- properties PROPERTIES. OBJECT is the buffer or string containing
- the text. OBJECT nil means use the current buffer.
- SIGNAL_AFTER_CHANGE_P nil means don't signal after changes. Value
- is nil if the function _detected_ that it did not replace any
- properties, non-nil otherwise. */
- Lisp_Object
- set_text_properties (start, end, properties, object, signal_after_change_p)
- Lisp_Object start, end, properties, object, signal_after_change_p;
- {
- register INTERVAL i;
- Lisp_Object ostart, oend;
- ostart = start;
- oend = end;
- properties = validate_plist (properties);
- if (NILP (object))
- XSETBUFFER (object, current_buffer);
- /* 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))
- {
- if (! STRING_INTERVALS (object))
- return Qnil;
- STRING_SET_INTERVALS (object, NULL_INTERVAL);
- return Qt;
- }
- i = validate_interval_range (object, &start, &end, soft);
- if (NULL_INTERVAL_P (i))
- {
- /* If buffer has no properties, and we want none, return now. */
- 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 (NULL_INTERVAL_P (i))
- return Qnil;
- }
- if (BUFFERP (object))
- modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
- set_text_properties_1 (start, end, properties, object, i);
- if (BUFFERP (object) && !NILP (signal_after_change_p))
- signal_after_change (XINT (start), XINT (end) - XINT (start),
- XINT (end) - XINT (start));
- return Qt;
- }
- /* Replace properties of text from START to END with new list of
- properties PROPERTIES. BUFFER is the buffer containing
- the text. This does not obey any hooks.
- You can provide the interval that START is located in as I,
- or pass NULL for I and this function will find it.
- START and END can be in any order. */
- void
- set_text_properties_1 (start, end, properties, buffer, i)
- Lisp_Object start, end, properties, buffer;
- INTERVAL i;
- {
- register INTERVAL prev_changed = NULL_INTERVAL;
- register int s, len;
- INTERVAL unchanged;
- s = XINT (start);
- len = XINT (end) - s;
- if (len == 0)
- return;
- if (len < 0)
- {
- s = s + len;
- len = - len;
- }
- if (i == 0)
- i = find_interval (BUF_INTERVALS (XBUFFER (buffer)), s);
- if (i->position != s)
- {
- unchanged = i;
- i = split_interval_right (unchanged, s - unchanged->position);
- if (LENGTH (i) > len)
- {
- copy_properties (unchanged, i);
- i = split_interval_left (i, len);
- set_properties (properties, i, buffer);
- return;
- }
- set_properties (properties, i, buffer);
- if (LENGTH (i) == len)
- return;
- prev_changed = i;
- len -= LENGTH (i);
- i = next_interval (i);
- }
- /* We are starting at the beginning of an interval, I */
- while (len > 0)
- {
- if (i == 0)
- abort ();
- if (LENGTH (i) >= len)
- {
- if (LENGTH (i) > len)
- i = split_interval_left (i, len);
- /* We have to call set_properties even if we are going to
- merge the intervals, so as to make the undo records
- and cause redisplay to happen. */
- set_properties (properties, i, buffer);
- if (!NULL_INTERVAL_P (prev_changed))
- merge_interval_left (i);
- return;
- }
- len -= LENGTH (i);
- /* We have to call set_properties even if we are going to
- merge the intervals, so as to make the undo records
- and cause redisplay to happen. */
- set_properties (properties, i, buffer);
- if (NULL_INTERVAL_P (prev_changed))
- prev_changed = i;
- else
- prev_changed = i = merge_interval_left (i);
- i = next_interval (i);
- }
- }
- DEFUN ("remove-text-properties", Fremove_text_properties,
- Sremove_text_properties, 3, 4, 0,
- doc: /* Remove some properties from text from START to END.
- The third argument PROPERTIES is a property list
- whose property names specify the properties to remove.
- \(The values stored in PROPERTIES are ignored.)
- If the optional fourth argument OBJECT is a buffer (or nil, which means
- the current buffer), START and END are buffer positions (integers or
- 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.
- Use `set-text-properties' if you want to remove all text properties. */)
- (start, end, properties, object)
- Lisp_Object start, end, properties, object;
- {
- register INTERVAL i, unchanged;
- register int s, len, modified = 0;
- if (NILP (object))
- XSETBUFFER (object, current_buffer);
- i = validate_interval_range (object, &start, &end, soft);
- if (NULL_INTERVAL_P (i))
- return Qnil;
- s = XINT (start);
- len = XINT (end) - s;
- if (i->position != s)
- {
- /* No properties on this first interval -- return if
- it covers the entire region. */
- if (! interval_has_some_properties (properties, i))
- {
- int got = (LENGTH (i) - (s - i->position));
- if (got >= len)
- return Qnil;
- len -= got;
- i = next_interval (i);
- }
- /* Split away the beginning of this interval; what we don't
- want to modify. */
- else
- {
- unchanged = i;
- i = split_interval_right (unchanged, s - unchanged->position);
- copy_properties (unchanged, i);
- }
- }
- if (BUFFERP (object))
- modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
- /* We are at the beginning of an interval, with len to scan */
- for (;;)
- {
- if (i == 0)
- abort ();
- if (LENGTH (i) >= len)
- {
- if (! interval_has_some_properties (properties, i))
- return modified ? Qt : Qnil;
- if (LENGTH (i) == len)
- {
- remove_properties (properties, Qnil, i, object);
- if (BUFFERP (object))
- signal_after_change (XINT (start), XINT (end) - XINT (start),
- XINT (end) - XINT (start));
- return Qt;
- }
- /* i has the properties, and goes past the change limit */
- unchanged = i;
- i = split_interval_left (i, len);
- 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));
- return Qt;
- }
- len -= LENGTH (i);
- modified += remove_properties (properties, Qnil, i, object);
- i = next_interval (i);
- }
- }
- DEFUN ("remove-list-of-text-properties", Fremove_list_of_text_properties,
- Sremove_list_of_text_properties, 3, 4, 0,
- doc: /* Remove some properties from text from START to END.
- The third argument LIST-OF-PROPERTIES is a list of property names to remove.
- If the optional fourth argument OBJECT is a buffer (or nil, which means
- the current buffer), START and END are buffer positions (integers or
- 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. */)
- (start, end, list_of_properties, object)
- Lisp_Object start, end, list_of_properties, object;
- {
- register INTERVAL i, unchanged;
- register int s, len, modified = 0;
- Lisp_Object properties;
- properties = list_of_properties;
- if (NILP (object))
- XSETBUFFER (object, current_buffer);
- i = validate_interval_range (object, &start, &end, soft);
- if (NULL_INTERVAL_P (i))
- return Qnil;
- s = XINT (start);
- len = XINT (end) - s;
- if (i->position != s)
- {
- /* No properties on this first interval -- return if
- it covers the entire region. */
- if (! interval_has_some_properties_list (properties, i))
- {
- int got = (LENGTH (i) - (s - i->position));
- if (got >= len)
- return Qnil;
- len -= got;
- i = next_interval (i);
- }
- /* Split away the beginning of this interval; what we don't
- want to modify. */
- else
- {
- unchanged = i;
- i = split_interval_right (unchanged, s - unchanged->position);
- copy_properties (unchanged, i);
- }
- }
- /* We are at the beginning of an interval, with len to scan.
- The flag `modified' records if changes have been made.
- When object is a buffer, we must call modify_region before changes are
- made and signal_after_change when we are done.
- We call modify_region before calling remove_properties if modified == 0,
- and we call signal_after_change before returning if modified != 0. */
- for (;;)
- {
- if (i == 0)
- abort ();
- if (LENGTH (i) >= len)
- {
- if (! interval_has_some_properties_list (properties, i))
- if (modified)
- {
- if (BUFFERP (object))
- signal_after_change (XINT (start), XINT (end) - XINT (start),
- XINT (end) - XINT (start));
- return Qt;
- }
- else
- return Qnil;
- if (LENGTH (i) == len)
- {
- if (!modified && BUFFERP (object))
- modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
- remove_properties (Qnil, properties, i, object);
- if (BUFFERP (object))
- signal_after_change (XINT (start), XINT (end) - XINT (start),
- XINT (end) - XINT (start));
- return Qt;
- }
- /* i has the properties, and goes past the change limit */
- unchanged = i;
- i = split_interval_left (i, len);
- copy_properties (unchanged, i);
- if (!modified && BUFFERP (object))
- modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
- remove_properties (Qnil, properties, i, object);
- if (BUFFERP (object))
- signal_after_change (XINT (start), XINT (end) - XINT (start),
- XINT (end) - XINT (star…
Large files files are truncated, but you can click here to view the full file