Mercurial > emacs
comparison src/textprop.c @ 1029:425f62908a54
Initial revision
author | Joseph Arceneaux <jla@gnu.org> |
---|---|
date | Fri, 21 Aug 1992 23:45:45 +0000 |
parents | |
children | 7eb43ab890e0 |
comparison
equal
deleted
inserted
replaced
1028:508bb8dd1e88 | 1029:425f62908a54 |
---|---|
1 /* Interface code for dealing with text properties. | |
2 Copyright (C) 1992 Free Software Foundation, Inc. | |
3 | |
4 This file is part of GNU Emacs. | |
5 | |
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 | |
8 the Free Software Foundation; either version 1, or (at your option) | |
9 any later version. | |
10 | |
11 GNU Emacs is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with GNU Emacs; see the file COPYING. If not, write to | |
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | |
20 #include "config.h" | |
21 #include "lisp.h" | |
22 #include "intervals.h" | |
23 #include "buffer.h" | |
24 | |
25 | |
26 /* NOTES: previous- and next- property change will have to skip | |
27 zero-length intervals if they are implemented. This could be done | |
28 inside next_interval and previous_interval. | |
29 | |
30 It is assumed that for any interval plist, a property appears | |
31 only once on the list. Although some code i.e., remove_properties (), | |
32 handles the more general case, the uniqueness of properties is | |
33 neccessary for the system to remain consistent. This requirement | |
34 is enforced by the subrs installing properties onto the intervals. */ | |
35 | |
36 | |
37 /* Types of hooks. */ | |
38 Lisp_Object Qmouse_left; | |
39 Lisp_Object Qmouse_entered; | |
40 Lisp_Object Qpoint_left; | |
41 Lisp_Object Qpoint_entered; | |
42 Lisp_Object Qmodification; | |
43 | |
44 /* Visual properties text (including strings) may have. */ | |
45 Lisp_Object Qforeground, Qbackground, Qfont, Qunderline, Qstipple; | |
46 Lisp_Object Qinvisible, Qread_only; | |
47 | |
48 /* Extract the interval at position BEGIN from OBJECT, a string | |
49 or buffer. Additionally, check that BEGIN and END are within | |
50 the bounds of OBJECT. | |
51 | |
52 Note that buffer points don't correspond to interval indices. | |
53 For example, point-max is 1 greater than the index of the last | |
54 character. This difference is handled in the caller, which uses | |
55 the validated points to determine a length, and operates on that. | |
56 Exceptions are Ftext_properties_at, Fnext_property_change, and | |
57 Fprevious_property_change which call this function with BEGIN == END. | |
58 Handle this case specially. | |
59 | |
60 If FORCE is soft (0), it's OK to return NULL_INTERVAL. Otherwise, | |
61 create an interval tree for OBJECT if one doesn't exist. */ | |
62 | |
63 #define soft 0 | |
64 #define hard 1 | |
65 | |
66 static INTERVAL | |
67 validate_interval_range (object, begin, end, force) | |
68 Lisp_Object object, *begin, *end; | |
69 int force; | |
70 { | |
71 register INTERVAL i; | |
72 CHECK_STRING_OR_BUFFER (object, 0); | |
73 CHECK_NUMBER_COERCE_MARKER (*begin, 0); | |
74 CHECK_NUMBER_COERCE_MARKER (*end, 0); | |
75 | |
76 /* If we are asked for a point, but from a subr which operates | |
77 on a range, then return nothing. */ | |
78 if (*begin == *end && begin != end) | |
79 return NULL_INTERVAL; | |
80 | |
81 if (XINT (*begin) > XINT (*end)) | |
82 { | |
83 register int n; | |
84 n = XFASTINT (*begin); /* This is legit even if *begin is < 0 */ | |
85 *begin = *end; | |
86 XFASTINT (*end) = n; /* because this is all we do with n. */ | |
87 } | |
88 | |
89 if (XTYPE (object) == Lisp_Buffer) | |
90 { | |
91 register struct buffer *b = XBUFFER (object); | |
92 | |
93 /* If there's no text, there are no properties. */ | |
94 if (BUF_BEGV (b) == BUF_ZV (b)) | |
95 return NULL_INTERVAL; | |
96 | |
97 if (!(BUF_BEGV (b) <= XINT (*begin) && XINT (*begin) <= XINT (*end) | |
98 && XINT (*end) <= BUF_ZV (b))) | |
99 args_out_of_range (*begin, *end); | |
100 i = b->intervals; | |
101 | |
102 /* Special case for point-max: return the interval for the | |
103 last character. */ | |
104 if (*begin == *end && *begin == BUF_Z (b)) | |
105 *begin -= 1; | |
106 } | |
107 else | |
108 { | |
109 register struct Lisp_String *s = XSTRING (object); | |
110 | |
111 if (! (1 <= XINT (*begin) && XINT (*begin) <= XINT (*end) | |
112 && XINT (*end) <= s->size)) | |
113 args_out_of_range (*begin, *end); | |
114 i = s->intervals; | |
115 } | |
116 | |
117 if (NULL_INTERVAL_P (i)) | |
118 return (force ? create_root_interval (object) : i); | |
119 | |
120 return find_interval (i, XINT (*begin)); | |
121 } | |
122 | |
123 /* Validate LIST as a property list. If LIST is not a list, then | |
124 make one consisting of (LIST nil). Otherwise, verify that LIST | |
125 is even numbered and thus suitable as a plist. */ | |
126 | |
127 static Lisp_Object | |
128 validate_plist (list) | |
129 { | |
130 if (NILP (list)) | |
131 return Qnil; | |
132 | |
133 if (CONSP (list)) | |
134 { | |
135 register int i; | |
136 register Lisp_Object tail; | |
137 for (i = 0, tail = list; !NILP (tail); i++) | |
138 tail = Fcdr (tail); | |
139 if (i & 1) | |
140 error ("Odd length text property list"); | |
141 return list; | |
142 } | |
143 | |
144 return Fcons (list, Fcons (Qnil, Qnil)); | |
145 } | |
146 | |
147 #define set_properties(list,i) (i->plist = Fcopy_sequence (list)) | |
148 | |
149 /* Return nonzero if interval I has all the properties, | |
150 with the same values, of list PLIST. */ | |
151 | |
152 static int | |
153 interval_has_all_properties (plist, i) | |
154 Lisp_Object plist; | |
155 INTERVAL i; | |
156 { | |
157 register Lisp_Object tail1, tail2, sym1, sym2; | |
158 register int found; | |
159 | |
160 /* Go through each element of PLIST. */ | |
161 for (tail1 = plist; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1))) | |
162 { | |
163 sym1 = Fcar (tail1); | |
164 found = 0; | |
165 | |
166 /* Go through I's plist, looking for sym1 */ | |
167 for (tail2 = i->plist; ! NILP (tail2); tail2 = Fcdr (Fcdr (tail2))) | |
168 if (EQ (sym1, Fcar (tail2))) | |
169 { | |
170 /* Found the same property on both lists. If the | |
171 values are unequal, return zero. */ | |
172 if (! EQ (Fequal (Fcar (Fcdr (tail1)), Fcar (Fcdr (tail2))), | |
173 Qt)) | |
174 return 0; | |
175 | |
176 /* Property has same value on both lists; go to next one. */ | |
177 found = 1; | |
178 break; | |
179 } | |
180 | |
181 if (! found) | |
182 return 0; | |
183 } | |
184 | |
185 return 1; | |
186 } | |
187 | |
188 /* Return nonzero if the plist of interval I has any of the | |
189 properties of PLIST, regardless of their values. */ | |
190 | |
191 static INLINE int | |
192 interval_has_some_properties (plist, i) | |
193 Lisp_Object plist; | |
194 INTERVAL i; | |
195 { | |
196 register Lisp_Object tail1, tail2, sym; | |
197 | |
198 /* Go through each element of PLIST. */ | |
199 for (tail1 = plist; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1))) | |
200 { | |
201 sym = Fcar (tail1); | |
202 | |
203 /* Go through i's plist, looking for tail1 */ | |
204 for (tail2 = i->plist; ! NILP (tail2); tail2 = Fcdr (Fcdr (tail2))) | |
205 if (EQ (sym, Fcar (tail2))) | |
206 return 1; | |
207 } | |
208 | |
209 return 0; | |
210 } | |
211 | |
212 /* Add the properties of PLIST to the interval I, or set | |
213 the value of I's property to the value of the property on PLIST | |
214 if they are different. | |
215 | |
216 Return nonzero if this changes I (i.e., if any members of PLIST | |
217 are actually added to I's plist) */ | |
218 | |
219 static INLINE int | |
220 add_properties (plist, i) | |
221 Lisp_Object plist; | |
222 INTERVAL i; | |
223 { | |
224 register Lisp_Object tail1, tail2, sym1, val1; | |
225 register int changed = 0; | |
226 register int found; | |
227 | |
228 /* Go through each element of PLIST. */ | |
229 for (tail1 = plist; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1))) | |
230 { | |
231 sym1 = Fcar (tail1); | |
232 val1 = Fcar (Fcdr (tail1)); | |
233 found = 0; | |
234 | |
235 /* Go through I's plist, looking for sym1 */ | |
236 for (tail2 = i->plist; ! NILP (tail2); tail2 = Fcdr (Fcdr (tail2))) | |
237 if (EQ (sym1, Fcar (tail2))) | |
238 { | |
239 register Lisp_Object this_cdr = Fcdr (tail2); | |
240 | |
241 /* Found the property. Now check its value. */ | |
242 found = 1; | |
243 | |
244 /* The properties have the same value on both lists. | |
245 Continue to the next property. */ | |
246 if (Fequal (val1, Fcar (this_cdr))) | |
247 break; | |
248 | |
249 /* I's property has a different value -- change it */ | |
250 Fsetcar (this_cdr, val1); | |
251 changed++; | |
252 break; | |
253 } | |
254 | |
255 if (! found) | |
256 { | |
257 i->plist = Fcons (sym1, Fcons (val1, i->plist)); | |
258 changed++; | |
259 } | |
260 } | |
261 | |
262 return changed; | |
263 } | |
264 | |
265 /* For any members of PLIST which are properties of I, remove them | |
266 from I's plist. */ | |
267 | |
268 static INLINE int | |
269 remove_properties (plist, i) | |
270 Lisp_Object plist; | |
271 INTERVAL i; | |
272 { | |
273 register Lisp_Object tail1, tail2, sym; | |
274 register Lisp_Object current_plist = i->plist; | |
275 register int changed = 0; | |
276 | |
277 /* Go through each element of plist. */ | |
278 for (tail1 = plist; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1))) | |
279 { | |
280 sym = Fcar (tail1); | |
281 | |
282 /* First, remove the symbol if its at the head of the list */ | |
283 while (! NILP (current_plist) && EQ (sym, Fcar (current_plist))) | |
284 { | |
285 current_plist = Fcdr (Fcdr (current_plist)); | |
286 changed++; | |
287 } | |
288 | |
289 /* Go through i's plist, looking for sym */ | |
290 tail2 = current_plist; | |
291 while (! NILP (tail2)) | |
292 { | |
293 register Lisp_Object this = Fcdr (Fcdr (tail2)); | |
294 if (EQ (sym, Fcar (this))) | |
295 { | |
296 Fsetcdr (Fcdr (tail2), Fcdr (Fcdr (this))); | |
297 changed++; | |
298 } | |
299 tail2 = this; | |
300 } | |
301 } | |
302 | |
303 if (changed) | |
304 i->plist = current_plist; | |
305 return changed; | |
306 } | |
307 | |
308 /* Remove all properties from interval I. Return non-zero | |
309 if this changes the interval. */ | |
310 | |
311 static INLINE int | |
312 erase_properties (i) | |
313 INTERVAL i; | |
314 { | |
315 if (NILP (i->plist)) | |
316 return 0; | |
317 | |
318 i->plist = Qnil; | |
319 return 1; | |
320 } | |
321 | |
322 | |
323 DEFUN ("text-properties-at", Ftext_properties_at, | |
324 Stext_properties_at, 1, 2, 0, | |
325 "Return the list of properties held by the character at POSITION\n\ | |
326 in optional argument OBJECT, a string or buffer. If nil, OBJECT\n\ | |
327 defaults to the current buffer.") | |
328 (pos, object) | |
329 Lisp_Object pos, object; | |
330 { | |
331 register INTERVAL i; | |
332 register int p; | |
333 | |
334 if (NILP (object)) | |
335 XSET (object, Lisp_Buffer, current_buffer); | |
336 | |
337 i = validate_interval_range (object, &pos, &pos, soft); | |
338 if (NULL_INTERVAL_P (i)) | |
339 return Qnil; | |
340 | |
341 return i->plist; | |
342 } | |
343 | |
344 DEFUN ("next-property-change", Fnext_property_change, | |
345 Snext_property_change, 2, 2, 0, | |
346 "Return the position after POSITION in OBJECT which has properties\n\ | |
347 different from those at POSITION. OBJECT may be a string or buffer.\n\ | |
348 Returns nil if unsuccessful.") | |
349 (pos, object) | |
350 Lisp_Object pos, object; | |
351 { | |
352 register INTERVAL i, next; | |
353 | |
354 i = validate_interval_range (object, &pos, &pos, soft); | |
355 if (NULL_INTERVAL_P (i)) | |
356 return Qnil; | |
357 | |
358 next = next_interval (i); | |
359 while (! NULL_INTERVAL_P (next) && intervals_equal (i, next)) | |
360 next = next_interval (next); | |
361 | |
362 if (NULL_INTERVAL_P (next)) | |
363 return Qnil; | |
364 | |
365 return next->position; | |
366 } | |
367 | |
368 DEFUN ("previous-property-change", Fprevious_property_change, | |
369 Sprevious_property_change, 2, 2, 0, | |
370 "Return the position before POSITION in OBJECT which has properties\n\ | |
371 different from those at POSITION. OBJECT may be a string or buffer.\n\ | |
372 Returns nil if unsuccessful.") | |
373 (pos, object) | |
374 Lisp_Object pos, object; | |
375 { | |
376 register INTERVAL i, previous; | |
377 | |
378 i = validate_interval_range (object, &pos, &pos, soft); | |
379 if (NULL_INTERVAL_P (i)) | |
380 return Qnil; | |
381 | |
382 previous = previous_interval (i); | |
383 while (! NULL_INTERVAL_P (previous) && intervals_equal (previous, i)) | |
384 previous = previous_interval (previous); | |
385 if (NULL_INTERVAL_P (previous)) | |
386 return Qnil; | |
387 | |
388 return previous->position + LENGTH (previous) - 1; | |
389 } | |
390 | |
391 DEFUN ("add-text-properties", Fadd_text_properties, | |
392 Sadd_text_properties, 4, 4, 0, | |
393 "Add the PROPERTIES (a property list) to the text of OBJECT\n\ | |
394 (a string or buffer) in the range START to END. Returns t if any change\n\ | |
395 was made, nil otherwise.") | |
396 (object, start, end, properties) | |
397 Lisp_Object object, start, end, properties; | |
398 { | |
399 register INTERVAL i, unchanged; | |
400 register int s, len, modified; | |
401 | |
402 properties = validate_plist (properties); | |
403 if (NILP (properties)) | |
404 return Qnil; | |
405 | |
406 i = validate_interval_range (object, &start, &end, hard); | |
407 if (NULL_INTERVAL_P (i)) | |
408 return Qnil; | |
409 | |
410 s = XINT (start); | |
411 len = XINT (end) - s; | |
412 | |
413 /* If we're not starting on an interval boundary, we have to | |
414 split this interval. */ | |
415 if (i->position != s) | |
416 { | |
417 /* If this interval already has the properties, we can | |
418 skip it. */ | |
419 if (interval_has_all_properties (properties, i)) | |
420 { | |
421 int got = (LENGTH (i) - (s - i->position)); | |
422 if (got >= len) | |
423 return Qnil; | |
424 len -= got; | |
425 } | |
426 else | |
427 { | |
428 unchanged = i; | |
429 i = split_interval_right (unchanged, s - unchanged->position + 1); | |
430 copy_properties (unchanged, i); | |
431 if (LENGTH (i) > len) | |
432 { | |
433 i = split_interval_left (i, len + 1); | |
434 copy_properties (unchanged, i); | |
435 add_properties (properties, i); | |
436 return Qt; | |
437 } | |
438 | |
439 add_properties (properties, i); | |
440 modified = 1; | |
441 len -= LENGTH (i); | |
442 i = next_interval (i); | |
443 } | |
444 } | |
445 | |
446 /* We are at the beginning of an interval, with len to scan */ | |
447 while (1) | |
448 { | |
449 if (LENGTH (i) >= len) | |
450 { | |
451 if (interval_has_all_properties (properties, i)) | |
452 return modified ? Qt : Qnil; | |
453 | |
454 if (LENGTH (i) == len) | |
455 { | |
456 add_properties (properties, i); | |
457 return Qt; | |
458 } | |
459 | |
460 /* i doesn't have the properties, and goes past the change limit */ | |
461 unchanged = i; | |
462 i = split_interval_left (unchanged, len + 1); | |
463 copy_properties (unchanged, i); | |
464 add_properties (properties, i); | |
465 return Qt; | |
466 } | |
467 | |
468 len -= LENGTH (i); | |
469 modified += add_properties (properties, i); | |
470 i = next_interval (i); | |
471 } | |
472 } | |
473 | |
474 DEFUN ("set-text-properties", Fset_text_properties, | |
475 Sset_text_properties, 4, 4, 0, | |
476 "Make the text of OBJECT (a string or buffer) have precisely\n\ | |
477 PROPERTIES (a list of properties) in the range START to END.\n\ | |
478 \n\ | |
479 If called with a valid property list, return t (text was changed).\n\ | |
480 Otherwise return nil.") | |
481 (object, start, end, properties) | |
482 Lisp_Object object, start, end, properties; | |
483 { | |
484 register INTERVAL i, unchanged; | |
485 register int s, len; | |
486 | |
487 properties = validate_plist (properties); | |
488 if (NILP (properties)) | |
489 return Qnil; | |
490 | |
491 i = validate_interval_range (object, &start, &end, hard); | |
492 if (NULL_INTERVAL_P (i)) | |
493 return Qnil; | |
494 | |
495 s = XINT (start); | |
496 len = XINT (end) - s; | |
497 | |
498 if (i->position != s) | |
499 { | |
500 unchanged = i; | |
501 i = split_interval_right (unchanged, s - unchanged->position + 1); | |
502 copy_properties (unchanged, i); | |
503 if (LENGTH (i) > len) | |
504 { | |
505 i = split_interval_left (i, len); | |
506 set_properties (properties, i); | |
507 return Qt; | |
508 } | |
509 | |
510 set_properties (properties, i); | |
511 len -= LENGTH (i); | |
512 i = next_interval (i); | |
513 } | |
514 | |
515 while (1) | |
516 { | |
517 if (LENGTH (i) >= len) | |
518 { | |
519 if (LENGTH (i) == len) | |
520 { | |
521 set_properties (properties, i); | |
522 return Qt; | |
523 } | |
524 | |
525 i = split_interval_left (i, len + 1); | |
526 set_properties (properties, i); | |
527 return Qt; | |
528 } | |
529 | |
530 len -= LENGTH (i); | |
531 set_properties (properties, i); | |
532 i = next_interval (i); | |
533 } | |
534 | |
535 return Qt; | |
536 } | |
537 | |
538 DEFUN ("remove-text-properties", Fremove_text_properties, | |
539 Sremove_text_properties, 4, 4, 0, | |
540 "Remove the PROPERTIES (a property list) from the text of OBJECT\n\ | |
541 (a string or buffer) in the range START to END. Returns t if any change\n\ | |
542 was made, nil otherwise.") | |
543 (object, start, end, properties) | |
544 Lisp_Object object, start, end, properties; | |
545 { | |
546 register INTERVAL i, unchanged; | |
547 register int s, len, modified; | |
548 | |
549 i = validate_interval_range (object, &start, &end, soft); | |
550 if (NULL_INTERVAL_P (i)) | |
551 return Qnil; | |
552 | |
553 s = XINT (start); | |
554 len = XINT (end) - s; | |
555 if (i->position != s) | |
556 { | |
557 /* No properties on this first interval -- return if | |
558 it covers the entire region. */ | |
559 if (! interval_has_some_properties (properties, i)) | |
560 { | |
561 int got = (LENGTH (i) - (s - i->position)); | |
562 if (got >= len) | |
563 return Qnil; | |
564 len -= got; | |
565 } | |
566 /* Remove the properties from this interval. If it's short | |
567 enough, return, splitting it if it's too short. */ | |
568 else | |
569 { | |
570 unchanged = i; | |
571 i = split_interval_right (unchanged, s - unchanged->position + 1); | |
572 copy_properties (unchanged, i); | |
573 if (LENGTH (i) > len) | |
574 { | |
575 i = split_interval_left (i, len + 1); | |
576 copy_properties (unchanged, i); | |
577 remove_properties (properties, i); | |
578 return Qt; | |
579 } | |
580 | |
581 remove_properties (properties, i); | |
582 modified = 1; | |
583 len -= LENGTH (i); | |
584 i = next_interval (i); | |
585 } | |
586 } | |
587 | |
588 /* We are at the beginning of an interval, with len to scan */ | |
589 while (1) | |
590 { | |
591 if (LENGTH (i) >= len) | |
592 { | |
593 if (! interval_has_some_properties (properties, i)) | |
594 return modified ? Qt : Qnil; | |
595 | |
596 if (LENGTH (i) == len) | |
597 { | |
598 remove_properties (properties, i); | |
599 return Qt; | |
600 } | |
601 | |
602 /* i has the properties, and goes past the change limit */ | |
603 unchanged = split_interval_right (i, len + 1); | |
604 copy_properties (unchanged, i); | |
605 remove_properties (properties, i); | |
606 return Qt; | |
607 } | |
608 | |
609 len -= LENGTH (i); | |
610 modified += remove_properties (properties, i); | |
611 i = next_interval (i); | |
612 } | |
613 } | |
614 | |
615 DEFUN ("erase-text-properties", Ferase_text_properties, | |
616 Serase_text_properties, 3, 3, 0, | |
617 "Remove all text properties from OBJECT (a string or buffer), in the\n\ | |
618 range START to END. Returns t if any change was made, nil otherwise.") | |
619 (object, start, end) | |
620 Lisp_Object object, start, end; | |
621 { | |
622 register INTERVAL i, unchanged; | |
623 register int s, len, modified; | |
624 | |
625 i = validate_interval_range (object, &start, &end, soft); | |
626 if (NULL_INTERVAL_P (i)) | |
627 return Qnil; | |
628 | |
629 s = XINT (start); | |
630 len = XINT (end) - s; | |
631 if (i->position != s) | |
632 { | |
633 int got = LENGTH (i) - (s - i->position); | |
634 | |
635 if (got > len) | |
636 { | |
637 if (NILP (i->plist)) | |
638 return Qnil; | |
639 | |
640 unchanged = i; | |
641 i = split_interval_right (unchanged, s - unchanged->position + 1); | |
642 i = split_interval_right (i, len + 1); | |
643 copy_properties (unchanged, i); | |
644 return Qt; | |
645 } | |
646 | |
647 if (! NILP (i->plist)) | |
648 { | |
649 i = split_interval_right (i, s - i->position + 1); | |
650 modified++; | |
651 } | |
652 | |
653 len -= got; | |
654 i = next_interval (i); | |
655 } | |
656 | |
657 /* We are starting at the beginning of an interval */ | |
658 while (len > 0) | |
659 { | |
660 if (LENGTH (i) > len) | |
661 { | |
662 if (NILP (i->plist)) | |
663 return modified ? Qt : Qnil; | |
664 | |
665 i = split_interval_left (i, len + 1); | |
666 return Qt; | |
667 } | |
668 | |
669 len -= LENGTH (i); | |
670 modified += erase_properties (i); | |
671 i = next_interval (i); | |
672 } | |
673 | |
674 return modified ? Qt : Qnil; | |
675 } | |
676 | |
677 void | |
678 syms_of_textprop () | |
679 { | |
680 DEFVAR_INT ("interval-balance-threshold", &interval_balance_threshold, | |
681 "Threshold for rebalancing interval trees, expressed as the | |
682 percentage by which the left interval tree should not differ from the right."); | |
683 interval_balance_threshold = 8; | |
684 | |
685 /* Common attributes one might give text */ | |
686 | |
687 staticpro (&Qforeground); | |
688 Qforeground = intern ("foreground"); | |
689 staticpro (&Qbackground); | |
690 Qbackground = intern ("background"); | |
691 staticpro (&Qfont); | |
692 Qfont = intern ("font"); | |
693 staticpro (&Qstipple); | |
694 Qstipple = intern ("stipple"); | |
695 staticpro (&Qunderline); | |
696 Qunderline = intern ("underline"); | |
697 staticpro (&Qread_only); | |
698 Qread_only = intern ("read-only"); | |
699 staticpro (&Qinvisible); | |
700 Qinvisible = intern ("invisible"); | |
701 | |
702 /* Properties that text might use to specify certain actions */ | |
703 | |
704 staticpro (&Qmouse_left); | |
705 Qmouse_left = intern ("mouse-left"); | |
706 staticpro (&Qmouse_entered); | |
707 Qmouse_entered = intern ("mouse-entered"); | |
708 staticpro (&Qpoint_left); | |
709 Qpoint_left = intern ("point-left"); | |
710 staticpro (&Qpoint_entered); | |
711 Qpoint_entered = intern ("point-entered"); | |
712 staticpro (&Qmodification); | |
713 Qmodification = intern ("modification"); | |
714 | |
715 defsubr (&Stext_properties_at); | |
716 defsubr (&Snext_property_change); | |
717 defsubr (&Sprevious_property_change); | |
718 defsubr (&Sadd_text_properties); | |
719 defsubr (&Sset_text_properties); | |
720 defsubr (&Sremove_text_properties); | |
721 defsubr (&Serase_text_properties); | |
722 } |