Mercurial > emacs
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 { |