/* Interface code for dealing with text properties.
- Copyright (C) 1993-1995, 1997, 1999-2012 Free Software Foundation, Inc.
+ Copyright (C) 1993-1995, 1997, 1999-2013 Free Software Foundation,
+ Inc.
This file is part of GNU Emacs.
static Lisp_Object Qread_only;
Lisp_Object Qminibuffer_prompt;
-/* Sticky properties */
+/* 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
xsignal0 (Qtext_read_only);
}
+/* Prepare to modify the region of BUFFER from START to END. */
+
+static void
+modify_region (Lisp_Object buffer, Lisp_Object start, Lisp_Object end)
+{
+ struct buffer *buf = XBUFFER (buffer), *old = current_buffer;
+
+ set_buffer_internal (buf);
+ modify_region_1 (XINT (start), XINT (end), true);
+ set_buffer_internal (old);
+}
+
+/* Complain if object is not string or buffer type. */
+
+static void
+CHECK_STRING_OR_BUFFER (Lisp_Object x)
+{
+ CHECK_TYPE (STRINGP (x) || BUFFERP (x), Qbuffer_or_string_p, x);
+}
-\f
/* 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
#define hard 1
INTERVAL
-validate_interval_range (Lisp_Object object, Lisp_Object *begin, Lisp_Object *end, int force)
+validate_interval_range (Lisp_Object object, Lisp_Object *begin,
+ Lisp_Object *end, bool force)
{
- register INTERVAL i;
+ INTERVAL i;
ptrdiff_t searchpos;
CHECK_STRING_OR_BUFFER (object);
if (CONSP (list))
{
- register int i;
- register Lisp_Object tail;
- for (i = 0, tail = list; CONSP (tail); i++)
+ bool odd_length = 0;
+ Lisp_Object tail;
+ for (tail = list; CONSP (tail); tail = XCDR (tail))
{
- tail = XCDR (tail);
+ odd_length ^= 1;
QUIT;
}
- if (i & 1)
+ if (odd_length)
error ("Odd length text property list");
return list;
}
return Fcons (list, Fcons (Qnil, Qnil));
}
-/* Return nonzero if interval I has all the properties,
+/* Return true if interval I has all the properties,
with the same values, of list PLIST. */
-static int
+static bool
interval_has_all_properties (Lisp_Object plist, INTERVAL i)
{
- register Lisp_Object tail1, tail2, sym1;
- register int found;
+ Lisp_Object tail1, tail2;
/* Go through each element of PLIST. */
for (tail1 = plist; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
{
- sym1 = XCAR (tail1);
- found = 0;
+ Lisp_Object sym1 = XCAR (tail1);
+ bool found = 0;
/* Go through I's plist, looking for sym1 */
for (tail2 = i->plist; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
return 1;
}
-/* Return nonzero if the plist of interval I has any of the
+/* Return true if the plist of interval I has any of the
properties of PLIST, regardless of their values. */
-static int
+static bool
interval_has_some_properties (Lisp_Object plist, INTERVAL i)
{
- register Lisp_Object tail1, tail2, sym;
+ Lisp_Object tail1, tail2, sym;
/* Go through each element of PLIST. */
for (tail1 = plist; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
/* Return nonzero if the plist of interval I has any of the
property names in LIST, regardless of their values. */
-static int
+static bool
interval_has_some_properties_list (Lisp_Object list, INTERVAL i)
{
- register Lisp_Object tail1, tail2, sym;
+ Lisp_Object tail1, tail2, sym;
/* Go through each element of LIST. */
for (tail1 = list; CONSP (tail1); tail1 = XCDR (tail1))
OBJECT should be the string or buffer the interval is in.
- Return nonzero if this changes I (i.e., if any members of PLIST
+ Return true if this changes I (i.e., if any members of PLIST
are actually added to I's plist) */
-static int
+static bool
add_properties (Lisp_Object plist, INTERVAL i, Lisp_Object object)
{
Lisp_Object tail1, tail2, sym1, val1;
- register int changed = 0;
- register int found;
+ bool changed = 0;
struct gcpro gcpro1, gcpro2, gcpro3;
tail1 = plist;
/* Go through each element of PLIST. */
for (tail1 = plist; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
{
+ bool found = 0;
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)))
/* I's property has a different value -- change it */
Fsetcar (this_cdr, val1);
- changed++;
+ changed = 1;
break;
}
sym1, Qnil, object);
}
set_interval_plist (i, Fcons (sym1, Fcons (val1, i->plist)));
- changed++;
+ changed = 1;
}
}
(If PLIST is non-nil, use that, otherwise use LIST.)
OBJECT is the string or buffer containing I. */
-static int
+static bool
remove_properties (Lisp_Object plist, Lisp_Object list, INTERVAL i, Lisp_Object object)
{
- register Lisp_Object tail1, tail2, sym, current_plist;
- register int changed = 0;
+ Lisp_Object tail1, tail2, sym, current_plist;
+ bool changed = 0;
- /* Nonzero means tail1 is a plist, otherwise it is a list. */
- int use_plist;
+ /* True means tail1 is a plist, otherwise it is a list. */
+ bool use_plist;
current_plist = i->plist;
object);
current_plist = XCDR (XCDR (current_plist));
- changed++;
+ changed = 1;
}
/* Go through I's plist, looking for SYM. */
sym, XCAR (XCDR (this)), object);
Fsetcdr (XCDR (tail2), XCDR (XCDR (this)));
- changed++;
+ changed = 1;
}
tail2 = this;
}
if (WINDOWP (object))
{
+ CHECK_LIVE_WINDOW (object);
w = XWINDOW (object);
- object = w->buffer;
+ object = w->contents;
}
if (BUFFERP (object))
{
Return t if any property value actually changed, nil otherwise. */)
(Lisp_Object start, Lisp_Object end, Lisp_Object properties, Lisp_Object object)
{
- register INTERVAL i, unchanged;
- register ptrdiff_t s, len;
- register int modified = 0;
+ INTERVAL i, unchanged;
+ ptrdiff_t s, len;
+ bool modified = 0;
struct gcpro gcpro1;
+ bool first_time = 1;
properties = validate_plist (properties);
if (NILP (properties))
if (NILP (object))
XSETBUFFER (object, current_buffer);
+ retry:
i = validate_interval_range (object, &start, &end, hard);
if (!i)
return Qnil;
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))
{
- /* If this interval already has the properties, we can
- skip it. */
- if (interval_has_all_properties (properties, i))
+ ptrdiff_t got = LENGTH (i) - (s - i->position);
+
+ do
{
- ptrdiff_t got = (LENGTH (i) - (s - i->position));
if (got >= len)
RETURN_UNGCPRO (Qnil);
len -= got;
i = next_interval (i);
+ got = LENGTH (i);
}
- else
+ while (interval_has_all_properties (properties, i));
+ }
+ else if (i->position != s)
+ {
+ /* If we're not starting on an interval boundary, we have to
+ split this interval. */
+ unchanged = i;
+ i = split_interval_right (unchanged, s - unchanged->position);
+ copy_properties (unchanged, i);
+ }
+
+ if (BUFFERP (object) && first_time)
+ {
+ ptrdiff_t prev_total_length = TOTAL_LENGTH (i);
+ ptrdiff_t prev_pos = i->position;
+
+ modify_region (object, start, end);
+ /* If someone called us recursively as a side effect of
+ modify_region, and changed the intervals behind our back
+ (could happen if lock_file, called by prepare_to_modify_buffer,
+ triggers redisplay, and that calls add-text-properties again
+ in the same buffer), we cannot continue with I, because its
+ data changed. So we restart the interval analysis anew. */
+ if (TOTAL_LENGTH (i) != prev_total_length
+ || i->position != prev_pos)
{
- unchanged = i;
- i = split_interval_right (unchanged, s - unchanged->position);
- copy_properties (unchanged, i);
+ first_time = 0;
+ goto retry;
}
}
- 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 (;;)
{
signal_after_change (XINT (start), XINT (end) - XINT (start),
XINT (end) - XINT (start));
- return modified ? Qt : Qnil;
+ eassert (modified);
+ return Qt;
}
if (LENGTH (i) == len)
}
len -= LENGTH (i);
- modified += add_properties (properties, i, object);
+ modified |= add_properties (properties, i, object);
i = next_interval (i);
}
}
}
if (BUFFERP (object) && !NILP (coherent_change_p))
- modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
+ modify_region (object, start, end);
set_text_properties_1 (start, end, properties, object, i);
}
/* Replace properties of text from START to END with new list of
- properties PROPERTIES. BUFFER is the buffer containing
+ properties PROPERTIES. OBJECT is the buffer or string 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.
+ You should provide the interval that START is located in as I.
START and END can be in any order. */
void
-set_text_properties_1 (Lisp_Object start, Lisp_Object end, Lisp_Object properties, Lisp_Object buffer, 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;
else
return;
- if (i == NULL)
- i = find_interval (buffer_intervals (XBUFFER (buffer)), s);
+ eassert (i);
if (i->position != s)
{
{
copy_properties (unchanged, i);
i = split_interval_left (i, len);
- set_properties (properties, i, buffer);
+ set_properties (properties, i, object);
return;
}
- set_properties (properties, i, buffer);
+ set_properties (properties, i, object);
if (LENGTH (i) == len)
return;
/* 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);
+ set_properties (properties, i, object);
if (prev_changed)
merge_interval_left (i);
return;
/* 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);
+ set_properties (properties, i, object);
if (!prev_changed)
prev_changed = i;
else
Use `set-text-properties' if you want to remove all text properties. */)
(Lisp_Object start, Lisp_Object end, Lisp_Object properties, Lisp_Object object)
{
- register INTERVAL i, unchanged;
- register ptrdiff_t s, len;
- register int modified = 0;
+ INTERVAL i, unchanged;
+ ptrdiff_t s, len;
+ bool modified = 0;
+ bool first_time = 1;
if (NILP (object))
XSETBUFFER (object, current_buffer);
+ retry:
i = validate_interval_range (object, &start, &end, soft);
if (!i)
return Qnil;
s = XINT (start);
len = XINT (end) - s;
- if (i->position != s)
+ /* If there are no properties on this entire interval, return. */
+ if (! interval_has_some_properties (properties, i))
{
- /* No properties on this first interval -- return if
- it covers the entire region. */
- if (! interval_has_some_properties (properties, i))
+ ptrdiff_t got = LENGTH (i) - (s - i->position);
+
+ do
{
- ptrdiff_t got = (LENGTH (i) - (s - i->position));
if (got >= len)
return Qnil;
len -= got;
i = next_interval (i);
+ got = LENGTH (i);
}
- /* Split away the beginning of this interval; what we don't
- want to modify. */
- else
+ while (! interval_has_some_properties (properties, i));
+ }
+ /* Split away the beginning of this interval; what we don't
+ want to modify. */
+ else if (i->position != s)
+ {
+ unchanged = i;
+ i = split_interval_right (unchanged, s - unchanged->position);
+ copy_properties (unchanged, i);
+ }
+
+ if (BUFFERP (object) && first_time)
+ {
+ ptrdiff_t prev_total_length = TOTAL_LENGTH (i);
+ ptrdiff_t prev_pos = i->position;
+
+ modify_region (object, start, end);
+ /* If someone called us recursively as a side effect of
+ modify_region, and changed the intervals behind our back
+ (could happen if lock_file, called by prepare_to_modify_buffer,
+ triggers redisplay, and that calls add-text-properties again
+ in the same buffer), we cannot continue with I, because its
+ data changed. So we restart the interval analysis anew. */
+ if (TOTAL_LENGTH (i) != prev_total_length
+ || i->position != prev_pos)
{
- unchanged = i;
- i = split_interval_right (unchanged, s - unchanged->position);
- copy_properties (unchanged, i);
+ first_time = 0;
+ goto retry;
}
}
- 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 (LENGTH (i) >= len)
{
if (! interval_has_some_properties (properties, i))
- return modified ? Qt : Qnil;
+ {
+ eassert (modified);
+ if (BUFFERP (object))
+ signal_after_change (XINT (start), XINT (end) - XINT (start),
+ XINT (end) - XINT (start));
+ return Qt;
+ }
if (LENGTH (i) == len)
{
}
len -= LENGTH (i);
- modified += remove_properties (properties, Qnil, i, object);
+ modified |= remove_properties (properties, Qnil, i, object);
i = next_interval (i);
}
}
Return t if any property was actually removed, nil otherwise. */)
(Lisp_Object start, Lisp_Object end, Lisp_Object list_of_properties, Lisp_Object object)
{
- register INTERVAL i, unchanged;
- register ptrdiff_t s, len;
- register int modified = 0;
+ INTERVAL i, unchanged;
+ ptrdiff_t s, len;
+ bool modified = 0;
Lisp_Object properties;
properties = list_of_properties;
s = XINT (start);
len = XINT (end) - s;
- if (i->position != s)
+ /* If there are no properties on the interval, return. */
+ if (! interval_has_some_properties_list (properties, i))
{
- /* No properties on this first interval -- return if
- it covers the entire region. */
- if (! interval_has_some_properties_list (properties, i))
+ ptrdiff_t got = LENGTH (i) - (s - i->position);
+
+ do
{
- ptrdiff_t got = (LENGTH (i) - (s - i->position));
if (got >= len)
return Qnil;
len -= got;
i = next_interval (i);
+ got = LENGTH (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);
- }
+ while (! interval_has_some_properties_list (properties, i));
+ }
+ /* Split away the beginning of this interval; what we don't
+ want to modify. */
+ else if (i->position != s)
+ {
+ 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.
else if (LENGTH (i) == len)
{
if (!modified && BUFFERP (object))
- modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
+ modify_region (object, start, end);
remove_properties (Qnil, properties, i, object);
if (BUFFERP (object))
signal_after_change (XINT (start), XINT (end) - XINT (start),
i = split_interval_left (i, len);
copy_properties (unchanged, i);
if (!modified && BUFFERP (object))
- modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
+ modify_region (object, start, end);
remove_properties (Qnil, properties, i, object);
if (BUFFERP (object))
signal_after_change (XINT (start), XINT (end) - XINT (start),
if (interval_has_some_properties_list (properties, i))
{
if (!modified && BUFFERP (object))
- modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
+ modify_region (object, start, end);
remove_properties (Qnil, properties, i, object);
modified = 1;
}
text_property_stickiness (Lisp_Object prop, Lisp_Object pos, Lisp_Object buffer)
{
Lisp_Object prev_pos, front_sticky;
- int is_rear_sticky = 1, is_front_sticky = 0; /* defaults */
+ bool is_rear_sticky = 1, is_front_sticky = 0; /* defaults */
Lisp_Object defalt = Fassq (prop, Vtext_property_default_nonsticky);
if (NILP (buffer))
Lisp_Object stuff;
Lisp_Object plist;
ptrdiff_t s, e, e2, p, len;
- int modified = 0;
+ bool modified = 0;
struct gcpro gcpro1, gcpro2;
i = validate_interval_range (src, &start, &end, soft);
res = Fadd_text_properties (Fcar (res), Fcar (Fcdr (res)),
Fcar (Fcdr (Fcdr (res))), dest);
if (! NILP (res))
- modified++;
+ modified = 1;
stuff = Fcdr (stuff);
}
/* Add text properties to OBJECT from LIST. LIST is a list of triples
(START END PLIST), where START and END are positions and PLIST is a
property list containing the text properties to add. Adjust START
- and END positions by DELTA before adding properties. Value is
- non-zero if OBJECT was modified. */
+ and END positions by DELTA before adding properties. */
-int
+void
add_text_properties_from_list (Lisp_Object object, Lisp_Object list, Lisp_Object delta)
{
struct gcpro gcpro1, gcpro2;
- int modified_p = 0;
GCPRO2 (list, object);
for (; CONSP (list); list = XCDR (list))
{
- Lisp_Object item, start, end, plist, tem;
+ 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));
plist = XCAR (XCDR (XCDR (item)));
- tem = Fadd_text_properties (start, end, plist, object);
- if (!NILP (tem))
- modified_p = 1;
+ Fadd_text_properties (start, end, plist, object);
}
UNGCPRO;
- return modified_p;
}