diff options
| author | Richard M. Stallman | 1993-03-01 08:57:31 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1993-03-01 08:57:31 +0000 |
| commit | d4b530ad2db1e26f7c6e6635ecdf3b66b74f3585 (patch) | |
| tree | c40dd5ba50c0fff9ef4a1a698e1053fdbfff14d3 /src | |
| parent | 323a7ad4fd811dd71425e2fed7ebafb9daaaed72 (diff) | |
| download | emacs-d4b530ad2db1e26f7c6e6635ecdf3b66b74f3585.tar.gz emacs-d4b530ad2db1e26f7c6e6635ecdf3b66b74f3585.zip | |
(Fadd_text_properties, Fremove_text_properties):
Add len>0 as condition for main loop.
Abort if reach a null interval.
(Fset_text_properties): Abort if reach a null interval.
(Ftext_properties_at, Fget_text_property):
Return nil if POS is end of OBJECT.
(add_properties): Use NILP to test result of Fequal.
No longer inline.
(remove_properties): No longer inline.
(set_properties): Total rewrite as function.
(validate_interval_range): Don't alter *begin at end of buffer.
But do search for a position just before the end.
Return null for an empty string.
(validate_interval_range): Allow 0 as position in string.
Add 1 to specified string positions.
(Fprevious_single_property_change): Subtract 1 if object is string.
(Fnext_single_property_change): Likewise.
(Fprevious_property_change, Fnext_property_change): Likewise.
(remove_properties): Call modify_buffer.
(add_properties): Likewise.
(Fadd_text_properties): Pass new arg to add_properties.
(Fremove_text_properties): Likewise.
(add_properties, remove_properties): New arg OBJECT. Record undo info.
(Fput_text_property): New function.
Diffstat (limited to 'src')
| -rw-r--r-- | src/textprop.c | 213 |
1 files changed, 172 insertions, 41 deletions
diff --git a/src/textprop.c b/src/textprop.c index d8a674a1e70..97951ca1846 100644 --- a/src/textprop.c +++ b/src/textprop.c | |||
| @@ -30,7 +30,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |||
| 30 | set_properties needs to deal with the interval property cache. | 30 | set_properties needs to deal with the interval property cache. |
| 31 | 31 | ||
| 32 | It is assumed that for any interval plist, a property appears | 32 | It is assumed that for any interval plist, a property appears |
| 33 | only once on the list. Although some code i.e., remove_properties (), | 33 | only once on the list. Although some code i.e., remove_properties, |
| 34 | handles the more general case, the uniqueness of properties is | 34 | handles the more general case, the uniqueness of properties is |
| 35 | neccessary for the system to remain consistent. This requirement | 35 | neccessary for the system to remain consistent. This requirement |
| 36 | is enforced by the subrs installing properties onto the intervals. */ | 36 | is enforced by the subrs installing properties onto the intervals. */ |
| @@ -56,6 +56,9 @@ Lisp_Object Qinvisible, Qread_only; | |||
| 56 | to by BEGIN and END may be integers or markers; if the latter, they | 56 | to by BEGIN and END may be integers or markers; if the latter, they |
| 57 | are coerced to integers. | 57 | are coerced to integers. |
| 58 | 58 | ||
| 59 | When OBJECT is a string, we increment *BEGIN and *END | ||
| 60 | to make them origin-one. | ||
| 61 | |||
| 59 | Note that buffer points don't correspond to interval indices. | 62 | Note that buffer points don't correspond to interval indices. |
| 60 | For example, point-max is 1 greater than the index of the last | 63 | For example, point-max is 1 greater than the index of the last |
| 61 | character. This difference is handled in the caller, which uses | 64 | character. This difference is handled in the caller, which uses |
| @@ -67,7 +70,7 @@ Lisp_Object Qinvisible, Qread_only; | |||
| 67 | If FORCE is soft (0), it's OK to return NULL_INTERVAL. Otherwise, | 70 | If FORCE is soft (0), it's OK to return NULL_INTERVAL. Otherwise, |
| 68 | create an interval tree for OBJECT if one doesn't exist, provided | 71 | create an interval tree for OBJECT if one doesn't exist, provided |
| 69 | the object actually contains text. In the current design, if there | 72 | the object actually contains text. In the current design, if there |
| 70 | is no text, there can be no text properties. */ | 73 | is no text, there can be no text properties. */ |
| 71 | 74 | ||
| 72 | #define soft 0 | 75 | #define soft 0 |
| 73 | #define hard 1 | 76 | #define hard 1 |
| @@ -78,6 +81,8 @@ validate_interval_range (object, begin, end, force) | |||
| 78 | int force; | 81 | int force; |
| 79 | { | 82 | { |
| 80 | register INTERVAL i; | 83 | register INTERVAL i; |
| 84 | int searchpos; | ||
| 85 | |||
| 81 | CHECK_STRING_OR_BUFFER (object, 0); | 86 | CHECK_STRING_OR_BUFFER (object, 0); |
| 82 | CHECK_NUMBER_COERCE_MARKER (*begin, 0); | 87 | CHECK_NUMBER_COERCE_MARKER (*begin, 0); |
| 83 | CHECK_NUMBER_COERCE_MARKER (*end, 0); | 88 | CHECK_NUMBER_COERCE_MARKER (*end, 0); |
| @@ -89,44 +94,60 @@ validate_interval_range (object, begin, end, force) | |||
| 89 | 94 | ||
| 90 | if (XINT (*begin) > XINT (*end)) | 95 | if (XINT (*begin) > XINT (*end)) |
| 91 | { | 96 | { |
| 92 | register int n; | 97 | Lisp_Object n; |
| 93 | n = XFASTINT (*begin); /* This is legit even if *begin is < 0 */ | 98 | n = *begin; |
| 94 | *begin = *end; | 99 | *begin = *end; |
| 95 | XFASTINT (*end) = n; /* because this is all we do with n. */ | 100 | *end = n; |
| 96 | } | 101 | } |
| 97 | 102 | ||
| 98 | if (XTYPE (object) == Lisp_Buffer) | 103 | if (XTYPE (object) == Lisp_Buffer) |
| 99 | { | 104 | { |
| 100 | register struct buffer *b = XBUFFER (object); | 105 | register struct buffer *b = XBUFFER (object); |
| 101 | 106 | ||
| 102 | /* If there's no text, there are no properties. */ | ||
| 103 | if (BUF_BEGV (b) == BUF_ZV (b)) | ||
| 104 | return NULL_INTERVAL; | ||
| 105 | |||
| 106 | if (!(BUF_BEGV (b) <= XINT (*begin) && XINT (*begin) <= XINT (*end) | 107 | if (!(BUF_BEGV (b) <= XINT (*begin) && XINT (*begin) <= XINT (*end) |
| 107 | && XINT (*end) <= BUF_ZV (b))) | 108 | && XINT (*end) <= BUF_ZV (b))) |
| 108 | args_out_of_range (*begin, *end); | 109 | args_out_of_range (*begin, *end); |
| 109 | i = b->intervals; | 110 | i = b->intervals; |
| 110 | 111 | ||
| 112 | /* If there's no text, there are no properties. */ | ||
| 113 | if (BUF_BEGV (b) == BUF_ZV (b)) | ||
| 114 | return NULL_INTERVAL; | ||
| 115 | |||
| 116 | searchpos = XINT (*begin); | ||
| 117 | if (searchpos == BUF_Z (b)) | ||
| 118 | searchpos--; | ||
| 119 | #if 0 | ||
| 111 | /* Special case for point-max: return the interval for the | 120 | /* Special case for point-max: return the interval for the |
| 112 | last character. */ | 121 | last character. */ |
| 113 | if (*begin == *end && *begin == BUF_Z (b)) | 122 | if (*begin == *end && *begin == BUF_Z (b)) |
| 114 | *begin -= 1; | 123 | *begin -= 1; |
| 124 | #endif | ||
| 115 | } | 125 | } |
| 116 | else | 126 | else |
| 117 | { | 127 | { |
| 118 | register struct Lisp_String *s = XSTRING (object); | 128 | register struct Lisp_String *s = XSTRING (object); |
| 119 | 129 | ||
| 120 | if (! (1 <= XINT (*begin) && XINT (*begin) <= XINT (*end) | 130 | if (! (0 <= XINT (*begin) && XINT (*begin) <= XINT (*end) |
| 121 | && XINT (*end) <= s->size)) | 131 | && XINT (*end) <= s->size)) |
| 122 | args_out_of_range (*begin, *end); | 132 | args_out_of_range (*begin, *end); |
| 133 | /* User-level Positions in strings start with 0, | ||
| 134 | but the interval code always wants positions starting with 1. */ | ||
| 135 | XFASTINT (*begin) += 1; | ||
| 136 | XFASTINT (*end) += 1; | ||
| 123 | i = s->intervals; | 137 | i = s->intervals; |
| 138 | |||
| 139 | if (s->size == 0) | ||
| 140 | return NULL_INTERVAL; | ||
| 141 | |||
| 142 | searchpos = XINT (*begin); | ||
| 143 | if (searchpos > s->size) | ||
| 144 | searchpos--; | ||
| 124 | } | 145 | } |
| 125 | 146 | ||
| 126 | if (NULL_INTERVAL_P (i)) | 147 | if (NULL_INTERVAL_P (i)) |
| 127 | return (force ? create_root_interval (object) : i); | 148 | return (force ? create_root_interval (object) : i); |
| 128 | 149 | ||
| 129 | return find_interval (i, XINT (*begin)); | 150 | return find_interval (i, searchpos); |
| 130 | } | 151 | } |
| 131 | 152 | ||
| 132 | /* Validate LIST as a property list. If LIST is not a list, then | 153 | /* Validate LIST as a property list. If LIST is not a list, then |
| @@ -153,8 +174,6 @@ validate_plist (list) | |||
| 153 | return Fcons (list, Fcons (Qnil, Qnil)); | 174 | return Fcons (list, Fcons (Qnil, Qnil)); |
| 154 | } | 175 | } |
| 155 | 176 | ||
| 156 | #define set_properties(list,i) (i->plist = Fcopy_sequence (list)) | ||
| 157 | |||
| 158 | /* Return nonzero if interval I has all the properties, | 177 | /* Return nonzero if interval I has all the properties, |
| 159 | with the same values, of list PLIST. */ | 178 | with the same values, of list PLIST. */ |
| 160 | 179 | ||
| @@ -217,18 +236,49 @@ interval_has_some_properties (plist, i) | |||
| 217 | 236 | ||
| 218 | return 0; | 237 | return 0; |
| 219 | } | 238 | } |
| 239 | |||
| 240 | /* Set the properties of INTERVAL to PROPERTIES, | ||
| 241 | and record undo info for the previous values. | ||
| 242 | OBJECT is the string or buffer that INTERVAL belongs to. */ | ||
| 243 | |||
| 244 | static void | ||
| 245 | set_properties (properties, interval, object) | ||
| 246 | Lisp_Object properties, object; | ||
| 247 | INTERVAL interval; | ||
| 248 | { | ||
| 249 | Lisp_Object oldprops; | ||
| 250 | oldprops = interval->plist; | ||
| 251 | |||
| 252 | /* Record undo for old properties. */ | ||
| 253 | while (XTYPE (oldprops) == Lisp_Cons) | ||
| 254 | { | ||
| 255 | Lisp_Object sym; | ||
| 256 | sym = Fcar (oldprops); | ||
| 257 | record_property_change (interval->position, LENGTH (interval), | ||
| 258 | sym, Fcar_safe (Fcdr (oldprops)), | ||
| 259 | object); | ||
| 260 | |||
| 261 | oldprops = Fcdr_safe (Fcdr (oldprops)); | ||
| 262 | } | ||
| 263 | |||
| 264 | /* Store new properties. */ | ||
| 265 | interval->plist = Fcopy_sequence (properties); | ||
| 266 | } | ||
| 220 | 267 | ||
| 221 | /* Add the properties of PLIST to the interval I, or set | 268 | /* Add the properties of PLIST to the interval I, or set |
| 222 | the value of I's property to the value of the property on PLIST | 269 | the value of I's property to the value of the property on PLIST |
| 223 | if they are different. | 270 | if they are different. |
| 224 | 271 | ||
| 272 | OBJECT should be the string or buffer the interval is in. | ||
| 273 | |||
| 225 | Return nonzero if this changes I (i.e., if any members of PLIST | 274 | Return nonzero if this changes I (i.e., if any members of PLIST |
| 226 | are actually added to I's plist) */ | 275 | are actually added to I's plist) */ |
| 227 | 276 | ||
| 228 | static INLINE int | 277 | static int |
| 229 | add_properties (plist, i) | 278 | add_properties (plist, i, object) |
| 230 | Lisp_Object plist; | 279 | Lisp_Object plist; |
| 231 | INTERVAL i; | 280 | INTERVAL i; |
| 281 | Lisp_Object object; | ||
| 232 | { | 282 | { |
| 233 | register Lisp_Object tail1, tail2, sym1, val1; | 283 | register Lisp_Object tail1, tail2, sym1, val1; |
| 234 | register int changed = 0; | 284 | register int changed = 0; |
| @@ -252,9 +302,18 @@ add_properties (plist, i) | |||
| 252 | 302 | ||
| 253 | /* The properties have the same value on both lists. | 303 | /* The properties have the same value on both lists. |
| 254 | Continue to the next property. */ | 304 | Continue to the next property. */ |
| 255 | if (Fequal (val1, Fcar (this_cdr))) | 305 | if (!NILP (Fequal (val1, Fcar (this_cdr)))) |
| 256 | break; | 306 | break; |
| 257 | 307 | ||
| 308 | /* Record this change in the buffer, for undo purposes. */ | ||
| 309 | if (XTYPE (object) == Lisp_Buffer) | ||
| 310 | { | ||
| 311 | record_property_change (i->position, LENGTH (i), | ||
| 312 | sym1, Fcar (this_cdr), object); | ||
| 313 | modify_region (make_number (i->position), | ||
| 314 | make_number (i->position + LENGTH (i))); | ||
| 315 | } | ||
| 316 | |||
| 258 | /* I's property has a different value -- change it */ | 317 | /* I's property has a different value -- change it */ |
| 259 | Fsetcar (this_cdr, val1); | 318 | Fsetcar (this_cdr, val1); |
| 260 | changed++; | 319 | changed++; |
| @@ -263,6 +322,14 @@ add_properties (plist, i) | |||
| 263 | 322 | ||
| 264 | if (! found) | 323 | if (! found) |
| 265 | { | 324 | { |
| 325 | /* Record this change in the buffer, for undo purposes. */ | ||
| 326 | if (XTYPE (object) == Lisp_Buffer) | ||
| 327 | { | ||
| 328 | record_property_change (i->position, LENGTH (i), | ||
| 329 | sym1, Qnil, object); | ||
| 330 | modify_region (make_number (i->position), | ||
| 331 | make_number (i->position + LENGTH (i))); | ||
| 332 | } | ||
| 266 | i->plist = Fcons (sym1, Fcons (val1, i->plist)); | 333 | i->plist = Fcons (sym1, Fcons (val1, i->plist)); |
| 267 | changed++; | 334 | changed++; |
| 268 | } | 335 | } |
| @@ -272,12 +339,14 @@ add_properties (plist, i) | |||
| 272 | } | 339 | } |
| 273 | 340 | ||
| 274 | /* For any members of PLIST which are properties of I, remove them | 341 | /* For any members of PLIST which are properties of I, remove them |
| 275 | from I's plist. */ | 342 | from I's plist. |
| 343 | OBJECT is the string or buffer containing I. */ | ||
| 276 | 344 | ||
| 277 | static INLINE int | 345 | static int |
| 278 | remove_properties (plist, i) | 346 | remove_properties (plist, i, object) |
| 279 | Lisp_Object plist; | 347 | Lisp_Object plist; |
| 280 | INTERVAL i; | 348 | INTERVAL i; |
| 349 | Lisp_Object object; | ||
| 281 | { | 350 | { |
| 282 | register Lisp_Object tail1, tail2, sym; | 351 | register Lisp_Object tail1, tail2, sym; |
| 283 | register Lisp_Object current_plist = i->plist; | 352 | register Lisp_Object current_plist = i->plist; |
| @@ -291,6 +360,15 @@ remove_properties (plist, i) | |||
| 291 | /* First, remove the symbol if its at the head of the list */ | 360 | /* First, remove the symbol if its at the head of the list */ |
| 292 | while (! NILP (current_plist) && EQ (sym, Fcar (current_plist))) | 361 | while (! NILP (current_plist) && EQ (sym, Fcar (current_plist))) |
| 293 | { | 362 | { |
| 363 | if (XTYPE (object) == Lisp_Buffer) | ||
| 364 | { | ||
| 365 | record_property_change (i->position, LENGTH (i), | ||
| 366 | sym, Fcar (Fcdr (current_plist)), | ||
| 367 | object); | ||
| 368 | modify_region (make_number (i->position), | ||
| 369 | make_number (i->position + LENGTH (i))); | ||
| 370 | } | ||
| 371 | |||
| 294 | current_plist = Fcdr (Fcdr (current_plist)); | 372 | current_plist = Fcdr (Fcdr (current_plist)); |
| 295 | changed++; | 373 | changed++; |
| 296 | } | 374 | } |
| @@ -302,6 +380,14 @@ remove_properties (plist, i) | |||
| 302 | register Lisp_Object this = Fcdr (Fcdr (tail2)); | 380 | register Lisp_Object this = Fcdr (Fcdr (tail2)); |
| 303 | if (EQ (sym, Fcar (this))) | 381 | if (EQ (sym, Fcar (this))) |
| 304 | { | 382 | { |
| 383 | if (XTYPE (object) == Lisp_Buffer) | ||
| 384 | { | ||
| 385 | record_property_change (i->position, LENGTH (i), | ||
| 386 | sym, Fcar (Fcdr (this)), object); | ||
| 387 | modify_region (make_number (i->position), | ||
| 388 | make_number (i->position + LENGTH (i))); | ||
| 389 | } | ||
| 390 | |||
| 305 | Fsetcdr (Fcdr (tail2), Fcdr (Fcdr (this))); | 391 | Fsetcdr (Fcdr (tail2), Fcdr (Fcdr (this))); |
| 306 | changed++; | 392 | changed++; |
| 307 | } | 393 | } |
| @@ -314,6 +400,7 @@ remove_properties (plist, i) | |||
| 314 | return changed; | 400 | return changed; |
| 315 | } | 401 | } |
| 316 | 402 | ||
| 403 | #if 0 | ||
| 317 | /* Remove all properties from interval I. Return non-zero | 404 | /* Remove all properties from interval I. Return non-zero |
| 318 | if this changes the interval. */ | 405 | if this changes the interval. */ |
| 319 | 406 | ||
| @@ -327,12 +414,14 @@ erase_properties (i) | |||
| 327 | i->plist = Qnil; | 414 | i->plist = Qnil; |
| 328 | return 1; | 415 | return 1; |
| 329 | } | 416 | } |
| 417 | #endif | ||
| 330 | 418 | ||
| 331 | DEFUN ("text-properties-at", Ftext_properties_at, | 419 | DEFUN ("text-properties-at", Ftext_properties_at, |
| 332 | Stext_properties_at, 1, 2, 0, | 420 | Stext_properties_at, 1, 2, 0, |
| 333 | "Return the list of properties held by the character at POSITION\n\ | 421 | "Return the list of properties held by the character at POSITION\n\ |
| 334 | in optional argument OBJECT, a string or buffer. If nil, OBJECT\n\ | 422 | in optional argument OBJECT, a string or buffer. If nil, OBJECT\n\ |
| 335 | defaults to the current buffer.") | 423 | defaults to the current buffer.\n\ |
| 424 | If POSITION is at the end of OBJECT, the value is nil.") | ||
| 336 | (pos, object) | 425 | (pos, object) |
| 337 | Lisp_Object pos, object; | 426 | Lisp_Object pos, object; |
| 338 | { | 427 | { |
| @@ -344,13 +433,20 @@ defaults to the current buffer.") | |||
| 344 | i = validate_interval_range (object, &pos, &pos, soft); | 433 | i = validate_interval_range (object, &pos, &pos, soft); |
| 345 | if (NULL_INTERVAL_P (i)) | 434 | if (NULL_INTERVAL_P (i)) |
| 346 | return Qnil; | 435 | return Qnil; |
| 436 | /* If POS is at the end of the interval, | ||
| 437 | it means it's the end of OBJECT. | ||
| 438 | There are no properties at the very end, | ||
| 439 | since no character follows. */ | ||
| 440 | if (XINT (pos) == LENGTH (i) + i->position) | ||
| 441 | return Qnil; | ||
| 347 | 442 | ||
| 348 | return i->plist; | 443 | return i->plist; |
| 349 | } | 444 | } |
| 350 | 445 | ||
| 351 | DEFUN ("get-text-property", Fget_text_property, Sget_text_property, 2, 3, 0, | 446 | DEFUN ("get-text-property", Fget_text_property, Sget_text_property, 2, 3, 0, |
| 352 | "Return the value of position POS's property PROP, in OBJECT.\n\ | 447 | "Return the value of position POS's property PROP, in OBJECT.\n\ |
| 353 | OBJECT is optional and defaults to the current buffer.") | 448 | OBJECT is optional and defaults to the current buffer.\n\ |
| 449 | If POSITION is at the end of OBJECT, the value is nil.") | ||
| 354 | (pos, prop, object) | 450 | (pos, prop, object) |
| 355 | Lisp_Object pos, object; | 451 | Lisp_Object pos, object; |
| 356 | register Lisp_Object prop; | 452 | register Lisp_Object prop; |
| @@ -360,11 +456,17 @@ OBJECT is optional and defaults to the current buffer.") | |||
| 360 | 456 | ||
| 361 | if (NILP (object)) | 457 | if (NILP (object)) |
| 362 | XSET (object, Lisp_Buffer, current_buffer); | 458 | XSET (object, Lisp_Buffer, current_buffer); |
| 363 | |||
| 364 | i = validate_interval_range (object, &pos, &pos, soft); | 459 | i = validate_interval_range (object, &pos, &pos, soft); |
| 365 | if (NULL_INTERVAL_P (i)) | 460 | if (NULL_INTERVAL_P (i)) |
| 366 | return Qnil; | 461 | return Qnil; |
| 367 | 462 | ||
| 463 | /* If POS is at the end of the interval, | ||
| 464 | it means it's the end of OBJECT. | ||
| 465 | There are no properties at the very end, | ||
| 466 | since no character follows. */ | ||
| 467 | if (XINT (pos) == LENGTH (i) + i->position) | ||
| 468 | return Qnil; | ||
| 469 | |||
| 368 | for (tail = i->plist; !NILP (tail); tail = Fcdr (Fcdr (tail))) | 470 | for (tail = i->plist; !NILP (tail); tail = Fcdr (Fcdr (tail))) |
| 369 | { | 471 | { |
| 370 | register Lisp_Object tem; | 472 | register Lisp_Object tem; |
| @@ -402,7 +504,8 @@ If the value is non-nil, it is a position greater than POS, never equal.") | |||
| 402 | if (NULL_INTERVAL_P (next)) | 504 | if (NULL_INTERVAL_P (next)) |
| 403 | return Qnil; | 505 | return Qnil; |
| 404 | 506 | ||
| 405 | return next->position; | 507 | return next->position - (XTYPE (object) == Lisp_String); |
| 508 | ; | ||
| 406 | } | 509 | } |
| 407 | 510 | ||
| 408 | DEFUN ("next-single-property-change", Fnext_single_property_change, | 511 | DEFUN ("next-single-property-change", Fnext_single_property_change, |
| @@ -434,7 +537,7 @@ If the value is non-nil, it is a position greater than POS, never equal.") | |||
| 434 | if (NULL_INTERVAL_P (next)) | 537 | if (NULL_INTERVAL_P (next)) |
| 435 | return Qnil; | 538 | return Qnil; |
| 436 | 539 | ||
| 437 | return next->position; | 540 | return next->position - (XTYPE (object) == Lisp_String); |
| 438 | } | 541 | } |
| 439 | 542 | ||
| 440 | DEFUN ("previous-property-change", Fprevious_property_change, | 543 | DEFUN ("previous-property-change", Fprevious_property_change, |
| @@ -463,7 +566,8 @@ If the value is non-nil, it is a position less than POS, never equal.") | |||
| 463 | if (NULL_INTERVAL_P (previous)) | 566 | if (NULL_INTERVAL_P (previous)) |
| 464 | return Qnil; | 567 | return Qnil; |
| 465 | 568 | ||
| 466 | return previous->position + LENGTH (previous) - 1; | 569 | return (previous->position + LENGTH (previous) - 1 |
| 570 | - (XTYPE (object) == Lisp_String)); | ||
| 467 | } | 571 | } |
| 468 | 572 | ||
| 469 | DEFUN ("previous-single-property-change", Fprevious_single_property_change, | 573 | DEFUN ("previous-single-property-change", Fprevious_single_property_change, |
| @@ -495,7 +599,8 @@ If the value is non-nil, it is a position less than POS, never equal.") | |||
| 495 | if (NULL_INTERVAL_P (previous)) | 599 | if (NULL_INTERVAL_P (previous)) |
| 496 | return Qnil; | 600 | return Qnil; |
| 497 | 601 | ||
| 498 | return previous->position + LENGTH (previous) - 1; | 602 | return (previous->position + LENGTH (previous) - 1 |
| 603 | - (XTYPE (object) == Lisp_String)); | ||
| 499 | } | 604 | } |
| 500 | 605 | ||
| 501 | DEFUN ("add-text-properties", Fadd_text_properties, | 606 | DEFUN ("add-text-properties", Fadd_text_properties, |
| @@ -548,11 +653,11 @@ Return t if any property value actually changed, nil otherwise.") | |||
| 548 | { | 653 | { |
| 549 | i = split_interval_left (i, len + 1); | 654 | i = split_interval_left (i, len + 1); |
| 550 | copy_properties (unchanged, i); | 655 | copy_properties (unchanged, i); |
| 551 | add_properties (properties, i); | 656 | add_properties (properties, i, object); |
| 552 | return Qt; | 657 | return Qt; |
| 553 | } | 658 | } |
| 554 | 659 | ||
| 555 | add_properties (properties, i); | 660 | add_properties (properties, i, object); |
| 556 | modified = 1; | 661 | modified = 1; |
| 557 | len -= LENGTH (i); | 662 | len -= LENGTH (i); |
| 558 | i = next_interval (i); | 663 | i = next_interval (i); |
| @@ -560,8 +665,11 @@ Return t if any property value actually changed, nil otherwise.") | |||
| 560 | } | 665 | } |
| 561 | 666 | ||
| 562 | /* We are at the beginning of an interval, with len to scan */ | 667 | /* We are at the beginning of an interval, with len to scan */ |
| 563 | while (1) | 668 | while (len > 0) |
| 564 | { | 669 | { |
| 670 | if (i == 0) | ||
| 671 | abort (); | ||
| 672 | |||
| 565 | if (LENGTH (i) >= len) | 673 | if (LENGTH (i) >= len) |
| 566 | { | 674 | { |
| 567 | if (interval_has_all_properties (properties, i)) | 675 | if (interval_has_all_properties (properties, i)) |
| @@ -569,7 +677,7 @@ Return t if any property value actually changed, nil otherwise.") | |||
| 569 | 677 | ||
| 570 | if (LENGTH (i) == len) | 678 | if (LENGTH (i) == len) |
| 571 | { | 679 | { |
| 572 | add_properties (properties, i); | 680 | add_properties (properties, i, object); |
| 573 | return Qt; | 681 | return Qt; |
| 574 | } | 682 | } |
| 575 | 683 | ||
| @@ -577,16 +685,32 @@ Return t if any property value actually changed, nil otherwise.") | |||
| 577 | unchanged = i; | 685 | unchanged = i; |
| 578 | i = split_interval_left (unchanged, len + 1); | 686 | i = split_interval_left (unchanged, len + 1); |
| 579 | copy_properties (unchanged, i); | 687 | copy_properties (unchanged, i); |
| 580 | add_properties (properties, i); | 688 | add_properties (properties, i, object); |
| 581 | return Qt; | 689 | return Qt; |
| 582 | } | 690 | } |
| 583 | 691 | ||
| 584 | len -= LENGTH (i); | 692 | len -= LENGTH (i); |
| 585 | modified += add_properties (properties, i); | 693 | modified += add_properties (properties, i, object); |
| 586 | i = next_interval (i); | 694 | i = next_interval (i); |
| 587 | } | 695 | } |
| 588 | } | 696 | } |
| 589 | 697 | ||
| 698 | DEFUN ("put-text-property", Fput_text_property, | ||
| 699 | Sput_text_property, 4, 5, 0, | ||
| 700 | "Set one property of the text from START to END.\n\ | ||
| 701 | The third and fourth arguments PROP and VALUE\n\ | ||
| 702 | specify the property to add.\n\ | ||
| 703 | The optional fifth argument, OBJECT,\n\ | ||
| 704 | is the string or buffer containing the text.") | ||
| 705 | (start, end, prop, value, object) | ||
| 706 | Lisp_Object start, end, prop, value, object; | ||
| 707 | { | ||
| 708 | Fadd_text_properties (start, end, | ||
| 709 | Fcons (prop, Fcons (value, Qnil)), | ||
| 710 | object); | ||
| 711 | return Qnil; | ||
| 712 | } | ||
| 713 | |||
| 590 | DEFUN ("set-text-properties", Fset_text_properties, | 714 | DEFUN ("set-text-properties", Fset_text_properties, |
| 591 | Sset_text_properties, 3, 4, 0, | 715 | Sset_text_properties, 3, 4, 0, |
| 592 | "Completely replace properties of text from START to END.\n\ | 716 | "Completely replace properties of text from START to END.\n\ |
| @@ -618,7 +742,7 @@ is the string or buffer containing the text.") | |||
| 618 | { | 742 | { |
| 619 | unchanged = i; | 743 | unchanged = i; |
| 620 | i = split_interval_right (unchanged, s - unchanged->position + 1); | 744 | i = split_interval_right (unchanged, s - unchanged->position + 1); |
| 621 | set_properties (props, i); | 745 | set_properties (props, i, object); |
| 622 | 746 | ||
| 623 | if (LENGTH (i) > len) | 747 | if (LENGTH (i) > len) |
| 624 | { | 748 | { |
| @@ -638,13 +762,16 @@ is the string or buffer containing the text.") | |||
| 638 | /* We are starting at the beginning of an interval, I */ | 762 | /* We are starting at the beginning of an interval, I */ |
| 639 | while (len > 0) | 763 | while (len > 0) |
| 640 | { | 764 | { |
| 765 | if (i == 0) | ||
| 766 | abort (); | ||
| 767 | |||
| 641 | if (LENGTH (i) >= len) | 768 | if (LENGTH (i) >= len) |
| 642 | { | 769 | { |
| 643 | if (LENGTH (i) > len) | 770 | if (LENGTH (i) > len) |
| 644 | i = split_interval_left (i, len + 1); | 771 | i = split_interval_left (i, len + 1); |
| 645 | 772 | ||
| 646 | if (NULL_INTERVAL_P (prev_changed)) | 773 | if (NULL_INTERVAL_P (prev_changed)) |
| 647 | set_properties (props, i); | 774 | set_properties (props, i, object); |
| 648 | else | 775 | else |
| 649 | merge_interval_left (i); | 776 | merge_interval_left (i); |
| 650 | return Qt; | 777 | return Qt; |
| @@ -653,7 +780,7 @@ is the string or buffer containing the text.") | |||
| 653 | len -= LENGTH (i); | 780 | len -= LENGTH (i); |
| 654 | if (NULL_INTERVAL_P (prev_changed)) | 781 | if (NULL_INTERVAL_P (prev_changed)) |
| 655 | { | 782 | { |
| 656 | set_properties (props, i); | 783 | set_properties (props, i, object); |
| 657 | prev_changed = i; | 784 | prev_changed = i; |
| 658 | } | 785 | } |
| 659 | else | 786 | else |
| @@ -712,11 +839,11 @@ Return t if any property was actually removed, nil otherwise.") | |||
| 712 | { | 839 | { |
| 713 | i = split_interval_left (i, len + 1); | 840 | i = split_interval_left (i, len + 1); |
| 714 | copy_properties (unchanged, i); | 841 | copy_properties (unchanged, i); |
| 715 | remove_properties (props, i); | 842 | remove_properties (props, i, object); |
| 716 | return Qt; | 843 | return Qt; |
| 717 | } | 844 | } |
| 718 | 845 | ||
| 719 | remove_properties (props, i); | 846 | remove_properties (props, i, object); |
| 720 | modified = 1; | 847 | modified = 1; |
| 721 | len -= LENGTH (i); | 848 | len -= LENGTH (i); |
| 722 | i = next_interval (i); | 849 | i = next_interval (i); |
| @@ -724,8 +851,11 @@ Return t if any property was actually removed, nil otherwise.") | |||
| 724 | } | 851 | } |
| 725 | 852 | ||
| 726 | /* We are at the beginning of an interval, with len to scan */ | 853 | /* We are at the beginning of an interval, with len to scan */ |
| 727 | while (1) | 854 | while (len > 0) |
| 728 | { | 855 | { |
| 856 | if (i == 0) | ||
| 857 | abort (); | ||
| 858 | |||
| 729 | if (LENGTH (i) >= len) | 859 | if (LENGTH (i) >= len) |
| 730 | { | 860 | { |
| 731 | if (! interval_has_some_properties (props, i)) | 861 | if (! interval_has_some_properties (props, i)) |
| @@ -733,19 +863,19 @@ Return t if any property was actually removed, nil otherwise.") | |||
| 733 | 863 | ||
| 734 | if (LENGTH (i) == len) | 864 | if (LENGTH (i) == len) |
| 735 | { | 865 | { |
| 736 | remove_properties (props, i); | 866 | remove_properties (props, i, object); |
| 737 | return Qt; | 867 | return Qt; |
| 738 | } | 868 | } |
| 739 | 869 | ||
| 740 | /* i has the properties, and goes past the change limit */ | 870 | /* i has the properties, and goes past the change limit */ |
| 741 | unchanged = split_interval_right (i, len + 1); | 871 | unchanged = split_interval_right (i, len + 1); |
| 742 | copy_properties (unchanged, i); | 872 | copy_properties (unchanged, i); |
| 743 | remove_properties (props, i); | 873 | remove_properties (props, i, object); |
| 744 | return Qt; | 874 | return Qt; |
| 745 | } | 875 | } |
| 746 | 876 | ||
| 747 | len -= LENGTH (i); | 877 | len -= LENGTH (i); |
| 748 | modified += remove_properties (props, i); | 878 | modified += remove_properties (props, i, object); |
| 749 | i = next_interval (i); | 879 | i = next_interval (i); |
| 750 | } | 880 | } |
| 751 | } | 881 | } |
| @@ -903,6 +1033,7 @@ percentage by which the left interval tree should not differ from the right."); | |||
| 903 | defsubr (&Sprevious_property_change); | 1033 | defsubr (&Sprevious_property_change); |
| 904 | defsubr (&Sprevious_single_property_change); | 1034 | defsubr (&Sprevious_single_property_change); |
| 905 | defsubr (&Sadd_text_properties); | 1035 | defsubr (&Sadd_text_properties); |
| 1036 | defsubr (&Sput_text_property); | ||
| 906 | defsubr (&Sset_text_properties); | 1037 | defsubr (&Sset_text_properties); |
| 907 | defsubr (&Sremove_text_properties); | 1038 | defsubr (&Sremove_text_properties); |
| 908 | /* defsubr (&Serase_text_properties); */ | 1039 | /* defsubr (&Serase_text_properties); */ |