comparison src/textprop.c @ 17467:98c47e7857f3

Style of comments corrected. (interval_of): New function.
author Richard M. Stallman <rms@gnu.org>
date Tue, 15 Apr 1997 04:58:34 +0000
parents 38c158927e6f
children 614b916ff5bf
comparison
equal deleted inserted replaced
17466:c6ba5208968b 17467:98c47e7857f3
1 /* Interface code for dealing with text properties. 1 /* Interface code for dealing with text properties.
2 Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. 2 Copyright (C) 1993, 1994, 1995, 1997 Free Software Foundation, Inc.
3 3
4 This file is part of GNU Emacs. 4 This file is part of GNU Emacs.
5 5
6 GNU Emacs is free software; you can redistribute it and/or modify 6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by 7 it under the terms of the GNU General Public License as published by
42 42
43 It is assumed that for any interval plist, a property appears 43 It is assumed that for any interval plist, a property appears
44 only once on the list. Although some code i.e., remove_properties, 44 only once on the list. Although some code i.e., remove_properties,
45 handles the more general case, the uniqueness of properties is 45 handles the more general case, the uniqueness of properties is
46 necessary for the system to remain consistent. This requirement 46 necessary for the system to remain consistent. This requirement
47 is enforced by the subrs installing properties onto the intervals. */ 47 is enforced by the subrs installing properties onto the intervals. */
48 48
49 /* The rest of the file is within this conditional */ 49 /* The rest of the file is within this conditional */
50 #ifdef USE_TEXT_PROPERTIES 50 #ifdef USE_TEXT_PROPERTIES
51 51
52 /* Types of hooks. */ 52 /* Types of hooks. */
53 Lisp_Object Qmouse_left; 53 Lisp_Object Qmouse_left;
54 Lisp_Object Qmouse_entered; 54 Lisp_Object Qmouse_entered;
55 Lisp_Object Qpoint_left; 55 Lisp_Object Qpoint_left;
56 Lisp_Object Qpoint_entered; 56 Lisp_Object Qpoint_entered;
57 Lisp_Object Qcategory; 57 Lisp_Object Qcategory;
58 Lisp_Object Qlocal_map; 58 Lisp_Object Qlocal_map;
59 59
60 /* Visual properties text (including strings) may have. */ 60 /* Visual properties text (including strings) may have. */
61 Lisp_Object Qforeground, Qbackground, Qfont, Qunderline, Qstipple; 61 Lisp_Object Qforeground, Qbackground, Qfont, Qunderline, Qstipple;
62 Lisp_Object Qinvisible, Qread_only, Qintangible; 62 Lisp_Object Qinvisible, Qread_only, Qintangible;
63 63
64 /* Sticky properties */ 64 /* Sticky properties */
65 Lisp_Object Qfront_sticky, Qrear_nonsticky; 65 Lisp_Object Qfront_sticky, Qrear_nonsticky;
114 CHECK_STRING_OR_BUFFER (object, 0); 114 CHECK_STRING_OR_BUFFER (object, 0);
115 CHECK_NUMBER_COERCE_MARKER (*begin, 0); 115 CHECK_NUMBER_COERCE_MARKER (*begin, 0);
116 CHECK_NUMBER_COERCE_MARKER (*end, 0); 116 CHECK_NUMBER_COERCE_MARKER (*end, 0);
117 117
118 /* If we are asked for a point, but from a subr which operates 118 /* If we are asked for a point, but from a subr which operates
119 on a range, then return nothing. */ 119 on a range, then return nothing. */
120 if (EQ (*begin, *end) && begin != end) 120 if (EQ (*begin, *end) && begin != end)
121 return NULL_INTERVAL; 121 return NULL_INTERVAL;
122 122
123 if (XINT (*begin) > XINT (*end)) 123 if (XINT (*begin) > XINT (*end))
124 { 124 {
135 if (!(BUF_BEGV (b) <= XINT (*begin) && XINT (*begin) <= XINT (*end) 135 if (!(BUF_BEGV (b) <= XINT (*begin) && XINT (*begin) <= XINT (*end)
136 && XINT (*end) <= BUF_ZV (b))) 136 && XINT (*end) <= BUF_ZV (b)))
137 args_out_of_range (*begin, *end); 137 args_out_of_range (*begin, *end);
138 i = BUF_INTERVALS (b); 138 i = BUF_INTERVALS (b);
139 139
140 /* If there's no text, there are no properties. */ 140 /* If there's no text, there are no properties. */
141 if (BUF_BEGV (b) == BUF_ZV (b)) 141 if (BUF_BEGV (b) == BUF_ZV (b))
142 return NULL_INTERVAL; 142 return NULL_INTERVAL;
143 143
144 searchpos = XINT (*begin); 144 searchpos = XINT (*begin);
145 } 145 }
169 return find_interval (i, searchpos); 169 return find_interval (i, searchpos);
170 } 170 }
171 171
172 /* Validate LIST as a property list. If LIST is not a list, then 172 /* Validate LIST as a property list. If LIST is not a list, then
173 make one consisting of (LIST nil). Otherwise, verify that LIST 173 make one consisting of (LIST nil). Otherwise, verify that LIST
174 is even numbered and thus suitable as a plist. */ 174 is even numbered and thus suitable as a plist. */
175 175
176 static Lisp_Object 176 static Lisp_Object
177 validate_plist (list) 177 validate_plist (list)
178 Lisp_Object list; 178 Lisp_Object list;
179 { 179 {
196 196
197 return Fcons (list, Fcons (Qnil, Qnil)); 197 return Fcons (list, Fcons (Qnil, Qnil));
198 } 198 }
199 199
200 /* Return nonzero if interval I has all the properties, 200 /* Return nonzero if interval I has all the properties,
201 with the same values, of list PLIST. */ 201 with the same values, of list PLIST. */
202 202
203 static int 203 static int
204 interval_has_all_properties (plist, i) 204 interval_has_all_properties (plist, i)
205 Lisp_Object plist; 205 Lisp_Object plist;
206 INTERVAL i; 206 INTERVAL i;
207 { 207 {
208 register Lisp_Object tail1, tail2, sym1, sym2; 208 register Lisp_Object tail1, tail2, sym1, sym2;
209 register int found; 209 register int found;
210 210
211 /* Go through each element of PLIST. */ 211 /* Go through each element of PLIST. */
212 for (tail1 = plist; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1))) 212 for (tail1 = plist; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1)))
213 { 213 {
214 sym1 = Fcar (tail1); 214 sym1 = Fcar (tail1);
215 found = 0; 215 found = 0;
216 216
217 /* Go through I's plist, looking for sym1 */ 217 /* Go through I's plist, looking for sym1 */
218 for (tail2 = i->plist; ! NILP (tail2); tail2 = Fcdr (Fcdr (tail2))) 218 for (tail2 = i->plist; ! NILP (tail2); tail2 = Fcdr (Fcdr (tail2)))
219 if (EQ (sym1, Fcar (tail2))) 219 if (EQ (sym1, Fcar (tail2)))
220 { 220 {
221 /* Found the same property on both lists. If the 221 /* Found the same property on both lists. If the
222 values are unequal, return zero. */ 222 values are unequal, return zero. */
223 if (! EQ (Fcar (Fcdr (tail1)), Fcar (Fcdr (tail2)))) 223 if (! EQ (Fcar (Fcdr (tail1)), Fcar (Fcdr (tail2))))
224 return 0; 224 return 0;
225 225
226 /* Property has same value on both lists; go to next one. */ 226 /* Property has same value on both lists; go to next one. */
227 found = 1; 227 found = 1;
228 break; 228 break;
229 } 229 }
230 230
231 if (! found) 231 if (! found)
234 234
235 return 1; 235 return 1;
236 } 236 }
237 237
238 /* Return nonzero if the plist of interval I has any of the 238 /* Return nonzero if the plist of interval I has any of the
239 properties of PLIST, regardless of their values. */ 239 properties of PLIST, regardless of their values. */
240 240
241 static INLINE int 241 static INLINE int
242 interval_has_some_properties (plist, i) 242 interval_has_some_properties (plist, i)
243 Lisp_Object plist; 243 Lisp_Object plist;
244 INTERVAL i; 244 INTERVAL i;
245 { 245 {
246 register Lisp_Object tail1, tail2, sym; 246 register Lisp_Object tail1, tail2, sym;
247 247
248 /* Go through each element of PLIST. */ 248 /* Go through each element of PLIST. */
249 for (tail1 = plist; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1))) 249 for (tail1 = plist; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1)))
250 { 250 {
251 sym = Fcar (tail1); 251 sym = Fcar (tail1);
252 252
253 /* Go through i's plist, looking for tail1 */ 253 /* Go through i's plist, looking for tail1 */
347 /* No need to protect OBJECT, because we can GC only in the case 347 /* No need to protect OBJECT, because we can GC only in the case
348 where it is a buffer, and live buffers are always protected. 348 where it is a buffer, and live buffers are always protected.
349 I and its plist are also protected, via OBJECT. */ 349 I and its plist are also protected, via OBJECT. */
350 GCPRO3 (tail1, sym1, val1); 350 GCPRO3 (tail1, sym1, val1);
351 351
352 /* Go through each element of PLIST. */ 352 /* Go through each element of PLIST. */
353 for (tail1 = plist; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1))) 353 for (tail1 = plist; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1)))
354 { 354 {
355 sym1 = Fcar (tail1); 355 sym1 = Fcar (tail1);
356 val1 = Fcar (Fcdr (tail1)); 356 val1 = Fcar (Fcdr (tail1));
357 found = 0; 357 found = 0;
363 /* No need to gcpro, because tail2 protects this 363 /* No need to gcpro, because tail2 protects this
364 and it must be a cons cell (we get an error otherwise). */ 364 and it must be a cons cell (we get an error otherwise). */
365 register Lisp_Object this_cdr; 365 register Lisp_Object this_cdr;
366 366
367 this_cdr = Fcdr (tail2); 367 this_cdr = Fcdr (tail2);
368 /* Found the property. Now check its value. */ 368 /* Found the property. Now check its value. */
369 found = 1; 369 found = 1;
370 370
371 /* The properties have the same value on both lists. 371 /* The properties have the same value on both lists.
372 Continue to the next property. */ 372 Continue to the next property. */
373 if (EQ (val1, Fcar (this_cdr))) 373 if (EQ (val1, Fcar (this_cdr)))
374 break; 374 break;
375 375
376 /* Record this change in the buffer, for undo purposes. */ 376 /* Record this change in the buffer, for undo purposes. */
377 if (BUFFERP (object)) 377 if (BUFFERP (object))
416 { 416 {
417 register Lisp_Object tail1, tail2, sym, current_plist; 417 register Lisp_Object tail1, tail2, sym, current_plist;
418 register int changed = 0; 418 register int changed = 0;
419 419
420 current_plist = i->plist; 420 current_plist = i->plist;
421 /* Go through each element of plist. */ 421 /* Go through each element of plist. */
422 for (tail1 = plist; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1))) 422 for (tail1 = plist; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1)))
423 { 423 {
424 sym = Fcar (tail1); 424 sym = Fcar (tail1);
425 425
426 /* First, remove the symbol if its at the head of the list */ 426 /* First, remove the symbol if its at the head of the list */
463 return changed; 463 return changed;
464 } 464 }
465 465
466 #if 0 466 #if 0
467 /* Remove all properties from interval I. Return non-zero 467 /* Remove all properties from interval I. Return non-zero
468 if this changes the interval. */ 468 if this changes the interval. */
469 469
470 static INLINE int 470 static INLINE int
471 erase_properties (i) 471 erase_properties (i)
472 INTERVAL i; 472 INTERVAL i;
473 { 473 {
476 476
477 i->plist = Qnil; 477 i->plist = Qnil;
478 return 1; 478 return 1;
479 } 479 }
480 #endif 480 #endif
481
482 /* Returns the interval of the POSITION in OBJECT.
483 POSITION is BEG-based. */
484
485 INTERVAL
486 interval_of (position, object)
487 int position;
488 Lisp_Object object;
489 {
490 register INTERVAL i;
491 int beg, end;
492
493 if (NILP (object))
494 XSETBUFFER (object, current_buffer);
495
496 CHECK_STRING_OR_BUFFER (object, 0);
497
498 if (BUFFERP (object))
499 {
500 register struct buffer *b = XBUFFER (object);
501
502 beg = BUF_BEGV (b);
503 end = BUF_ZV (b);
504 i = BUF_INTERVALS (b);
505 }
506 else
507 {
508 register struct Lisp_String *s = XSTRING (object);
509
510 /* We expect position to be 1-based. */
511 beg = BEG;
512 end = s->size + BEG;
513 i = s->intervals;
514 }
515
516 if (!(beg <= position && position <= end))
517 args_out_of_range (position, position);
518 if (beg == end || NULL_INTERVAL_P (i))
519 return NULL_INTERVAL;
520
521 return find_interval (i, position);
522 }
481 523
482 DEFUN ("text-properties-at", Ftext_properties_at, 524 DEFUN ("text-properties-at", Ftext_properties_at,
483 Stext_properties_at, 1, 2, 0, 525 Stext_properties_at, 1, 2, 0,
484 "Return the list of properties held by the character at POSITION\n\ 526 "Return the list of properties held by the character at POSITION\n\
485 in optional argument OBJECT, a string or buffer. If nil, OBJECT\n\ 527 in optional argument OBJECT, a string or buffer. If nil, OBJECT\n\
898 /* No need to protect OBJECT, because we GC only if it's a buffer, 940 /* No need to protect OBJECT, because we GC only if it's a buffer,
899 and live buffers are always protected. */ 941 and live buffers are always protected. */
900 GCPRO1 (properties); 942 GCPRO1 (properties);
901 943
902 /* If we're not starting on an interval boundary, we have to 944 /* If we're not starting on an interval boundary, we have to
903 split this interval. */ 945 split this interval. */
904 if (i->position != s) 946 if (i->position != s)
905 { 947 {
906 /* If this interval already has the properties, we can 948 /* If this interval already has the properties, we can
907 skip it. */ 949 skip it. */
908 if (interval_has_all_properties (properties, i)) 950 if (interval_has_all_properties (properties, i))
909 { 951 {
910 int got = (LENGTH (i) - (s - i->position)); 952 int got = (LENGTH (i) - (s - i->position));
911 if (got >= len) 953 if (got >= len)
912 RETURN_UNGCPRO (Qnil); 954 RETURN_UNGCPRO (Qnil);
1153 len = XINT (end) - s; 1195 len = XINT (end) - s;
1154 1196
1155 if (i->position != s) 1197 if (i->position != s)
1156 { 1198 {
1157 /* No properties on this first interval -- return if 1199 /* No properties on this first interval -- return if
1158 it covers the entire region. */ 1200 it covers the entire region. */
1159 if (! interval_has_some_properties (properties, i)) 1201 if (! interval_has_some_properties (properties, i))
1160 { 1202 {
1161 int got = (LENGTH (i) - (s - i->position)); 1203 int got = (LENGTH (i) - (s - i->position));
1162 if (got >= len) 1204 if (got >= len)
1163 return Qnil; 1205 return Qnil;
1313 if (i->position != s) 1355 if (i->position != s)
1314 { 1356 {
1315 register int got; 1357 register int got;
1316 register INTERVAL unchanged = i; 1358 register INTERVAL unchanged = i;
1317 1359
1318 /* If there are properties here, then this text will be modified. */ 1360 /* If there are properties here, then this text will be modified. */
1319 if (! NILP (i->plist)) 1361 if (! NILP (i->plist))
1320 { 1362 {
1321 i = split_interval_right (unchanged, s - unchanged->position); 1363 i = split_interval_right (unchanged, s - unchanged->position);
1322 i->plist = Qnil; 1364 i->plist = Qnil;
1323 modified++; 1365 modified++;
1338 LEN or more characters, then we may return without changing 1380 LEN or more characters, then we may return without changing
1339 anything.*/ 1381 anything.*/
1340 else if (LENGTH (i) - (s - i->position) <= len) 1382 else if (LENGTH (i) - (s - i->position) <= len)
1341 return Qnil; 1383 return Qnil;
1342 /* The amount of text to change extends past I, so just note 1384 /* The amount of text to change extends past I, so just note
1343 how much we've gotten. */ 1385 how much we've gotten. */
1344 else 1386 else
1345 got = LENGTH (i) - (s - i->position); 1387 got = LENGTH (i) - (s - i->position);
1346 1388
1347 len -= got; 1389 len -= got;
1348 prev_changed = i; 1390 prev_changed = i;
1349 i = next_interval (i); 1391 i = next_interval (i);
1350 } 1392 }
1351 1393
1352 /* We are starting at the beginning of an interval, I. */ 1394 /* We are starting at the beginning of an interval, I. */
1353 while (len > 0) 1395 while (len > 0)
1354 { 1396 {
1355 if (LENGTH (i) >= len) 1397 if (LENGTH (i) >= len)
1356 { 1398 {
1357 /* If I has no properties, simply merge it if possible. */ 1399 /* If I has no properties, simply merge it if possible. */
1381 prev_changed = i; 1423 prev_changed = i;
1382 } 1424 }
1383 else 1425 else
1384 { 1426 {
1385 modified += ! NILP (i->plist); 1427 modified += ! NILP (i->plist);
1386 /* Merging I will give it the properties of PREV_CHANGED. */ 1428 /* Merging I will give it the properties of PREV_CHANGED. */
1387 prev_changed = i = merge_interval_left (i); 1429 prev_changed = i = merge_interval_left (i);
1388 } 1430 }
1389 1431
1390 i = next_interval (i); 1432 i = next_interval (i);
1391 } 1433 }
1461 plist = Fcdr (Fcdr (plist)); 1503 plist = Fcdr (Fcdr (plist));
1462 } 1504 }
1463 if (! NILP (plist)) 1505 if (! NILP (plist))
1464 { 1506 {
1465 /* Must defer modifications to the interval tree in case src 1507 /* Must defer modifications to the interval tree in case src
1466 and dest refer to the same string or buffer. */ 1508 and dest refer to the same string or buffer. */
1467 stuff = Fcons (Fcons (make_number (p), 1509 stuff = Fcons (Fcons (make_number (p),
1468 Fcons (make_number (p + len), 1510 Fcons (make_number (p + len),
1469 Fcons (plist, Qnil))), 1511 Fcons (plist, Qnil))),
1470 stuff); 1512 stuff);
1471 } 1513 }
1570 /* If Vinhibit_read_only is set and is not a list, we can 1612 /* If Vinhibit_read_only is set and is not a list, we can
1571 skip the read_only checks. */ 1613 skip the read_only checks. */
1572 if (NILP (Vinhibit_read_only) || CONSP (Vinhibit_read_only)) 1614 if (NILP (Vinhibit_read_only) || CONSP (Vinhibit_read_only))
1573 { 1615 {
1574 /* If I and PREV differ we need to check for the read-only 1616 /* If I and PREV differ we need to check for the read-only
1575 property together with its stickiness. If either I or 1617 property together with its stickiness. If either I or
1576 PREV are 0, this check is all we need. 1618 PREV are 0, this check is all we need.
1577 We have to take special care, since read-only may be 1619 We have to take special care, since read-only may be
1578 indirectly defined via the category property. */ 1620 indirectly defined via the category property. */
1579 if (i != prev) 1621 if (i != prev)
1580 { 1622 {