1 /* Interface code for dealing with text properties.
2 Copyright (C) 1993, 1994, 1995, 1997 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
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 2, or (at your option)
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.
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, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
23 #include "intervals.h"
28 #define NULL (void *)0
31 /* Test for membership, allowing for t (actually any non-cons) to mean the
34 #define TMEM(sym, set) (CONSP (set) ? ! NILP (Fmemq (sym, set)) : ! NILP (set))
37 /* NOTES: previous- and next- property change will have to skip
38 zero-length intervals if they are implemented. This could be done
39 inside next_interval and previous_interval.
41 set_properties needs to deal with the interval property cache.
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,
45 handles the more general case, the uniqueness of properties is
46 necessary for the system to remain consistent. This requirement
47 is enforced by the subrs installing properties onto the intervals. */
49 /* The rest of the file is within this conditional */
50 #ifdef USE_TEXT_PROPERTIES
53 Lisp_Object Qmouse_left
;
54 Lisp_Object Qmouse_entered
;
55 Lisp_Object Qpoint_left
;
56 Lisp_Object Qpoint_entered
;
57 Lisp_Object Qcategory
;
58 Lisp_Object Qlocal_map
;
60 /* Visual properties text (including strings) may have. */
61 Lisp_Object Qforeground
, Qbackground
, Qfont
, Qunderline
, Qstipple
;
62 Lisp_Object Qinvisible
, Qread_only
, Qintangible
, Qmouse_face
;
64 /* Sticky properties */
65 Lisp_Object Qfront_sticky
, Qrear_nonsticky
;
67 /* If o1 is a cons whose cdr is a cons, return non-zero and set o2 to
68 the o1's cdr. Otherwise, return zero. This is handy for
70 #define PLIST_ELT_P(o1, o2) (CONSP (o1) && ((o2)=XCDR (o1), CONSP (o2)))
72 Lisp_Object Vinhibit_point_motion_hooks
;
73 Lisp_Object Vdefault_text_properties
;
75 /* verify_interval_modification saves insertion hooks here
76 to be run later by report_interval_modification. */
77 Lisp_Object interval_insert_behind_hooks
;
78 Lisp_Object interval_insert_in_front_hooks
;
80 /* Extract the interval at the position pointed to by BEGIN from
81 OBJECT, a string or buffer. Additionally, check that the positions
82 pointed to by BEGIN and END are within the bounds of OBJECT, and
83 reverse them if *BEGIN is greater than *END. The objects pointed
84 to by BEGIN and END may be integers or markers; if the latter, they
85 are coerced to integers.
87 When OBJECT is a string, we increment *BEGIN and *END
88 to make them origin-one.
90 Note that buffer points don't correspond to interval indices.
91 For example, point-max is 1 greater than the index of the last
92 character. This difference is handled in the caller, which uses
93 the validated points to determine a length, and operates on that.
94 Exceptions are Ftext_properties_at, Fnext_property_change, and
95 Fprevious_property_change which call this function with BEGIN == END.
96 Handle this case specially.
98 If FORCE is soft (0), it's OK to return NULL_INTERVAL. Otherwise,
99 create an interval tree for OBJECT if one doesn't exist, provided
100 the object actually contains text. In the current design, if there
101 is no text, there can be no text properties. */
107 validate_interval_range (object
, begin
, end
, force
)
108 Lisp_Object object
, *begin
, *end
;
114 CHECK_STRING_OR_BUFFER (object
, 0);
115 CHECK_NUMBER_COERCE_MARKER (*begin
, 0);
116 CHECK_NUMBER_COERCE_MARKER (*end
, 0);
118 /* If we are asked for a point, but from a subr which operates
119 on a range, then return nothing. */
120 if (EQ (*begin
, *end
) && begin
!= end
)
121 return NULL_INTERVAL
;
123 if (XINT (*begin
) > XINT (*end
))
131 if (BUFFERP (object
))
133 register struct buffer
*b
= XBUFFER (object
);
135 if (!(BUF_BEGV (b
) <= XINT (*begin
) && XINT (*begin
) <= XINT (*end
)
136 && XINT (*end
) <= BUF_ZV (b
)))
137 args_out_of_range (*begin
, *end
);
138 i
= BUF_INTERVALS (b
);
140 /* If there's no text, there are no properties. */
141 if (BUF_BEGV (b
) == BUF_ZV (b
))
142 return NULL_INTERVAL
;
144 searchpos
= XINT (*begin
);
148 register struct Lisp_String
*s
= XSTRING (object
);
150 if (! (0 <= XINT (*begin
) && XINT (*begin
) <= XINT (*end
)
151 && XINT (*end
) <= s
->size
))
152 args_out_of_range (*begin
, *end
);
153 XSETFASTINT (*begin
, XFASTINT (*begin
));
155 XSETFASTINT (*end
, XFASTINT (*end
));
159 return NULL_INTERVAL
;
161 searchpos
= XINT (*begin
);
164 if (NULL_INTERVAL_P (i
))
165 return (force
? create_root_interval (object
) : i
);
167 return find_interval (i
, searchpos
);
170 /* Validate LIST as a property list. If LIST is not a list, then
171 make one consisting of (LIST nil). Otherwise, verify that LIST
172 is even numbered and thus suitable as a plist. */
175 validate_plist (list
)
184 register Lisp_Object tail
;
185 for (i
= 0, tail
= list
; !NILP (tail
); i
++)
191 error ("Odd length text property list");
195 return Fcons (list
, Fcons (Qnil
, Qnil
));
198 /* Return nonzero if interval I has all the properties,
199 with the same values, of list PLIST. */
202 interval_has_all_properties (plist
, i
)
206 register Lisp_Object tail1
, tail2
, sym1
;
209 /* Go through each element of PLIST. */
210 for (tail1
= plist
; ! NILP (tail1
); tail1
= Fcdr (Fcdr (tail1
)))
215 /* Go through I's plist, looking for sym1 */
216 for (tail2
= i
->plist
; ! NILP (tail2
); tail2
= Fcdr (Fcdr (tail2
)))
217 if (EQ (sym1
, Fcar (tail2
)))
219 /* Found the same property on both lists. If the
220 values are unequal, return zero. */
221 if (! EQ (Fcar (Fcdr (tail1
)), Fcar (Fcdr (tail2
))))
224 /* Property has same value on both lists; go to next one. */
236 /* Return nonzero if the plist of interval I has any of the
237 properties of PLIST, regardless of their values. */
240 interval_has_some_properties (plist
, i
)
244 register Lisp_Object tail1
, tail2
, sym
;
246 /* Go through each element of PLIST. */
247 for (tail1
= plist
; ! NILP (tail1
); tail1
= Fcdr (Fcdr (tail1
)))
251 /* Go through i's plist, looking for tail1 */
252 for (tail2
= i
->plist
; ! NILP (tail2
); tail2
= Fcdr (Fcdr (tail2
)))
253 if (EQ (sym
, Fcar (tail2
)))
260 /* Changing the plists of individual intervals. */
262 /* Return the value of PROP in property-list PLIST, or Qunbound if it
265 property_value (plist
, prop
)
266 Lisp_Object plist
, prop
;
270 while (PLIST_ELT_P (plist
, value
))
271 if (EQ (XCAR (plist
), prop
))
274 plist
= XCDR (value
);
279 /* Set the properties of INTERVAL to PROPERTIES,
280 and record undo info for the previous values.
281 OBJECT is the string or buffer that INTERVAL belongs to. */
284 set_properties (properties
, interval
, object
)
285 Lisp_Object properties
, object
;
288 Lisp_Object sym
, value
;
290 if (BUFFERP (object
))
292 /* For each property in the old plist which is missing from PROPERTIES,
293 or has a different value in PROPERTIES, make an undo record. */
294 for (sym
= interval
->plist
;
295 PLIST_ELT_P (sym
, value
);
297 if (! EQ (property_value (properties
, XCAR (sym
)),
300 record_property_change (interval
->position
, LENGTH (interval
),
301 XCAR (sym
), XCAR (value
),
305 /* For each new property that has no value at all in the old plist,
306 make an undo record binding it to nil, so it will be removed. */
307 for (sym
= properties
;
308 PLIST_ELT_P (sym
, value
);
310 if (EQ (property_value (interval
->plist
, XCAR (sym
)), Qunbound
))
312 record_property_change (interval
->position
, LENGTH (interval
),
318 /* Store new properties. */
319 interval
->plist
= Fcopy_sequence (properties
);
322 /* Add the properties of PLIST to the interval I, or set
323 the value of I's property to the value of the property on PLIST
324 if they are different.
326 OBJECT should be the string or buffer the interval is in.
328 Return nonzero if this changes I (i.e., if any members of PLIST
329 are actually added to I's plist) */
332 add_properties (plist
, i
, object
)
337 Lisp_Object tail1
, tail2
, sym1
, val1
;
338 register int changed
= 0;
340 struct gcpro gcpro1
, gcpro2
, gcpro3
;
345 /* No need to protect OBJECT, because we can GC only in the case
346 where it is a buffer, and live buffers are always protected.
347 I and its plist are also protected, via OBJECT. */
348 GCPRO3 (tail1
, sym1
, val1
);
350 /* Go through each element of PLIST. */
351 for (tail1
= plist
; ! NILP (tail1
); tail1
= Fcdr (Fcdr (tail1
)))
354 val1
= Fcar (Fcdr (tail1
));
357 /* Go through I's plist, looking for sym1 */
358 for (tail2
= i
->plist
; ! NILP (tail2
); tail2
= Fcdr (Fcdr (tail2
)))
359 if (EQ (sym1
, Fcar (tail2
)))
361 /* No need to gcpro, because tail2 protects this
362 and it must be a cons cell (we get an error otherwise). */
363 register Lisp_Object this_cdr
;
365 this_cdr
= Fcdr (tail2
);
366 /* Found the property. Now check its value. */
369 /* The properties have the same value on both lists.
370 Continue to the next property. */
371 if (EQ (val1
, Fcar (this_cdr
)))
374 /* Record this change in the buffer, for undo purposes. */
375 if (BUFFERP (object
))
377 record_property_change (i
->position
, LENGTH (i
),
378 sym1
, Fcar (this_cdr
), object
);
381 /* I's property has a different value -- change it */
382 Fsetcar (this_cdr
, val1
);
389 /* Record this change in the buffer, for undo purposes. */
390 if (BUFFERP (object
))
392 record_property_change (i
->position
, LENGTH (i
),
395 i
->plist
= Fcons (sym1
, Fcons (val1
, i
->plist
));
405 /* For any members of PLIST which are properties of I, remove them
407 OBJECT is the string or buffer containing I. */
410 remove_properties (plist
, i
, object
)
415 register Lisp_Object tail1
, tail2
, sym
, current_plist
;
416 register int changed
= 0;
418 current_plist
= i
->plist
;
419 /* Go through each element of plist. */
420 for (tail1
= plist
; ! NILP (tail1
); tail1
= Fcdr (Fcdr (tail1
)))
424 /* First, remove the symbol if its at the head of the list */
425 while (! NILP (current_plist
) && EQ (sym
, Fcar (current_plist
)))
427 if (BUFFERP (object
))
429 record_property_change (i
->position
, LENGTH (i
),
430 sym
, Fcar (Fcdr (current_plist
)),
434 current_plist
= Fcdr (Fcdr (current_plist
));
438 /* Go through i's plist, looking for sym */
439 tail2
= current_plist
;
440 while (! NILP (tail2
))
442 register Lisp_Object
this;
443 this = Fcdr (Fcdr (tail2
));
444 if (EQ (sym
, Fcar (this)))
446 if (BUFFERP (object
))
448 record_property_change (i
->position
, LENGTH (i
),
449 sym
, Fcar (Fcdr (this)), object
);
452 Fsetcdr (Fcdr (tail2
), Fcdr (Fcdr (this)));
460 i
->plist
= current_plist
;
465 /* Remove all properties from interval I. Return non-zero
466 if this changes the interval. */
480 /* Returns the interval of POSITION in OBJECT.
481 POSITION is BEG-based. */
484 interval_of (position
, object
)
492 XSETBUFFER (object
, current_buffer
);
493 else if (EQ (object
, Qt
))
494 return NULL_INTERVAL
;
496 CHECK_STRING_OR_BUFFER (object
, 0);
498 if (BUFFERP (object
))
500 register struct buffer
*b
= XBUFFER (object
);
504 i
= BUF_INTERVALS (b
);
508 register struct Lisp_String
*s
= XSTRING (object
);
515 if (!(beg
<= position
&& position
<= end
))
516 args_out_of_range (make_number (position
), make_number (position
));
517 if (beg
== end
|| NULL_INTERVAL_P (i
))
518 return NULL_INTERVAL
;
520 return find_interval (i
, position
);
523 DEFUN ("text-properties-at", Ftext_properties_at
,
524 Stext_properties_at
, 1, 2, 0,
525 "Return the list of properties of the character at POSITION in OBJECT.\n\
526 OBJECT is the string or buffer to look for the properties in;\n\
527 nil means the current buffer.\n\
528 If POSITION is at the end of OBJECT, the value is nil.")
530 Lisp_Object position
, object
;
535 XSETBUFFER (object
, current_buffer
);
537 i
= validate_interval_range (object
, &position
, &position
, soft
);
538 if (NULL_INTERVAL_P (i
))
540 /* If POSITION is at the end of the interval,
541 it means it's the end of OBJECT.
542 There are no properties at the very end,
543 since no character follows. */
544 if (XINT (position
) == LENGTH (i
) + i
->position
)
550 DEFUN ("get-text-property", Fget_text_property
, Sget_text_property
, 2, 3, 0,
551 "Return the value of POSITION's property PROP, in OBJECT.\n\
552 OBJECT is optional and defaults to the current buffer.\n\
553 If POSITION is at the end of OBJECT, the value is nil.")
554 (position
, prop
, object
)
555 Lisp_Object position
, object
;
558 return textget (Ftext_properties_at (position
, object
), prop
);
561 DEFUN ("get-char-property", Fget_char_property
, Sget_char_property
, 2, 3, 0,
562 "Return the value of POSITION's property PROP, in OBJECT.\n\
563 OBJECT is optional and defaults to the current buffer.\n\
564 If POSITION is at the end of OBJECT, the value is nil.\n\
565 If OBJECT is a buffer, then overlay properties are considered as well as\n\
567 If OBJECT is a window, then that window's buffer is used, but window-specific\n\
568 overlays are considered only if they are associated with OBJECT.")
569 (position
, prop
, object
)
570 Lisp_Object position
, object
;
571 register Lisp_Object prop
;
573 struct window
*w
= 0;
575 CHECK_NUMBER_COERCE_MARKER (position
, 0);
578 XSETBUFFER (object
, current_buffer
);
580 if (WINDOWP (object
))
582 w
= XWINDOW (object
);
585 if (BUFFERP (object
))
587 int posn
= XINT (position
);
589 Lisp_Object
*overlay_vec
, tem
;
592 struct buffer
*obuf
= current_buffer
;
594 set_buffer_temp (XBUFFER (object
));
596 /* First try with room for 40 overlays. */
598 overlay_vec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
600 noverlays
= overlays_at (posn
, 0, &overlay_vec
, &len
,
601 &next_overlay
, NULL
);
603 /* If there are more than 40,
604 make enough space for all, and try again. */
608 overlay_vec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
609 noverlays
= overlays_at (posn
, 0, &overlay_vec
, &len
,
610 &next_overlay
, NULL
);
612 noverlays
= sort_overlays (overlay_vec
, noverlays
, w
);
614 set_buffer_temp (obuf
);
616 /* Now check the overlays in order of decreasing priority. */
617 while (--noverlays
>= 0)
619 tem
= Foverlay_get (overlay_vec
[noverlays
], prop
);
624 /* Not a buffer, or no appropriate overlay, so fall through to the
626 return (Fget_text_property (position
, prop
, object
));
629 DEFUN ("next-char-property-change", Fnext_char_property_change
,
630 Snext_char_property_change
, 1, 2, 0,
631 "Return the position of next text property or overlay change.\n\
632 This scans characters forward from POSITION in OBJECT till it finds\n\
633 a change in some text property, or the beginning or end of an overlay,\n\
634 and returns the position of that.\n\
635 If none is found, the function returns (point-max).\n\
637 If the optional third argument LIMIT is non-nil, don't search\n\
638 past position LIMIT; return LIMIT if nothing is found before LIMIT.")
640 Lisp_Object position
, limit
;
644 temp
= Fnext_overlay_change (position
);
647 CHECK_NUMBER (limit
, 2);
648 if (XINT (limit
) < XINT (temp
))
651 return Fnext_property_change (position
, Qnil
, temp
);
654 DEFUN ("previous-char-property-change", Fprevious_char_property_change
,
655 Sprevious_char_property_change
, 1, 2, 0,
656 "Return the position of previous text property or overlay change.\n\
657 Scans characters backward from POSITION in OBJECT till it finds\n\
658 a change in some text property, or the beginning or end of an overlay,\n\
659 and returns the position of that.\n\
660 If none is found, the function returns (point-max).\n\
662 If the optional third argument LIMIT is non-nil, don't search\n\
663 past position LIMIT; return LIMIT if nothing is found before LIMIT.")
665 Lisp_Object position
, limit
;
669 temp
= Fprevious_overlay_change (position
);
672 CHECK_NUMBER (limit
, 2);
673 if (XINT (limit
) > XINT (temp
))
676 return Fprevious_property_change (position
, Qnil
, temp
);
679 DEFUN ("next-property-change", Fnext_property_change
,
680 Snext_property_change
, 1, 3, 0,
681 "Return the position of next property change.\n\
682 Scans characters forward from POSITION in OBJECT till it finds\n\
683 a change in some text property, then returns the position of the change.\n\
684 The optional second argument OBJECT is the string or buffer to scan.\n\
685 Return nil if the property is constant all the way to the end of OBJECT.\n\
686 If the value is non-nil, it is a position greater than POSITION, never equal.\n\n\
687 If the optional third argument LIMIT is non-nil, don't search\n\
688 past position LIMIT; return LIMIT if nothing is found before LIMIT.")
689 (position
, object
, limit
)
690 Lisp_Object position
, object
, limit
;
692 register INTERVAL i
, next
;
695 XSETBUFFER (object
, current_buffer
);
697 if (! NILP (limit
) && ! EQ (limit
, Qt
))
698 CHECK_NUMBER_COERCE_MARKER (limit
, 0);
700 i
= validate_interval_range (object
, &position
, &position
, soft
);
702 /* If LIMIT is t, return start of next interval--don't
703 bother checking further intervals. */
706 if (NULL_INTERVAL_P (i
))
709 next
= next_interval (i
);
711 if (NULL_INTERVAL_P (next
))
712 XSETFASTINT (position
, (STRINGP (object
)
713 ? XSTRING (object
)->size
714 : BUF_ZV (XBUFFER (object
))));
716 XSETFASTINT (position
, next
->position
);
720 if (NULL_INTERVAL_P (i
))
723 next
= next_interval (i
);
725 while (! NULL_INTERVAL_P (next
) && intervals_equal (i
, next
)
726 && (NILP (limit
) || next
->position
< XFASTINT (limit
)))
727 next
= next_interval (next
);
729 if (NULL_INTERVAL_P (next
))
731 if (! NILP (limit
) && !(next
->position
< XFASTINT (limit
)))
734 XSETFASTINT (position
, next
->position
);
738 /* Return 1 if there's a change in some property between BEG and END. */
741 property_change_between_p (beg
, end
)
744 register INTERVAL i
, next
;
745 Lisp_Object object
, pos
;
747 XSETBUFFER (object
, current_buffer
);
748 XSETFASTINT (pos
, beg
);
750 i
= validate_interval_range (object
, &pos
, &pos
, soft
);
751 if (NULL_INTERVAL_P (i
))
754 next
= next_interval (i
);
755 while (! NULL_INTERVAL_P (next
) && intervals_equal (i
, next
))
757 next
= next_interval (next
);
758 if (NULL_INTERVAL_P (next
))
760 if (next
->position
>= end
)
764 if (NULL_INTERVAL_P (next
))
770 DEFUN ("next-single-property-change", Fnext_single_property_change
,
771 Snext_single_property_change
, 2, 4, 0,
772 "Return the position of next property change for a specific property.\n\
773 Scans characters forward from POSITION till it finds\n\
774 a change in the PROP property, then returns the position of the change.\n\
775 The optional third argument OBJECT is the string or buffer to scan.\n\
776 The property values are compared with `eq'.\n\
777 Return nil if the property is constant all the way to the end of OBJECT.\n\
778 If the value is non-nil, it is a position greater than POSITION, never equal.\n\n\
779 If the optional fourth argument LIMIT is non-nil, don't search\n\
780 past position LIMIT; return LIMIT if nothing is found before LIMIT.")
781 (position
, prop
, object
, limit
)
782 Lisp_Object position
, prop
, object
, limit
;
784 register INTERVAL i
, next
;
785 register Lisp_Object here_val
;
788 XSETBUFFER (object
, current_buffer
);
791 CHECK_NUMBER_COERCE_MARKER (limit
, 0);
793 i
= validate_interval_range (object
, &position
, &position
, soft
);
794 if (NULL_INTERVAL_P (i
))
797 here_val
= textget (i
->plist
, prop
);
798 next
= next_interval (i
);
799 while (! NULL_INTERVAL_P (next
)
800 && EQ (here_val
, textget (next
->plist
, prop
))
801 && (NILP (limit
) || next
->position
< XFASTINT (limit
)))
802 next
= next_interval (next
);
804 if (NULL_INTERVAL_P (next
))
806 if (! NILP (limit
) && !(next
->position
< XFASTINT (limit
)))
809 return make_number (next
->position
);
812 DEFUN ("previous-property-change", Fprevious_property_change
,
813 Sprevious_property_change
, 1, 3, 0,
814 "Return the position of previous property change.\n\
815 Scans characters backwards from POSITION in OBJECT till it finds\n\
816 a change in some text property, then returns the position of the change.\n\
817 The optional second argument OBJECT is the string or buffer to scan.\n\
818 Return nil if the property is constant all the way to the start of OBJECT.\n\
819 If the value is non-nil, it is a position less than POSITION, never equal.\n\n\
820 If the optional third argument LIMIT is non-nil, don't search\n\
821 back past position LIMIT; return LIMIT if nothing is found until LIMIT.")
822 (position
, object
, limit
)
823 Lisp_Object position
, object
, limit
;
825 register INTERVAL i
, previous
;
828 XSETBUFFER (object
, current_buffer
);
831 CHECK_NUMBER_COERCE_MARKER (limit
, 0);
833 i
= validate_interval_range (object
, &position
, &position
, soft
);
834 if (NULL_INTERVAL_P (i
))
837 /* Start with the interval containing the char before point. */
838 if (i
->position
== XFASTINT (position
))
839 i
= previous_interval (i
);
841 previous
= previous_interval (i
);
842 while (! NULL_INTERVAL_P (previous
) && intervals_equal (previous
, i
)
844 || (previous
->position
+ LENGTH (previous
) > XFASTINT (limit
))))
845 previous
= previous_interval (previous
);
846 if (NULL_INTERVAL_P (previous
))
849 && !(previous
->position
+ LENGTH (previous
) > XFASTINT (limit
)))
852 return make_number (previous
->position
+ LENGTH (previous
));
855 DEFUN ("previous-single-property-change", Fprevious_single_property_change
,
856 Sprevious_single_property_change
, 2, 4, 0,
857 "Return the position of previous property change for a specific property.\n\
858 Scans characters backward from POSITION till it finds\n\
859 a change in the PROP property, then returns the position of the change.\n\
860 The optional third argument OBJECT is the string or buffer to scan.\n\
861 The property values are compared with `eq'.\n\
862 Return nil if the property is constant all the way to the start of OBJECT.\n\
863 If the value is non-nil, it is a position less than POSITION, never equal.\n\n\
864 If the optional fourth argument LIMIT is non-nil, don't search\n\
865 back past position LIMIT; return LIMIT if nothing is found until LIMIT.")
866 (position
, prop
, object
, limit
)
867 Lisp_Object position
, prop
, object
, limit
;
869 register INTERVAL i
, previous
;
870 register Lisp_Object here_val
;
873 XSETBUFFER (object
, current_buffer
);
876 CHECK_NUMBER_COERCE_MARKER (limit
, 0);
878 i
= validate_interval_range (object
, &position
, &position
, soft
);
880 /* Start with the interval containing the char before point. */
881 if (! NULL_INTERVAL_P (i
) && i
->position
== XFASTINT (position
))
882 i
= previous_interval (i
);
884 if (NULL_INTERVAL_P (i
))
887 here_val
= textget (i
->plist
, prop
);
888 previous
= previous_interval (i
);
889 while (! NULL_INTERVAL_P (previous
)
890 && EQ (here_val
, textget (previous
->plist
, prop
))
892 || (previous
->position
+ LENGTH (previous
) > XFASTINT (limit
))))
893 previous
= previous_interval (previous
);
894 if (NULL_INTERVAL_P (previous
))
897 && !(previous
->position
+ LENGTH (previous
) > XFASTINT (limit
)))
900 return make_number (previous
->position
+ LENGTH (previous
));
903 /* Callers note, this can GC when OBJECT is a buffer (or nil). */
905 DEFUN ("add-text-properties", Fadd_text_properties
,
906 Sadd_text_properties
, 3, 4, 0,
907 "Add properties to the text from START to END.\n\
908 The third argument PROPERTIES is a property list\n\
909 specifying the property values to add.\n\
910 The optional fourth argument, OBJECT,\n\
911 is the string or buffer containing the text.\n\
912 Return t if any property value actually changed, nil otherwise.")
913 (start
, end
, properties
, object
)
914 Lisp_Object start
, end
, properties
, object
;
916 register INTERVAL i
, unchanged
;
917 register int s
, len
, modified
= 0;
920 properties
= validate_plist (properties
);
921 if (NILP (properties
))
925 XSETBUFFER (object
, current_buffer
);
927 i
= validate_interval_range (object
, &start
, &end
, hard
);
928 if (NULL_INTERVAL_P (i
))
932 len
= XINT (end
) - s
;
934 /* No need to protect OBJECT, because we GC only if it's a buffer,
935 and live buffers are always protected. */
938 /* If we're not starting on an interval boundary, we have to
939 split this interval. */
940 if (i
->position
!= s
)
942 /* If this interval already has the properties, we can
944 if (interval_has_all_properties (properties
, i
))
946 int got
= (LENGTH (i
) - (s
- i
->position
));
948 RETURN_UNGCPRO (Qnil
);
950 i
= next_interval (i
);
955 i
= split_interval_right (unchanged
, s
- unchanged
->position
);
956 copy_properties (unchanged
, i
);
960 if (BUFFERP (object
))
961 modify_region (XBUFFER (object
), XINT (start
), XINT (end
));
963 /* We are at the beginning of interval I, with LEN chars to scan. */
969 if (LENGTH (i
) >= len
)
971 /* We can UNGCPRO safely here, because there will be just
972 one more chance to gc, in the next call to add_properties,
973 and after that we will not need PROPERTIES or OBJECT again. */
976 if (interval_has_all_properties (properties
, i
))
978 if (BUFFERP (object
))
979 signal_after_change (XINT (start
), XINT (end
) - XINT (start
),
980 XINT (end
) - XINT (start
));
982 return modified
? Qt
: Qnil
;
985 if (LENGTH (i
) == len
)
987 add_properties (properties
, i
, object
);
988 if (BUFFERP (object
))
989 signal_after_change (XINT (start
), XINT (end
) - XINT (start
),
990 XINT (end
) - XINT (start
));
994 /* i doesn't have the properties, and goes past the change limit */
996 i
= split_interval_left (unchanged
, len
);
997 copy_properties (unchanged
, i
);
998 add_properties (properties
, i
, object
);
999 if (BUFFERP (object
))
1000 signal_after_change (XINT (start
), XINT (end
) - XINT (start
),
1001 XINT (end
) - XINT (start
));
1006 modified
+= add_properties (properties
, i
, object
);
1007 i
= next_interval (i
);
1011 /* Callers note, this can GC when OBJECT is a buffer (or nil). */
1013 DEFUN ("put-text-property", Fput_text_property
,
1014 Sput_text_property
, 4, 5, 0,
1015 "Set one property of the text from START to END.\n\
1016 The third and fourth arguments PROPERTY and VALUE\n\
1017 specify the property to add.\n\
1018 The optional fifth argument, OBJECT,\n\
1019 is the string or buffer containing the text.")
1020 (start
, end
, property
, value
, object
)
1021 Lisp_Object start
, end
, property
, value
, object
;
1023 Fadd_text_properties (start
, end
,
1024 Fcons (property
, Fcons (value
, Qnil
)),
1029 DEFUN ("set-text-properties", Fset_text_properties
,
1030 Sset_text_properties
, 3, 4, 0,
1031 "Completely replace properties of text from START to END.\n\
1032 The third argument PROPERTIES is the new property list.\n\
1033 The optional fourth argument, OBJECT,\n\
1034 is the string or buffer containing the text.")
1035 (start
, end
, properties
, object
)
1036 Lisp_Object start
, end
, properties
, object
;
1038 register INTERVAL i
, unchanged
;
1039 register INTERVAL prev_changed
= NULL_INTERVAL
;
1040 register int s
, len
;
1041 Lisp_Object ostart
, oend
;
1046 properties
= validate_plist (properties
);
1049 XSETBUFFER (object
, current_buffer
);
1051 /* If we want no properties for a whole string,
1052 get rid of its intervals. */
1053 if (NILP (properties
) && STRINGP (object
)
1054 && XFASTINT (start
) == 0
1055 && XFASTINT (end
) == XSTRING (object
)->size
)
1057 if (! XSTRING (object
)->intervals
)
1060 XSTRING (object
)->intervals
= 0;
1064 i
= validate_interval_range (object
, &start
, &end
, soft
);
1066 if (NULL_INTERVAL_P (i
))
1068 /* If buffer has no properties, and we want none, return now. */
1069 if (NILP (properties
))
1072 /* Restore the original START and END values
1073 because validate_interval_range increments them for strings. */
1077 i
= validate_interval_range (object
, &start
, &end
, hard
);
1078 /* This can return if start == end. */
1079 if (NULL_INTERVAL_P (i
))
1084 len
= XINT (end
) - s
;
1086 if (BUFFERP (object
))
1087 modify_region (XBUFFER (object
), XINT (start
), XINT (end
));
1089 if (i
->position
!= s
)
1092 i
= split_interval_right (unchanged
, s
- unchanged
->position
);
1094 if (LENGTH (i
) > len
)
1096 copy_properties (unchanged
, i
);
1097 i
= split_interval_left (i
, len
);
1098 set_properties (properties
, i
, object
);
1099 if (BUFFERP (object
))
1100 signal_after_change (XINT (start
), XINT (end
) - XINT (start
),
1101 XINT (end
) - XINT (start
));
1106 set_properties (properties
, i
, object
);
1108 if (LENGTH (i
) == len
)
1110 if (BUFFERP (object
))
1111 signal_after_change (XINT (start
), XINT (end
) - XINT (start
),
1112 XINT (end
) - XINT (start
));
1119 i
= next_interval (i
);
1122 /* We are starting at the beginning of an interval, I */
1128 if (LENGTH (i
) >= len
)
1130 if (LENGTH (i
) > len
)
1131 i
= split_interval_left (i
, len
);
1133 /* We have to call set_properties even if we are going to
1134 merge the intervals, so as to make the undo records
1135 and cause redisplay to happen. */
1136 set_properties (properties
, i
, object
);
1137 if (!NULL_INTERVAL_P (prev_changed
))
1138 merge_interval_left (i
);
1139 if (BUFFERP (object
))
1140 signal_after_change (XINT (start
), XINT (end
) - XINT (start
),
1141 XINT (end
) - XINT (start
));
1147 /* We have to call set_properties even if we are going to
1148 merge the intervals, so as to make the undo records
1149 and cause redisplay to happen. */
1150 set_properties (properties
, i
, object
);
1151 if (NULL_INTERVAL_P (prev_changed
))
1154 prev_changed
= i
= merge_interval_left (i
);
1156 i
= next_interval (i
);
1159 if (BUFFERP (object
))
1160 signal_after_change (XINT (start
), XINT (end
) - XINT (start
),
1161 XINT (end
) - XINT (start
));
1165 DEFUN ("remove-text-properties", Fremove_text_properties
,
1166 Sremove_text_properties
, 3, 4, 0,
1167 "Remove some properties from text from START to END.\n\
1168 The third argument PROPERTIES is a property list\n\
1169 whose property names specify the properties to remove.\n\
1170 \(The values stored in PROPERTIES are ignored.)\n\
1171 The optional fourth argument, OBJECT,\n\
1172 is the string or buffer containing the text.\n\
1173 Return t if any property was actually removed, nil otherwise.")
1174 (start
, end
, properties
, object
)
1175 Lisp_Object start
, end
, properties
, object
;
1177 register INTERVAL i
, unchanged
;
1178 register int s
, len
, modified
= 0;
1181 XSETBUFFER (object
, current_buffer
);
1183 i
= validate_interval_range (object
, &start
, &end
, soft
);
1184 if (NULL_INTERVAL_P (i
))
1188 len
= XINT (end
) - s
;
1190 if (i
->position
!= s
)
1192 /* No properties on this first interval -- return if
1193 it covers the entire region. */
1194 if (! interval_has_some_properties (properties
, i
))
1196 int got
= (LENGTH (i
) - (s
- i
->position
));
1200 i
= next_interval (i
);
1202 /* Split away the beginning of this interval; what we don't
1207 i
= split_interval_right (unchanged
, s
- unchanged
->position
);
1208 copy_properties (unchanged
, i
);
1212 if (BUFFERP (object
))
1213 modify_region (XBUFFER (object
), XINT (start
), XINT (end
));
1215 /* We are at the beginning of an interval, with len to scan */
1221 if (LENGTH (i
) >= len
)
1223 if (! interval_has_some_properties (properties
, i
))
1224 return modified
? Qt
: Qnil
;
1226 if (LENGTH (i
) == len
)
1228 remove_properties (properties
, i
, object
);
1229 if (BUFFERP (object
))
1230 signal_after_change (XINT (start
), XINT (end
) - XINT (start
),
1231 XINT (end
) - XINT (start
));
1235 /* i has the properties, and goes past the change limit */
1237 i
= split_interval_left (i
, len
);
1238 copy_properties (unchanged
, i
);
1239 remove_properties (properties
, i
, object
);
1240 if (BUFFERP (object
))
1241 signal_after_change (XINT (start
), XINT (end
) - XINT (start
),
1242 XINT (end
) - XINT (start
));
1247 modified
+= remove_properties (properties
, i
, object
);
1248 i
= next_interval (i
);
1252 DEFUN ("text-property-any", Ftext_property_any
,
1253 Stext_property_any
, 4, 5, 0,
1254 "Check text from START to END for property PROPERTY equalling VALUE.\n\
1255 If so, return the position of the first character whose property PROPERTY\n\
1256 is `eq' to VALUE. Otherwise return nil.\n\
1257 The optional fifth argument, OBJECT, is the string or buffer\n\
1258 containing the text.")
1259 (start
, end
, property
, value
, object
)
1260 Lisp_Object start
, end
, property
, value
, object
;
1262 register INTERVAL i
;
1263 register int e
, pos
;
1266 XSETBUFFER (object
, current_buffer
);
1267 i
= validate_interval_range (object
, &start
, &end
, soft
);
1268 if (NULL_INTERVAL_P (i
))
1269 return (!NILP (value
) || EQ (start
, end
) ? Qnil
: start
);
1272 while (! NULL_INTERVAL_P (i
))
1274 if (i
->position
>= e
)
1276 if (EQ (textget (i
->plist
, property
), value
))
1279 if (pos
< XINT (start
))
1281 return make_number (pos
);
1283 i
= next_interval (i
);
1288 DEFUN ("text-property-not-all", Ftext_property_not_all
,
1289 Stext_property_not_all
, 4, 5, 0,
1290 "Check text from START to END for property PROPERTY not equalling VALUE.\n\
1291 If so, return the position of the first character whose property PROPERTY\n\
1292 is not `eq' to VALUE. Otherwise, return nil.\n\
1293 The optional fifth argument, OBJECT, is the string or buffer\n\
1294 containing the text.")
1295 (start
, end
, property
, value
, object
)
1296 Lisp_Object start
, end
, property
, value
, object
;
1298 register INTERVAL i
;
1302 XSETBUFFER (object
, current_buffer
);
1303 i
= validate_interval_range (object
, &start
, &end
, soft
);
1304 if (NULL_INTERVAL_P (i
))
1305 return (NILP (value
) || EQ (start
, end
)) ? Qnil
: start
;
1309 while (! NULL_INTERVAL_P (i
))
1311 if (i
->position
>= e
)
1313 if (! EQ (textget (i
->plist
, property
), value
))
1315 if (i
->position
> s
)
1317 return make_number (s
);
1319 i
= next_interval (i
);
1324 /* I don't think this is the right interface to export; how often do you
1325 want to do something like this, other than when you're copying objects
1328 I think it would be better to have a pair of functions, one which
1329 returns the text properties of a region as a list of ranges and
1330 plists, and another which applies such a list to another object. */
1332 /* Add properties from SRC to SRC of SRC, starting at POS in DEST.
1333 SRC and DEST may each refer to strings or buffers.
1334 Optional sixth argument PROP causes only that property to be copied.
1335 Properties are copied to DEST as if by `add-text-properties'.
1336 Return t if any property value actually changed, nil otherwise. */
1338 /* Note this can GC when DEST is a buffer. */
1341 copy_text_properties (start
, end
, src
, pos
, dest
, prop
)
1342 Lisp_Object start
, end
, src
, pos
, dest
, prop
;
1348 int s
, e
, e2
, p
, len
, modified
= 0;
1349 struct gcpro gcpro1
, gcpro2
;
1351 i
= validate_interval_range (src
, &start
, &end
, soft
);
1352 if (NULL_INTERVAL_P (i
))
1355 CHECK_NUMBER_COERCE_MARKER (pos
, 0);
1357 Lisp_Object dest_start
, dest_end
;
1360 XSETFASTINT (dest_end
, XINT (dest_start
) + (XINT (end
) - XINT (start
)));
1361 /* Apply this to a copy of pos; it will try to increment its arguments,
1362 which we don't want. */
1363 validate_interval_range (dest
, &dest_start
, &dest_end
, soft
);
1374 e2
= i
->position
+ LENGTH (i
);
1381 while (! NILP (plist
))
1383 if (EQ (Fcar (plist
), prop
))
1385 plist
= Fcons (prop
, Fcons (Fcar (Fcdr (plist
)), Qnil
));
1388 plist
= Fcdr (Fcdr (plist
));
1392 /* Must defer modifications to the interval tree in case src
1393 and dest refer to the same string or buffer. */
1394 stuff
= Fcons (Fcons (make_number (p
),
1395 Fcons (make_number (p
+ len
),
1396 Fcons (plist
, Qnil
))),
1400 i
= next_interval (i
);
1401 if (NULL_INTERVAL_P (i
))
1408 GCPRO2 (stuff
, dest
);
1410 while (! NILP (stuff
))
1413 res
= Fadd_text_properties (Fcar (res
), Fcar (Fcdr (res
)),
1414 Fcar (Fcdr (Fcdr (res
))), dest
);
1417 stuff
= Fcdr (stuff
);
1422 return modified
? Qt
: Qnil
;
1426 /* Return a list representing the text properties of OBJECT between
1427 START and END. if PROP is non-nil, report only on that property.
1428 Each result list element has the form (S E PLIST), where S and E
1429 are positions in OBJECT and PLIST is a property list containing the
1430 text properties of OBJECT between S and E. Value is nil if OBJECT
1431 doesn't contain text properties between START and END. */
1434 text_property_list (object
, start
, end
, prop
)
1435 Lisp_Object object
, start
, end
, prop
;
1442 i
= validate_interval_range (object
, &start
, &end
, soft
);
1443 if (!NULL_INTERVAL_P (i
))
1445 int s
= XINT (start
);
1450 int interval_end
, len
;
1453 interval_end
= i
->position
+ LENGTH (i
);
1454 if (interval_end
> e
)
1456 len
= interval_end
- s
;
1461 for (; !NILP (plist
); plist
= Fcdr (Fcdr (plist
)))
1462 if (EQ (Fcar (plist
), prop
))
1464 plist
= Fcons (prop
, Fcons (Fcar (Fcdr (plist
)), Qnil
));
1469 result
= Fcons (Fcons (make_number (s
),
1470 Fcons (make_number (s
+ len
),
1471 Fcons (plist
, Qnil
))),
1474 i
= next_interval (i
);
1475 if (NULL_INTERVAL_P (i
))
1485 /* Add text properties to OBJECT from LIST. LIST is a list of triples
1486 (START END PLIST), where START and END are positions and PLIST is a
1487 property list containing the text properties to add. Adjust START
1488 and END positions by DELTA before adding properties. Value is
1489 non-zero if OBJECT was modified. */
1492 add_text_properties_from_list (object
, list
, delta
)
1493 Lisp_Object object
, list
, delta
;
1495 struct gcpro gcpro1
, gcpro2
;
1498 GCPRO2 (list
, object
);
1500 for (; CONSP (list
); list
= XCDR (list
))
1502 Lisp_Object item
, start
, end
, plist
, tem
;
1505 start
= make_number (XINT (XCAR (item
)) + XINT (delta
));
1506 end
= make_number (XINT (XCAR (XCDR (item
))) + XINT (delta
));
1507 plist
= XCAR (XCDR (XCDR (item
)));
1509 tem
= Fadd_text_properties (start
, end
, plist
, object
);
1520 /* Modify end-points of ranges in LIST destructively. LIST is a list
1521 as returned from text_property_list. Change end-points equal to
1522 OLD_END to NEW_END. */
1525 extend_property_ranges (list
, old_end
, new_end
)
1526 Lisp_Object list
, old_end
, new_end
;
1528 for (; CONSP (list
); list
= XCDR (list
))
1530 Lisp_Object item
, end
;
1533 end
= XCAR (XCDR (item
));
1535 if (EQ (end
, old_end
))
1536 XCAR (XCDR (item
)) = new_end
;
1542 /* Call the modification hook functions in LIST, each with START and END. */
1545 call_mod_hooks (list
, start
, end
)
1546 Lisp_Object list
, start
, end
;
1548 struct gcpro gcpro1
;
1550 while (!NILP (list
))
1552 call2 (Fcar (list
), start
, end
);
1558 /* Check for read-only intervals between character positions START ... END,
1559 in BUF, and signal an error if we find one.
1561 Then check for any modification hooks in the range.
1562 Create a list of all these hooks in lexicographic order,
1563 eliminating consecutive extra copies of the same hook. Then call
1564 those hooks in order, with START and END - 1 as arguments. */
1567 verify_interval_modification (buf
, start
, end
)
1571 register INTERVAL intervals
= BUF_INTERVALS (buf
);
1572 register INTERVAL i
;
1574 register Lisp_Object prev_mod_hooks
;
1575 Lisp_Object mod_hooks
;
1576 struct gcpro gcpro1
;
1579 prev_mod_hooks
= Qnil
;
1582 interval_insert_behind_hooks
= Qnil
;
1583 interval_insert_in_front_hooks
= Qnil
;
1585 if (NULL_INTERVAL_P (intervals
))
1595 /* For an insert operation, check the two chars around the position. */
1599 Lisp_Object before
, after
;
1601 /* Set I to the interval containing the char after START,
1602 and PREV to the interval containing the char before START.
1603 Either one may be null. They may be equal. */
1604 i
= find_interval (intervals
, start
);
1606 if (start
== BUF_BEGV (buf
))
1608 else if (i
->position
== start
)
1609 prev
= previous_interval (i
);
1610 else if (i
->position
< start
)
1612 if (start
== BUF_ZV (buf
))
1615 /* If Vinhibit_read_only is set and is not a list, we can
1616 skip the read_only checks. */
1617 if (NILP (Vinhibit_read_only
) || CONSP (Vinhibit_read_only
))
1619 /* If I and PREV differ we need to check for the read-only
1620 property together with its stickiness. If either I or
1621 PREV are 0, this check is all we need.
1622 We have to take special care, since read-only may be
1623 indirectly defined via the category property. */
1626 if (! NULL_INTERVAL_P (i
))
1628 after
= textget (i
->plist
, Qread_only
);
1630 /* If interval I is read-only and read-only is
1631 front-sticky, inhibit insertion.
1632 Check for read-only as well as category. */
1634 && NILP (Fmemq (after
, Vinhibit_read_only
)))
1638 tem
= textget (i
->plist
, Qfront_sticky
);
1639 if (TMEM (Qread_only
, tem
)
1640 || (NILP (Fplist_get (i
->plist
, Qread_only
))
1641 && TMEM (Qcategory
, tem
)))
1642 error ("Attempt to insert within read-only text");
1646 if (! NULL_INTERVAL_P (prev
))
1648 before
= textget (prev
->plist
, Qread_only
);
1650 /* If interval PREV is read-only and read-only isn't
1651 rear-nonsticky, inhibit insertion.
1652 Check for read-only as well as category. */
1654 && NILP (Fmemq (before
, Vinhibit_read_only
)))
1658 tem
= textget (prev
->plist
, Qrear_nonsticky
);
1659 if (! TMEM (Qread_only
, tem
)
1660 && (! NILP (Fplist_get (prev
->plist
,Qread_only
))
1661 || ! TMEM (Qcategory
, tem
)))
1662 error ("Attempt to insert within read-only text");
1666 else if (! NULL_INTERVAL_P (i
))
1668 after
= textget (i
->plist
, Qread_only
);
1670 /* If interval I is read-only and read-only is
1671 front-sticky, inhibit insertion.
1672 Check for read-only as well as category. */
1673 if (! NILP (after
) && NILP (Fmemq (after
, Vinhibit_read_only
)))
1677 tem
= textget (i
->plist
, Qfront_sticky
);
1678 if (TMEM (Qread_only
, tem
)
1679 || (NILP (Fplist_get (i
->plist
, Qread_only
))
1680 && TMEM (Qcategory
, tem
)))
1681 error ("Attempt to insert within read-only text");
1683 tem
= textget (prev
->plist
, Qrear_nonsticky
);
1684 if (! TMEM (Qread_only
, tem
)
1685 && (! NILP (Fplist_get (prev
->plist
, Qread_only
))
1686 || ! TMEM (Qcategory
, tem
)))
1687 error ("Attempt to insert within read-only text");
1692 /* Run both insert hooks (just once if they're the same). */
1693 if (!NULL_INTERVAL_P (prev
))
1694 interval_insert_behind_hooks
1695 = textget (prev
->plist
, Qinsert_behind_hooks
);
1696 if (!NULL_INTERVAL_P (i
))
1697 interval_insert_in_front_hooks
1698 = textget (i
->plist
, Qinsert_in_front_hooks
);
1702 /* Loop over intervals on or next to START...END,
1703 collecting their hooks. */
1705 i
= find_interval (intervals
, start
);
1708 if (! INTERVAL_WRITABLE_P (i
))
1709 error ("Attempt to modify read-only text");
1711 mod_hooks
= textget (i
->plist
, Qmodification_hooks
);
1712 if (! NILP (mod_hooks
) && ! EQ (mod_hooks
, prev_mod_hooks
))
1714 hooks
= Fcons (mod_hooks
, hooks
);
1715 prev_mod_hooks
= mod_hooks
;
1718 i
= next_interval (i
);
1720 /* Keep going thru the interval containing the char before END. */
1721 while (! NULL_INTERVAL_P (i
) && i
->position
< end
);
1724 hooks
= Fnreverse (hooks
);
1725 while (! EQ (hooks
, Qnil
))
1727 call_mod_hooks (Fcar (hooks
), make_number (start
),
1729 hooks
= Fcdr (hooks
);
1735 /* Run the interval hooks for an insertion on character range START ... END.
1736 verify_interval_modification chose which hooks to run;
1737 this function is called after the insertion happens
1738 so it can indicate the range of inserted text. */
1741 report_interval_modification (start
, end
)
1742 Lisp_Object start
, end
;
1744 if (! NILP (interval_insert_behind_hooks
))
1745 call_mod_hooks (interval_insert_behind_hooks
, start
, end
);
1746 if (! NILP (interval_insert_in_front_hooks
)
1747 && ! EQ (interval_insert_in_front_hooks
,
1748 interval_insert_behind_hooks
))
1749 call_mod_hooks (interval_insert_in_front_hooks
, start
, end
);
1755 DEFVAR_LISP ("default-text-properties", &Vdefault_text_properties
,
1756 "Property-list used as default values.\n\
1757 The value of a property in this list is seen as the value for every\n\
1758 character that does not have its own value for that property.");
1759 Vdefault_text_properties
= Qnil
;
1761 DEFVAR_LISP ("inhibit-point-motion-hooks", &Vinhibit_point_motion_hooks
,
1762 "If non-nil, don't run `point-left' and `point-entered' text properties.\n\
1763 This also inhibits the use of the `intangible' text property.");
1764 Vinhibit_point_motion_hooks
= Qnil
;
1766 staticpro (&interval_insert_behind_hooks
);
1767 staticpro (&interval_insert_in_front_hooks
);
1768 interval_insert_behind_hooks
= Qnil
;
1769 interval_insert_in_front_hooks
= Qnil
;
1772 /* Common attributes one might give text */
1774 staticpro (&Qforeground
);
1775 Qforeground
= intern ("foreground");
1776 staticpro (&Qbackground
);
1777 Qbackground
= intern ("background");
1779 Qfont
= intern ("font");
1780 staticpro (&Qstipple
);
1781 Qstipple
= intern ("stipple");
1782 staticpro (&Qunderline
);
1783 Qunderline
= intern ("underline");
1784 staticpro (&Qread_only
);
1785 Qread_only
= intern ("read-only");
1786 staticpro (&Qinvisible
);
1787 Qinvisible
= intern ("invisible");
1788 staticpro (&Qintangible
);
1789 Qintangible
= intern ("intangible");
1790 staticpro (&Qcategory
);
1791 Qcategory
= intern ("category");
1792 staticpro (&Qlocal_map
);
1793 Qlocal_map
= intern ("local-map");
1794 staticpro (&Qfront_sticky
);
1795 Qfront_sticky
= intern ("front-sticky");
1796 staticpro (&Qrear_nonsticky
);
1797 Qrear_nonsticky
= intern ("rear-nonsticky");
1798 staticpro (&Qmouse_face
);
1799 Qmouse_face
= intern ("mouse-face");
1801 /* Properties that text might use to specify certain actions */
1803 staticpro (&Qmouse_left
);
1804 Qmouse_left
= intern ("mouse-left");
1805 staticpro (&Qmouse_entered
);
1806 Qmouse_entered
= intern ("mouse-entered");
1807 staticpro (&Qpoint_left
);
1808 Qpoint_left
= intern ("point-left");
1809 staticpro (&Qpoint_entered
);
1810 Qpoint_entered
= intern ("point-entered");
1812 defsubr (&Stext_properties_at
);
1813 defsubr (&Sget_text_property
);
1814 defsubr (&Sget_char_property
);
1815 defsubr (&Snext_char_property_change
);
1816 defsubr (&Sprevious_char_property_change
);
1817 defsubr (&Snext_property_change
);
1818 defsubr (&Snext_single_property_change
);
1819 defsubr (&Sprevious_property_change
);
1820 defsubr (&Sprevious_single_property_change
);
1821 defsubr (&Sadd_text_properties
);
1822 defsubr (&Sput_text_property
);
1823 defsubr (&Sset_text_properties
);
1824 defsubr (&Sremove_text_properties
);
1825 defsubr (&Stext_property_any
);
1826 defsubr (&Stext_property_not_all
);
1827 /* defsubr (&Serase_text_properties); */
1828 /* defsubr (&Scopy_text_properties); */
1833 lose
-- this shouldn
't be compiled if USE_TEXT_PROPERTIES isn't defined
1835 #endif /* USE_TEXT_PROPERTIES */