This source file includes following definitions.
- text_read_only
- modify_text_properties
- CHECK_STRING_OR_BUFFER
- validate_interval_range
- validate_plist
- interval_has_all_properties
- interval_has_some_properties
- interval_has_some_properties_list
- property_value
- set_properties
- add_properties
- remove_properties
- interval_of
- get_char_property_and_overlay
- add_text_properties_1
- set_text_properties
- set_text_properties_1
- text_property_stickiness
- copy_text_properties
- text_property_list
- add_text_properties_from_list
- extend_property_ranges
- call_mod_hooks
- verify_interval_modification
- report_interval_modification
- syms_of_textprop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <config.h>
20
21 #include "lisp.h"
22 #include "intervals.h"
23 #include "buffer.h"
24 #include "window.h"
25
26
27
28
29 #define TMEM(sym, set) (CONSP (set) ? ! NILP (Fmemq (sym, set)) : ! NILP (set))
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 enum property_set_type
47 {
48 TEXT_PROPERTY_REPLACE,
49 TEXT_PROPERTY_PREPEND,
50 TEXT_PROPERTY_APPEND
51 };
52
53
54
55
56 #define PLIST_ELT_P(o1, o2) (CONSP (o1) && ((o2)=XCDR (o1), CONSP (o2)))
57
58
59
60 Lisp_Object interval_insert_behind_hooks;
61 Lisp_Object interval_insert_in_front_hooks;
62
63
64
65
66 static AVOID
67 text_read_only (Lisp_Object propval)
68 {
69 if (STRINGP (propval))
70 xsignal1 (Qtext_read_only, propval);
71
72 xsignal0 (Qtext_read_only);
73 }
74
75
76
77 static void
78 modify_text_properties (Lisp_Object buffer, Lisp_Object start, Lisp_Object end)
79 {
80 ptrdiff_t b = XFIXNUM (start), e = XFIXNUM (end);
81 struct buffer *buf = XBUFFER (buffer), *old = current_buffer;
82
83 set_buffer_internal (buf);
84
85 prepare_to_modify_buffer_1 (b, e, NULL);
86
87 BUF_COMPUTE_UNCHANGED (buf, b - 1, e);
88 if (MODIFF <= SAVE_MODIFF)
89 record_first_change ();
90 modiff_incr (&MODIFF, 1);
91
92 bset_point_before_scroll (current_buffer, Qnil);
93
94 set_buffer_internal (old);
95 }
96
97
98
99 static void
100 CHECK_STRING_OR_BUFFER (Lisp_Object x)
101 {
102 CHECK_TYPE (STRINGP (x) || BUFFERP (x), Qbuffer_or_string_p, x);
103 }
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 enum { soft = false, hard = true };
126
127 INTERVAL
128 validate_interval_range (Lisp_Object object, Lisp_Object *begin,
129 Lisp_Object *end, bool force)
130 {
131 INTERVAL i;
132 ptrdiff_t searchpos;
133 Lisp_Object begin0 = *begin, end0 = *end;
134
135 CHECK_STRING_OR_BUFFER (object);
136 CHECK_FIXNUM_COERCE_MARKER (*begin);
137 CHECK_FIXNUM_COERCE_MARKER (*end);
138
139
140
141 if (EQ (*begin, *end) && begin != end)
142 return NULL;
143
144 if (XFIXNUM (*begin) > XFIXNUM (*end))
145 {
146 Lisp_Object n;
147 n = *begin;
148 *begin = *end;
149 *end = n;
150 }
151
152 if (BUFFERP (object))
153 {
154 register struct buffer *b = XBUFFER (object);
155
156 if (!(BUF_BEGV (b) <= XFIXNUM (*begin) && XFIXNUM (*begin) <= XFIXNUM (*end)
157 && XFIXNUM (*end) <= BUF_ZV (b)))
158 args_out_of_range (begin0, end0);
159 i = buffer_intervals (b);
160
161
162 if (BUF_BEGV (b) == BUF_ZV (b))
163 return NULL;
164
165 searchpos = XFIXNUM (*begin);
166 }
167 else
168 {
169 ptrdiff_t len = SCHARS (object);
170
171 if (! (0 <= XFIXNUM (*begin) && XFIXNUM (*begin) <= XFIXNUM (*end)
172 && XFIXNUM (*end) <= len))
173 args_out_of_range (begin0, end0);
174 i = string_intervals (object);
175
176 if (len == 0)
177 return NULL;
178
179 searchpos = XFIXNUM (*begin);
180 }
181
182 if (!i)
183 return (force ? create_root_interval (object) : i);
184
185 return find_interval (i, searchpos);
186 }
187
188
189
190
191
192 static Lisp_Object
193 validate_plist (Lisp_Object list)
194 {
195 if (NILP (list))
196 return Qnil;
197
198 if (CONSP (list))
199 {
200 Lisp_Object tail = list;
201 do
202 {
203 tail = XCDR (tail);
204 if (! CONSP (tail))
205 error ("Odd length text property list");
206 tail = XCDR (tail);
207 maybe_quit ();
208 }
209 while (CONSP (tail));
210
211 return list;
212 }
213
214 return list2 (list, Qnil);
215 }
216
217
218
219
220 static bool
221 interval_has_all_properties (Lisp_Object plist, INTERVAL i)
222 {
223 Lisp_Object tail1, tail2;
224
225
226 for (tail1 = plist; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
227 {
228 Lisp_Object sym1 = XCAR (tail1);
229 bool found = false;
230
231
232 for (tail2 = i->plist; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
233 if (EQ (sym1, XCAR (tail2)))
234 {
235
236
237 if (! EQ (Fcar (XCDR (tail1)), Fcar (XCDR (tail2))))
238 return false;
239
240
241 found = true;
242 break;
243 }
244
245 if (! found)
246 return false;
247 }
248
249 return true;
250 }
251
252
253
254
255 static bool
256 interval_has_some_properties (Lisp_Object plist, INTERVAL i)
257 {
258 Lisp_Object tail1, tail2, sym;
259
260
261 for (tail1 = plist; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
262 {
263 sym = XCAR (tail1);
264
265
266 for (tail2 = i->plist; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
267 if (EQ (sym, XCAR (tail2)))
268 return true;
269 }
270
271 return false;
272 }
273
274
275
276
277 static bool
278 interval_has_some_properties_list (Lisp_Object list, INTERVAL i)
279 {
280 Lisp_Object tail1, tail2, sym;
281
282
283 for (tail1 = list; CONSP (tail1); tail1 = XCDR (tail1))
284 {
285 sym = XCAR (tail1);
286
287
288 for (tail2 = i->plist; CONSP (tail2); tail2 = XCDR (XCDR (tail2)))
289 if (EQ (sym, XCAR (tail2)))
290 return true;
291 }
292
293 return false;
294 }
295
296
297
298
299
300 static Lisp_Object
301 property_value (Lisp_Object plist, Lisp_Object prop)
302 {
303 Lisp_Object value;
304
305 while (PLIST_ELT_P (plist, value))
306 if (EQ (XCAR (plist), prop))
307 return XCAR (value);
308 else
309 plist = XCDR (value);
310
311 return Qunbound;
312 }
313
314
315
316
317
318 static void
319 set_properties (Lisp_Object properties, INTERVAL interval, Lisp_Object object)
320 {
321 Lisp_Object sym, value;
322
323 if (BUFFERP (object))
324 {
325
326
327 for (sym = interval->plist;
328 PLIST_ELT_P (sym, value);
329 sym = XCDR (value))
330 if (! EQ (property_value (properties, XCAR (sym)),
331 XCAR (value)))
332 {
333 record_property_change (interval->position, LENGTH (interval),
334 XCAR (sym), XCAR (value),
335 object);
336 }
337
338
339
340 for (sym = properties;
341 PLIST_ELT_P (sym, value);
342 sym = XCDR (value))
343 if (BASE_EQ (property_value (interval->plist, XCAR (sym)), Qunbound))
344 {
345 record_property_change (interval->position, LENGTH (interval),
346 XCAR (sym), Qnil,
347 object);
348 }
349 }
350
351
352 set_interval_plist (interval, Fcopy_sequence (properties));
353 }
354
355
356
357
358
359
360
361
362
363
364
365
366
367 static bool
368 add_properties (Lisp_Object plist, INTERVAL i, Lisp_Object object,
369 enum property_set_type set_type, bool destructive)
370 {
371 Lisp_Object tail1, tail2, sym1, val1;
372 bool changed = false;
373
374 tail1 = plist;
375 sym1 = Qnil;
376 val1 = Qnil;
377
378
379 for (tail1 = plist; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
380 {
381 bool found = false;
382 sym1 = XCAR (tail1);
383 val1 = Fcar (XCDR (tail1));
384
385
386 for (tail2 = i->plist; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
387 if (EQ (sym1, XCAR (tail2)))
388 {
389 Lisp_Object this_cdr;
390
391 this_cdr = XCDR (tail2);
392
393 found = true;
394
395
396
397 if (EQ (val1, Fcar (this_cdr)))
398 break;
399
400
401 if (BUFFERP (object))
402 {
403 record_property_change (i->position, LENGTH (i),
404 sym1, Fcar (this_cdr), object);
405 }
406
407
408 if (set_type == TEXT_PROPERTY_REPLACE)
409 Fsetcar (this_cdr, val1);
410 else {
411 if (CONSP (Fcar (this_cdr)) &&
412
413 (! EQ (sym1, Qface) ||
414 NILP (Fkeywordp (Fcar (Fcar (this_cdr))))))
415
416
417 if (set_type == TEXT_PROPERTY_PREPEND)
418 Fsetcar (this_cdr, Fcons (val1, Fcar (this_cdr)));
419 else
420 {
421
422 if (destructive)
423 nconc2 (Fcar (this_cdr), list1 (val1));
424 else
425 Fsetcar (this_cdr, CALLN (Fappend,
426 Fcar (this_cdr),
427 list1 (val1)));
428 }
429 else {
430
431
432 if (set_type == TEXT_PROPERTY_PREPEND)
433 Fsetcar (this_cdr, list2 (val1, Fcar (this_cdr)));
434 else
435 Fsetcar (this_cdr, list2 (Fcar (this_cdr), val1));
436 }
437 }
438 changed = true;
439 break;
440 }
441
442 if (! found)
443 {
444
445 if (BUFFERP (object))
446 {
447 record_property_change (i->position, LENGTH (i),
448 sym1, Qnil, object);
449 }
450 set_interval_plist (i, Fcons (sym1, Fcons (val1, i->plist)));
451 changed = true;
452 }
453 }
454
455 return changed;
456 }
457
458
459
460
461
462
463 static bool
464 remove_properties (Lisp_Object plist, Lisp_Object list, INTERVAL i, Lisp_Object object)
465 {
466 bool changed = false;
467
468
469 bool use_plist = ! NILP (plist);
470 Lisp_Object tail1 = use_plist ? plist : list;
471
472 Lisp_Object current_plist = i->plist;
473
474
475 while (CONSP (tail1))
476 {
477 Lisp_Object sym = XCAR (tail1);
478
479
480 while (CONSP (current_plist) && EQ (sym, XCAR (current_plist)))
481 {
482 if (BUFFERP (object))
483 record_property_change (i->position, LENGTH (i),
484 sym, XCAR (XCDR (current_plist)),
485 object);
486
487 current_plist = XCDR (XCDR (current_plist));
488 changed = true;
489 }
490
491
492 Lisp_Object tail2 = current_plist;
493 while (! NILP (tail2))
494 {
495 Lisp_Object this = XCDR (XCDR (tail2));
496 if (CONSP (this) && EQ (sym, XCAR (this)))
497 {
498 if (BUFFERP (object))
499 record_property_change (i->position, LENGTH (i),
500 sym, XCAR (XCDR (this)), object);
501
502 Fsetcdr (XCDR (tail2), XCDR (XCDR (this)));
503 changed = true;
504 }
505 tail2 = this;
506 }
507
508
509 tail1 = XCDR (tail1);
510 if (use_plist && CONSP (tail1))
511 tail1 = XCDR (tail1);
512 }
513
514 if (changed)
515 set_interval_plist (i, current_plist);
516 return changed;
517 }
518
519
520
521
522 INTERVAL
523 interval_of (ptrdiff_t position, Lisp_Object object)
524 {
525 register INTERVAL i;
526 ptrdiff_t beg, end;
527
528 if (NILP (object))
529 XSETBUFFER (object, current_buffer);
530 else if (EQ (object, Qt))
531 return NULL;
532
533 CHECK_STRING_OR_BUFFER (object);
534
535 if (BUFFERP (object))
536 {
537 register struct buffer *b = XBUFFER (object);
538
539 beg = BUF_BEGV (b);
540 end = BUF_ZV (b);
541 i = buffer_intervals (b);
542 }
543 else
544 {
545 beg = 0;
546 end = SCHARS (object);
547 i = string_intervals (object);
548 }
549
550 if (!(beg <= position && position <= end))
551 args_out_of_range (make_fixnum (position), make_fixnum (position));
552 if (beg == end || !i)
553 return NULL;
554
555 return find_interval (i, position);
556 }
557
558 DEFUN ("text-properties-at", Ftext_properties_at,
559 Stext_properties_at, 1, 2, 0,
560 doc:
561
562
563
564
565
566
567
568
569
570
571
572 )
573 (Lisp_Object position, Lisp_Object object)
574 {
575 register INTERVAL i;
576
577 if (NILP (object))
578 XSETBUFFER (object, current_buffer);
579
580 i = validate_interval_range (object, &position, &position, soft);
581 if (!i)
582 return Qnil;
583
584
585
586
587 if (XFIXNUM (position) == LENGTH (i) + i->position)
588 return Qnil;
589
590 return i->plist;
591 }
592
593 DEFUN ("get-text-property", Fget_text_property, Sget_text_property, 2, 3, 0,
594 doc:
595
596
597
598
599
600
601 )
602 (Lisp_Object position, Lisp_Object prop, Lisp_Object object)
603 {
604 return textget (Ftext_properties_at (position, object), prop);
605 }
606
607
608
609
610
611
612
613
614
615
616
617
618 Lisp_Object
619 get_char_property_and_overlay (Lisp_Object position, register Lisp_Object prop, Lisp_Object object, Lisp_Object *overlay)
620 {
621 struct window *w = 0;
622
623 EMACS_INT pos = fix_position (position);
624
625 if (NILP (object))
626 XSETBUFFER (object, current_buffer);
627
628 if (WINDOWP (object))
629 {
630 CHECK_LIVE_WINDOW (object);
631 w = XWINDOW (object);
632 object = w->contents;
633 }
634 if (BUFFERP (object))
635 {
636 struct buffer *b = XBUFFER (object);
637 struct itree_node *node;
638 struct sortvec items[2];
639 struct sortvec *result = NULL;
640 Lisp_Object result_tem = Qnil;
641
642 if (! (BUF_BEGV (b) <= pos
643 && pos <= BUF_ZV (b)))
644 xsignal1 (Qargs_out_of_range, position);
645
646
647 ITREE_FOREACH (node, b->overlays, pos, pos + 1, ASCENDING)
648 {
649 Lisp_Object tem = Foverlay_get (node->data, prop);
650 struct sortvec *this;
651
652 if (NILP (tem) || node->end < pos + 1
653 || (w && ! overlay_matches_window (w, node->data)))
654 continue;
655
656 this = (result == items ? items + 1 : items);
657 make_sortvec_item (this, node->data);
658 if (! result || (compare_overlays (result, this) < 0))
659 {
660 result = this;
661 result_tem = tem;
662 }
663 }
664 if (result)
665 {
666 if (overlay)
667 *overlay = result->overlay;
668 return result_tem;
669 }
670 }
671
672 if (overlay)
673
674 *overlay = Qnil;
675
676
677
678 return Fget_text_property (make_fixnum (pos), prop, object);
679 }
680
681 DEFUN ("get-char-property", Fget_char_property, Sget_char_property, 2, 3, 0,
682 doc:
683
684
685
686
687
688
689 )
690 (Lisp_Object position, Lisp_Object prop, Lisp_Object object)
691 {
692 return get_char_property_and_overlay (position, prop, object, 0);
693 }
694
695 DEFUN ("get-char-property-and-overlay", Fget_char_property_and_overlay,
696 Sget_char_property_and_overlay, 2, 3, 0,
697 doc:
698
699
700
701
702
703
704
705
706
707
708 )
709 (Lisp_Object position, Lisp_Object prop, Lisp_Object object)
710 {
711 Lisp_Object overlay;
712 Lisp_Object val
713 = get_char_property_and_overlay (position, prop, object, &overlay);
714 return Fcons (val, overlay);
715 }
716
717
718 DEFUN ("next-char-property-change", Fnext_char_property_change,
719 Snext_char_property_change, 1, 2, 0,
720 doc:
721
722
723
724
725
726
727
728
729 )
730 (Lisp_Object position, Lisp_Object limit)
731 {
732 Lisp_Object temp;
733
734 temp = Fnext_overlay_change (position);
735 if (! NILP (limit))
736 {
737 CHECK_FIXNUM_COERCE_MARKER (limit);
738 if (XFIXNUM (limit) < XFIXNUM (temp))
739 temp = limit;
740 }
741 return Fnext_property_change (position, Qnil, temp);
742 }
743
744 DEFUN ("previous-char-property-change", Fprevious_char_property_change,
745 Sprevious_char_property_change, 1, 2, 0,
746 doc:
747
748
749
750
751
752
753
754
755 )
756 (Lisp_Object position, Lisp_Object limit)
757 {
758 Lisp_Object temp;
759
760 temp = Fprevious_overlay_change (position);
761 if (! NILP (limit))
762 {
763 CHECK_FIXNUM_COERCE_MARKER (limit);
764 if (XFIXNUM (limit) > XFIXNUM (temp))
765 temp = limit;
766 }
767 return Fprevious_property_change (position, Qnil, temp);
768 }
769
770
771 DEFUN ("next-single-char-property-change", Fnext_single_char_property_change,
772 Snext_single_char_property_change, 2, 4, 0,
773 doc:
774
775
776
777
778
779
780
781
782
783
784
785
786
787 )
788 (Lisp_Object position, Lisp_Object prop, Lisp_Object object, Lisp_Object limit)
789 {
790 if (STRINGP (object))
791 {
792 position = Fnext_single_property_change (position, prop, object, limit);
793 if (NILP (position))
794 {
795 if (NILP (limit))
796 position = make_fixnum (SCHARS (object));
797 else
798 {
799 CHECK_FIXNUM (limit);
800 position = limit;
801 }
802 }
803 }
804 else
805 {
806 Lisp_Object initial_value, value;
807 specpdl_ref count = SPECPDL_INDEX ();
808
809 if (! NILP (object))
810 CHECK_BUFFER (object);
811
812 if (BUFFERP (object) && current_buffer != XBUFFER (object))
813 {
814 record_unwind_current_buffer ();
815 Fset_buffer (object);
816 }
817
818 CHECK_FIXNUM_COERCE_MARKER (position);
819
820 initial_value = Fget_char_property (position, prop, object);
821
822 if (NILP (limit))
823 XSETFASTINT (limit, ZV);
824 else
825 CHECK_FIXNUM_COERCE_MARKER (limit);
826
827 if (XFIXNUM (position) >= XFIXNUM (limit))
828 {
829 position = limit;
830 if (XFIXNUM (position) > ZV)
831 XSETFASTINT (position, ZV);
832 }
833 else
834 while (true)
835 {
836 position = Fnext_char_property_change (position, limit);
837 if (XFIXNAT (position) >= XFIXNAT (limit))
838 {
839 position = limit;
840 break;
841 }
842
843 value = Fget_char_property (position, prop, object);
844 if (!EQ (value, initial_value))
845 break;
846
847 if (XFIXNAT (position) >= ZV)
848 break;
849 }
850
851 position = unbind_to (count, position);
852 }
853
854 return position;
855 }
856
857 DEFUN ("previous-single-char-property-change",
858 Fprevious_single_char_property_change,
859 Sprevious_single_char_property_change, 2, 4, 0,
860 doc:
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875 )
876 (Lisp_Object position, Lisp_Object prop, Lisp_Object object, Lisp_Object limit)
877 {
878 if (STRINGP (object))
879 {
880 position = Fprevious_single_property_change (position, prop, object, limit);
881 if (NILP (position))
882 {
883 if (NILP (limit))
884 position = make_fixnum (0);
885 else
886 {
887 CHECK_FIXNUM (limit);
888 position = limit;
889 }
890 }
891 }
892 else
893 {
894 specpdl_ref count = SPECPDL_INDEX ();
895
896 if (! NILP (object))
897 CHECK_BUFFER (object);
898
899 if (BUFFERP (object) && current_buffer != XBUFFER (object))
900 {
901 record_unwind_current_buffer ();
902 Fset_buffer (object);
903 }
904
905 CHECK_FIXNUM_COERCE_MARKER (position);
906
907 if (NILP (limit))
908 XSETFASTINT (limit, BEGV);
909 else
910 CHECK_FIXNUM_COERCE_MARKER (limit);
911
912 if (XFIXNUM (position) <= XFIXNUM (limit))
913 {
914 position = limit;
915 if (XFIXNUM (position) < BEGV)
916 XSETFASTINT (position, BEGV);
917 }
918 else
919 {
920 Lisp_Object initial_value
921 = Fget_char_property (make_fixnum (XFIXNUM (position)
922 - (0 <= XFIXNUM (position))),
923 prop, object);
924
925 while (true)
926 {
927 position = Fprevious_char_property_change (position, limit);
928
929 if (XFIXNAT (position) <= XFIXNAT (limit))
930 {
931 position = limit;
932 break;
933 }
934 else
935 {
936 Lisp_Object value
937 = Fget_char_property (make_fixnum (XFIXNAT (position) - 1),
938 prop, object);
939
940 if (!EQ (value, initial_value))
941 break;
942 }
943 }
944 }
945
946 position = unbind_to (count, position);
947 }
948
949 return position;
950 }
951
952 DEFUN ("next-property-change", Fnext_property_change,
953 Snext_property_change, 1, 3, 0,
954 doc:
955
956
957
958
959
960
961
962
963
964
965 )
966 (Lisp_Object position, Lisp_Object object, Lisp_Object limit)
967 {
968 register INTERVAL i, next;
969
970 if (NILP (object))
971 XSETBUFFER (object, current_buffer);
972
973 if (!NILP (limit) && !EQ (limit, Qt))
974 CHECK_FIXNUM_COERCE_MARKER (limit);
975
976 i = validate_interval_range (object, &position, &position, soft);
977
978
979
980 if (EQ (limit, Qt))
981 {
982 if (!i)
983 next = i;
984 else
985 next = next_interval (i);
986
987 if (!next)
988 XSETFASTINT (position, (STRINGP (object)
989 ? SCHARS (object)
990 : BUF_ZV (XBUFFER (object))));
991 else
992 XSETFASTINT (position, next->position);
993 return position;
994 }
995
996 if (!i)
997 return limit;
998
999 next = next_interval (i);
1000
1001 while (next && intervals_equal (i, next)
1002 && (NILP (limit) || next->position < XFIXNUM (limit)))
1003 next = next_interval (next);
1004
1005 if (!next
1006 || (next->position
1007 >= (FIXNUMP (limit)
1008 ? XFIXNUM (limit)
1009 : (STRINGP (object)
1010 ? SCHARS (object)
1011 : BUF_ZV (XBUFFER (object))))))
1012 return limit;
1013 else
1014 return make_fixnum (next->position);
1015 }
1016
1017 DEFUN ("next-single-property-change", Fnext_single_property_change,
1018 Snext_single_property_change, 2, 4, 0,
1019 doc:
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031 )
1032 (Lisp_Object position, Lisp_Object prop, Lisp_Object object, Lisp_Object limit)
1033 {
1034 register INTERVAL i, next;
1035 register Lisp_Object here_val;
1036
1037 if (NILP (object))
1038 XSETBUFFER (object, current_buffer);
1039
1040 if (!NILP (limit))
1041 CHECK_FIXNUM_COERCE_MARKER (limit);
1042
1043 i = validate_interval_range (object, &position, &position, soft);
1044 if (!i)
1045 return limit;
1046
1047 here_val = textget (i->plist, prop);
1048 next = next_interval (i);
1049 while (next
1050 && EQ (here_val, textget (next->plist, prop))
1051 && (NILP (limit) || next->position < XFIXNUM (limit)))
1052 next = next_interval (next);
1053
1054 if (!next
1055 || (next->position
1056 >= (FIXNUMP (limit)
1057 ? XFIXNUM (limit)
1058 : (STRINGP (object)
1059 ? SCHARS (object)
1060 : BUF_ZV (XBUFFER (object))))))
1061 return limit;
1062 else
1063 return make_fixnum (next->position);
1064 }
1065
1066 DEFUN ("previous-property-change", Fprevious_property_change,
1067 Sprevious_property_change, 1, 3, 0,
1068 doc:
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079 )
1080 (Lisp_Object position, Lisp_Object object, Lisp_Object limit)
1081 {
1082 register INTERVAL i, previous;
1083
1084 if (NILP (object))
1085 XSETBUFFER (object, current_buffer);
1086
1087 if (!NILP (limit))
1088 CHECK_FIXNUM_COERCE_MARKER (limit);
1089
1090 i = validate_interval_range (object, &position, &position, soft);
1091 if (!i)
1092 return limit;
1093
1094
1095 if (i->position == XFIXNAT (position))
1096 i = previous_interval (i);
1097
1098 previous = previous_interval (i);
1099 while (previous && intervals_equal (previous, i)
1100 && (NILP (limit)
1101 || (previous->position + LENGTH (previous) > XFIXNUM (limit))))
1102 previous = previous_interval (previous);
1103
1104 if (!previous
1105 || (previous->position + LENGTH (previous)
1106 <= (FIXNUMP (limit)
1107 ? XFIXNUM (limit)
1108 : (STRINGP (object) ? 0 : BUF_BEGV (XBUFFER (object))))))
1109 return limit;
1110 else
1111 return make_fixnum (previous->position + LENGTH (previous));
1112 }
1113
1114 DEFUN ("previous-single-property-change", Fprevious_single_property_change,
1115 Sprevious_single_property_change, 2, 4, 0,
1116 doc:
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128 )
1129 (Lisp_Object position, Lisp_Object prop, Lisp_Object object, Lisp_Object limit)
1130 {
1131 register INTERVAL i, previous;
1132 register Lisp_Object here_val;
1133
1134 if (NILP (object))
1135 XSETBUFFER (object, current_buffer);
1136
1137 if (!NILP (limit))
1138 CHECK_FIXNUM_COERCE_MARKER (limit);
1139
1140 i = validate_interval_range (object, &position, &position, soft);
1141
1142
1143 if (i && i->position == XFIXNAT (position))
1144 i = previous_interval (i);
1145
1146 if (!i)
1147 return limit;
1148
1149 here_val = textget (i->plist, prop);
1150 previous = previous_interval (i);
1151 while (previous
1152 && EQ (here_val, textget (previous->plist, prop))
1153 && (NILP (limit)
1154 || (previous->position + LENGTH (previous) > XFIXNUM (limit))))
1155 previous = previous_interval (previous);
1156
1157 if (!previous
1158 || (previous->position + LENGTH (previous)
1159 <= (FIXNUMP (limit)
1160 ? XFIXNUM (limit)
1161 : (STRINGP (object) ? 0 : BUF_BEGV (XBUFFER (object))))))
1162 return limit;
1163 else
1164 return make_fixnum (previous->position + LENGTH (previous));
1165 }
1166
1167
1168
1169 static Lisp_Object
1170 add_text_properties_1 (Lisp_Object start, Lisp_Object end,
1171 Lisp_Object properties, Lisp_Object object,
1172 enum property_set_type set_type,
1173 bool destructive) {
1174
1175
1176
1177 if (BUFFERP (object) && XBUFFER (object) != current_buffer)
1178 {
1179 specpdl_ref count = SPECPDL_INDEX ();
1180 record_unwind_current_buffer ();
1181 set_buffer_internal (XBUFFER (object));
1182 return unbind_to (count, add_text_properties_1 (start, end, properties,
1183 object, set_type,
1184 destructive));
1185 }
1186
1187 INTERVAL i, unchanged;
1188 ptrdiff_t s, len;
1189 bool modified = false;
1190 bool first_time = true;
1191
1192 properties = validate_plist (properties);
1193 if (NILP (properties))
1194 return Qnil;
1195
1196 if (NILP (object))
1197 XSETBUFFER (object, current_buffer);
1198
1199 retry:
1200 i = validate_interval_range (object, &start, &end, hard);
1201 if (!i)
1202 return Qnil;
1203
1204 s = XFIXNUM (start);
1205 len = XFIXNUM (end) - s;
1206
1207
1208 if (interval_has_all_properties (properties, i))
1209 {
1210 ptrdiff_t got = LENGTH (i) - (s - i->position);
1211
1212 do
1213 {
1214 if (got >= len)
1215 return Qnil;
1216 len -= got;
1217 i = next_interval (i);
1218 got = LENGTH (i);
1219 }
1220 while (interval_has_all_properties (properties, i));
1221 }
1222 else if (i->position != s)
1223 {
1224
1225
1226 unchanged = i;
1227 i = split_interval_right (unchanged, s - unchanged->position);
1228 copy_properties (unchanged, i);
1229 }
1230
1231 if (BUFFERP (object) && first_time)
1232 {
1233 ptrdiff_t prev_total_length = TOTAL_LENGTH (i);
1234 ptrdiff_t prev_pos = i->position;
1235
1236 modify_text_properties (object, start, end);
1237
1238
1239
1240
1241
1242
1243 if (TOTAL_LENGTH (i) != prev_total_length
1244 || i->position != prev_pos)
1245 {
1246 first_time = false;
1247 goto retry;
1248 }
1249 }
1250
1251
1252 for (;;)
1253 {
1254 eassert (i != 0);
1255
1256 if (LENGTH (i) >= len)
1257 {
1258 if (interval_has_all_properties (properties, i))
1259 {
1260 if (BUFFERP (object))
1261 signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start),
1262 XFIXNUM (end) - XFIXNUM (start));
1263
1264 eassert (modified);
1265 return Qt;
1266 }
1267
1268 if (LENGTH (i) == len)
1269 {
1270 add_properties (properties, i, object, set_type, destructive);
1271 if (BUFFERP (object))
1272 signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start),
1273 XFIXNUM (end) - XFIXNUM (start));
1274 return Qt;
1275 }
1276
1277
1278 unchanged = i;
1279 i = split_interval_left (unchanged, len);
1280 copy_properties (unchanged, i);
1281 add_properties (properties, i, object, set_type, destructive);
1282 if (BUFFERP (object))
1283 signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start),
1284 XFIXNUM (end) - XFIXNUM (start));
1285 return Qt;
1286 }
1287
1288 len -= LENGTH (i);
1289 modified |= add_properties (properties, i, object, set_type, destructive);
1290 i = next_interval (i);
1291 }
1292 }
1293
1294
1295
1296 DEFUN ("add-text-properties", Fadd_text_properties,
1297 Sadd_text_properties, 3, 4, 0,
1298 doc:
1299
1300
1301
1302
1303
1304 )
1305 (Lisp_Object start, Lisp_Object end, Lisp_Object properties,
1306 Lisp_Object object)
1307 {
1308 return add_text_properties_1 (start, end, properties, object,
1309 TEXT_PROPERTY_REPLACE, true);
1310 }
1311
1312
1313
1314 DEFUN ("put-text-property", Fput_text_property,
1315 Sput_text_property, 4, 5, 0,
1316 doc:
1317
1318
1319
1320
1321 )
1322 (Lisp_Object start, Lisp_Object end, Lisp_Object property,
1323 Lisp_Object value, Lisp_Object object)
1324 {
1325 AUTO_LIST2 (properties, property, value);
1326 Fadd_text_properties (start, end, properties, object);
1327 return Qnil;
1328 }
1329
1330 DEFUN ("set-text-properties", Fset_text_properties,
1331 Sset_text_properties, 3, 4, 0,
1332 doc:
1333
1334
1335
1336
1337
1338 )
1339 (Lisp_Object start, Lisp_Object end, Lisp_Object properties, Lisp_Object object)
1340 {
1341 return set_text_properties (start, end, properties, object, Qt);
1342 }
1343
1344
1345 DEFUN ("add-face-text-property", Fadd_face_text_property,
1346 Sadd_face_text_property, 3, 5, 0,
1347 doc:
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363 )
1364 (Lisp_Object start, Lisp_Object end, Lisp_Object face,
1365 Lisp_Object append, Lisp_Object object)
1366 {
1367 AUTO_LIST2 (properties, Qface, face);
1368 add_text_properties_1 (start, end, properties, object,
1369 (NILP (append)
1370 ? TEXT_PROPERTY_PREPEND
1371 : TEXT_PROPERTY_APPEND),
1372 false);
1373 return Qnil;
1374 }
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385 Lisp_Object
1386 set_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object properties,
1387 Lisp_Object object, Lisp_Object coherent_change_p)
1388 {
1389
1390
1391
1392 if (BUFFERP (object) && XBUFFER (object) != current_buffer)
1393 {
1394 specpdl_ref count = SPECPDL_INDEX ();
1395 record_unwind_current_buffer ();
1396 set_buffer_internal (XBUFFER (object));
1397 return unbind_to (count,
1398 set_text_properties (start, end, properties,
1399 object, coherent_change_p));
1400 }
1401
1402 INTERVAL i;
1403 bool first_time = true;
1404
1405 properties = validate_plist (properties);
1406
1407 if (NILP (object))
1408 XSETBUFFER (object, current_buffer);
1409
1410
1411
1412 if (NILP (properties) && STRINGP (object)
1413 && BASE_EQ (start, make_fixnum (0))
1414 && BASE_EQ (end, make_fixnum (SCHARS (object))))
1415 {
1416 if (!string_intervals (object))
1417 return Qnil;
1418
1419 set_string_intervals (object, NULL);
1420 return Qt;
1421 }
1422
1423 retry:
1424 i = validate_interval_range (object, &start, &end, soft);
1425
1426 if (!i)
1427 {
1428
1429 if (NILP (properties))
1430 return Qnil;
1431
1432 i = validate_interval_range (object, &start, &end, hard);
1433
1434 if (!i)
1435 return Qnil;
1436 }
1437
1438 if (BUFFERP (object) && !NILP (coherent_change_p) && first_time)
1439 {
1440 ptrdiff_t prev_length = LENGTH (i);
1441 ptrdiff_t prev_pos = i->position;
1442
1443 modify_text_properties (object, start, end);
1444
1445
1446
1447
1448 if (LENGTH (i) != prev_length || i->position != prev_pos)
1449 {
1450 first_time = false;
1451 goto retry;
1452 }
1453 }
1454
1455 set_text_properties_1 (start, end, properties, object, i);
1456
1457 if (BUFFERP (object) && !NILP (coherent_change_p))
1458 signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start),
1459 XFIXNUM (end) - XFIXNUM (start));
1460 return Qt;
1461 }
1462
1463
1464
1465
1466
1467
1468 void
1469 set_text_properties_1 (Lisp_Object start, Lisp_Object end,
1470 Lisp_Object properties, Lisp_Object object, INTERVAL i)
1471 {
1472
1473
1474
1475 if (BUFFERP (object) && XBUFFER (object) != current_buffer)
1476 {
1477 specpdl_ref count = SPECPDL_INDEX ();
1478 record_unwind_current_buffer ();
1479 set_buffer_internal (XBUFFER (object));
1480
1481 set_text_properties_1 (start, end, properties, object, i);
1482 unbind_to (count, Qnil);
1483 return;
1484 }
1485
1486 INTERVAL prev_changed = NULL;
1487 ptrdiff_t s = XFIXNUM (start);
1488 ptrdiff_t len = XFIXNUM (end) - s;
1489
1490 if (len == 0)
1491 return;
1492 eassert (0 < len);
1493
1494 eassert (i);
1495
1496 if (i->position != s)
1497 {
1498 INTERVAL unchanged = i;
1499 i = split_interval_right (unchanged, s - unchanged->position);
1500
1501 if (LENGTH (i) > len)
1502 {
1503 copy_properties (unchanged, i);
1504 i = split_interval_left (i, len);
1505 set_properties (properties, i, object);
1506 return;
1507 }
1508
1509 set_properties (properties, i, object);
1510
1511 if (LENGTH (i) == len)
1512 return;
1513
1514 prev_changed = i;
1515 len -= LENGTH (i);
1516 i = next_interval (i);
1517 }
1518
1519
1520 do
1521 {
1522 eassert (i != 0);
1523
1524 if (LENGTH (i) >= len)
1525 {
1526 if (LENGTH (i) > len)
1527 i = split_interval_left (i, len);
1528
1529
1530
1531
1532 set_properties (properties, i, object);
1533 if (prev_changed)
1534 merge_interval_left (i);
1535 return;
1536 }
1537
1538 len -= LENGTH (i);
1539
1540
1541
1542
1543 set_properties (properties, i, object);
1544 if (!prev_changed)
1545 prev_changed = i;
1546 else
1547 prev_changed = i = merge_interval_left (i);
1548
1549 i = next_interval (i);
1550 }
1551 while (len > 0);
1552 }
1553
1554 DEFUN ("remove-text-properties", Fremove_text_properties,
1555 Sremove_text_properties, 3, 4, 0,
1556 doc:
1557
1558
1559
1560
1561
1562
1563
1564
1565 )
1566 (Lisp_Object start, Lisp_Object end, Lisp_Object properties, Lisp_Object object)
1567 {
1568
1569
1570
1571 if (BUFFERP (object) && XBUFFER (object) != current_buffer)
1572 {
1573 specpdl_ref count = SPECPDL_INDEX ();
1574 record_unwind_current_buffer ();
1575 set_buffer_internal (XBUFFER (object));
1576 return unbind_to (count,
1577 Fremove_text_properties (start, end, properties,
1578 object));
1579 }
1580
1581 INTERVAL i, unchanged;
1582 ptrdiff_t s, len;
1583 bool modified = false;
1584 bool first_time = true;
1585
1586 if (NILP (object))
1587 XSETBUFFER (object, current_buffer);
1588
1589 retry:
1590 i = validate_interval_range (object, &start, &end, soft);
1591 if (!i)
1592 return Qnil;
1593
1594 s = XFIXNUM (start);
1595 len = XFIXNUM (end) - s;
1596
1597
1598 if (! interval_has_some_properties (properties, i))
1599 {
1600 ptrdiff_t got = LENGTH (i) - (s - i->position);
1601
1602 do
1603 {
1604 if (got >= len)
1605 return Qnil;
1606 len -= got;
1607 i = next_interval (i);
1608 got = LENGTH (i);
1609 }
1610 while (! interval_has_some_properties (properties, i));
1611 }
1612
1613
1614 else if (i->position != s)
1615 {
1616 unchanged = i;
1617 i = split_interval_right (unchanged, s - unchanged->position);
1618 copy_properties (unchanged, i);
1619 }
1620
1621 if (BUFFERP (object) && first_time)
1622 {
1623 ptrdiff_t prev_total_length = TOTAL_LENGTH (i);
1624 ptrdiff_t prev_pos = i->position;
1625
1626 modify_text_properties (object, start, end);
1627
1628
1629
1630
1631
1632
1633 if (TOTAL_LENGTH (i) != prev_total_length
1634 || i->position != prev_pos)
1635 {
1636 first_time = false;
1637 goto retry;
1638 }
1639 }
1640
1641
1642 for (;;)
1643 {
1644 eassert (i != 0);
1645
1646 if (LENGTH (i) >= len)
1647 {
1648 if (! interval_has_some_properties (properties, i))
1649 {
1650 eassert (modified);
1651 if (BUFFERP (object))
1652 signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start),
1653 XFIXNUM (end) - XFIXNUM (start));
1654 return Qt;
1655 }
1656
1657 if (LENGTH (i) == len)
1658 {
1659 remove_properties (properties, Qnil, i, object);
1660 if (BUFFERP (object))
1661 signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start),
1662 XFIXNUM (end) - XFIXNUM (start));
1663 return Qt;
1664 }
1665
1666
1667 unchanged = i;
1668 i = split_interval_left (i, len);
1669 copy_properties (unchanged, i);
1670 remove_properties (properties, Qnil, i, object);
1671 if (BUFFERP (object))
1672 signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start),
1673 XFIXNUM (end) - XFIXNUM (start));
1674 return Qt;
1675 }
1676
1677 len -= LENGTH (i);
1678 modified |= remove_properties (properties, Qnil, i, object);
1679 i = next_interval (i);
1680 }
1681 }
1682
1683 DEFUN ("remove-list-of-text-properties", Fremove_list_of_text_properties,
1684 Sremove_list_of_text_properties, 3, 4, 0,
1685 doc:
1686
1687
1688
1689
1690 )
1691 (Lisp_Object start, Lisp_Object end, Lisp_Object list_of_properties, Lisp_Object object)
1692 {
1693
1694
1695
1696 if (BUFFERP (object) && XBUFFER (object) != current_buffer)
1697 {
1698 specpdl_ref count = SPECPDL_INDEX ();
1699 record_unwind_current_buffer ();
1700 set_buffer_internal (XBUFFER (object));
1701 return unbind_to (count,
1702 Fremove_list_of_text_properties (start, end,
1703 list_of_properties,
1704 object));
1705 }
1706
1707 INTERVAL i, unchanged;
1708 ptrdiff_t s, len;
1709 bool modified = false;
1710 Lisp_Object properties;
1711 properties = list_of_properties;
1712
1713 if (NILP (object))
1714 XSETBUFFER (object, current_buffer);
1715
1716 i = validate_interval_range (object, &start, &end, soft);
1717 if (!i)
1718 return Qnil;
1719
1720 s = XFIXNUM (start);
1721 len = XFIXNUM (end) - s;
1722
1723
1724 if (! interval_has_some_properties_list (properties, i))
1725 {
1726 ptrdiff_t got = LENGTH (i) - (s - i->position);
1727
1728 do
1729 {
1730 if (got >= len)
1731 return Qnil;
1732 len -= got;
1733 i = next_interval (i);
1734 got = LENGTH (i);
1735 }
1736 while (! interval_has_some_properties_list (properties, i));
1737 }
1738
1739
1740 else if (i->position != s)
1741 {
1742 unchanged = i;
1743 i = split_interval_right (unchanged, s - unchanged->position);
1744 copy_properties (unchanged, i);
1745 }
1746
1747
1748
1749
1750
1751
1752
1753 for (;;)
1754 {
1755 eassert (i != 0);
1756
1757 if (LENGTH (i) >= len)
1758 {
1759 if (! interval_has_some_properties_list (properties, i))
1760 {
1761 if (modified)
1762 {
1763 if (BUFFERP (object))
1764 signal_after_change (XFIXNUM (start),
1765 XFIXNUM (end) - XFIXNUM (start),
1766 XFIXNUM (end) - XFIXNUM (start));
1767 return Qt;
1768 }
1769 else
1770 return Qnil;
1771 }
1772 else if (LENGTH (i) == len)
1773 {
1774 if (!modified && BUFFERP (object))
1775 modify_text_properties (object, start, end);
1776 remove_properties (Qnil, properties, i, object);
1777 if (BUFFERP (object))
1778 signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start),
1779 XFIXNUM (end) - XFIXNUM (start));
1780 return Qt;
1781 }
1782 else
1783 {
1784 unchanged = i;
1785 i = split_interval_left (i, len);
1786 copy_properties (unchanged, i);
1787 if (!modified && BUFFERP (object))
1788 modify_text_properties (object, start, end);
1789 remove_properties (Qnil, properties, i, object);
1790 if (BUFFERP (object))
1791 signal_after_change (XFIXNUM (start), XFIXNUM (end) - XFIXNUM (start),
1792 XFIXNUM (end) - XFIXNUM (start));
1793 return Qt;
1794 }
1795 }
1796 if (interval_has_some_properties_list (properties, i))
1797 {
1798 if (!modified && BUFFERP (object))
1799 modify_text_properties (object, start, end);
1800 remove_properties (Qnil, properties, i, object);
1801 modified = true;
1802 }
1803 len -= LENGTH (i);
1804 i = next_interval (i);
1805 if (!i)
1806 {
1807 if (modified)
1808 {
1809 if (BUFFERP (object))
1810 signal_after_change (XFIXNUM (start),
1811 XFIXNUM (end) - XFIXNUM (start),
1812 XFIXNUM (end) - XFIXNUM (start));
1813 return Qt;
1814 }
1815 else
1816 return Qnil;
1817 }
1818 }
1819 }
1820
1821 DEFUN ("text-property-any", Ftext_property_any,
1822 Stext_property_any, 4, 5, 0,
1823 doc:
1824
1825
1826
1827
1828 )
1829 (Lisp_Object start, Lisp_Object end, Lisp_Object property, Lisp_Object value, Lisp_Object object)
1830 {
1831 register INTERVAL i;
1832 register ptrdiff_t e, pos;
1833
1834 if (NILP (object))
1835 XSETBUFFER (object, current_buffer);
1836 i = validate_interval_range (object, &start, &end, soft);
1837 if (!i)
1838 return (!NILP (value) || EQ (start, end) ? Qnil : start);
1839 e = XFIXNUM (end);
1840
1841 while (i)
1842 {
1843 if (i->position >= e)
1844 break;
1845 if (EQ (textget (i->plist, property), value))
1846 {
1847 pos = i->position;
1848 if (pos < XFIXNUM (start))
1849 pos = XFIXNUM (start);
1850 return make_fixnum (pos);
1851 }
1852 i = next_interval (i);
1853 }
1854 return Qnil;
1855 }
1856
1857 DEFUN ("text-property-not-all", Ftext_property_not_all,
1858 Stext_property_not_all, 4, 5, 0,
1859 doc:
1860
1861
1862
1863
1864 )
1865 (Lisp_Object start, Lisp_Object end, Lisp_Object property, Lisp_Object value, Lisp_Object object)
1866 {
1867 register INTERVAL i;
1868 register ptrdiff_t s, e;
1869
1870 if (NILP (object))
1871 XSETBUFFER (object, current_buffer);
1872 i = validate_interval_range (object, &start, &end, soft);
1873 if (!i)
1874 return (NILP (value) || EQ (start, end)) ? Qnil : start;
1875 s = XFIXNUM (start);
1876 e = XFIXNUM (end);
1877
1878 while (i)
1879 {
1880 if (i->position >= e)
1881 break;
1882 if (! EQ (textget (i->plist, property), value))
1883 {
1884 if (i->position > s)
1885 s = i->position;
1886 return make_fixnum (s);
1887 }
1888 i = next_interval (i);
1889 }
1890 return Qnil;
1891 }
1892
1893
1894
1895
1896
1897
1898
1899
1900 int
1901 text_property_stickiness (Lisp_Object prop, Lisp_Object pos, Lisp_Object buffer)
1902 {
1903 bool ignore_previous_character;
1904 Lisp_Object prev_pos = make_fixnum (XFIXNUM (pos) - 1);
1905 Lisp_Object front_sticky;
1906 bool is_rear_sticky = true, is_front_sticky = false;
1907 Lisp_Object defalt = Fassq (prop, Vtext_property_default_nonsticky);
1908
1909 if (NILP (buffer))
1910 XSETBUFFER (buffer, current_buffer);
1911
1912 ignore_previous_character = XFIXNUM (pos) <= BUF_BEGV (XBUFFER (buffer));
1913
1914 if (ignore_previous_character || (CONSP (defalt) && !NILP (XCDR (defalt))))
1915 is_rear_sticky = false;
1916 else
1917 {
1918 Lisp_Object rear_non_sticky
1919 = Fget_text_property (prev_pos, Qrear_nonsticky, buffer);
1920
1921 if (!NILP (CONSP (rear_non_sticky)
1922 ? Fmemq (prop, rear_non_sticky)
1923 : rear_non_sticky))
1924
1925 is_rear_sticky = false;
1926 }
1927
1928
1929
1930
1931 front_sticky = Fget_text_property (pos, Qfront_sticky, buffer);
1932
1933 if (EQ (front_sticky, Qt)
1934 || (CONSP (front_sticky)
1935 && !NILP (Fmemq (prop, front_sticky))))
1936
1937 is_front_sticky = true;
1938
1939
1940 if (is_rear_sticky && !is_front_sticky)
1941 return -1;
1942 else if (!is_rear_sticky && is_front_sticky)
1943 return 1;
1944 else if (!is_rear_sticky && !is_front_sticky)
1945 return 0;
1946
1947
1948
1949
1950
1951 if (ignore_previous_character
1952 || NILP (Fget_text_property (prev_pos, prop, buffer)))
1953 return 1;
1954 else
1955 return -1;
1956 }
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969 Lisp_Object
1970 copy_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object src,
1971 Lisp_Object pos, Lisp_Object dest, Lisp_Object prop)
1972 {
1973 INTERVAL i = validate_interval_range (src, &start, &end, soft);
1974 if (!i)
1975 return Qnil;
1976
1977 CHECK_FIXNUM_COERCE_MARKER (pos);
1978
1979 EMACS_INT dest_e = XFIXNUM (pos) + (XFIXNUM (end) - XFIXNUM (start));
1980 if (MOST_POSITIVE_FIXNUM < dest_e)
1981 args_out_of_range (pos, end);
1982 Lisp_Object dest_end = make_fixnum (dest_e);
1983 validate_interval_range (dest, &pos, &dest_end, soft);
1984
1985 ptrdiff_t s = XFIXNUM (start), e = XFIXNUM (end), p = XFIXNUM (pos);
1986
1987 Lisp_Object stuff = Qnil;
1988
1989 while (s < e)
1990 {
1991 ptrdiff_t e2 = i->position + LENGTH (i);
1992 if (e2 > e)
1993 e2 = e;
1994 ptrdiff_t len = e2 - s;
1995
1996 Lisp_Object plist = i->plist;
1997 if (! NILP (prop))
1998 while (! NILP (plist))
1999 {
2000 if (EQ (Fcar (plist), prop))
2001 {
2002 plist = list2 (prop, Fcar (Fcdr (plist)));
2003 break;
2004 }
2005 plist = Fcdr (Fcdr (plist));
2006 }
2007 if (! NILP (plist))
2008
2009
2010 stuff = Fcons (list3 (make_fixnum (p), make_fixnum (p + len), plist),
2011 stuff);
2012
2013 i = next_interval (i);
2014 if (!i)
2015 break;
2016
2017 p += len;
2018 s = i->position;
2019 }
2020
2021 bool modified = false;
2022
2023 while (! NILP (stuff))
2024 {
2025 Lisp_Object res = Fcar (stuff);
2026 res = Fadd_text_properties (Fcar (res), Fcar (Fcdr (res)),
2027 Fcar (Fcdr (Fcdr (res))), dest);
2028 if (! NILP (res))
2029 modified = true;
2030 stuff = Fcdr (stuff);
2031 }
2032
2033 return modified ? Qt : Qnil;
2034 }
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044 Lisp_Object
2045 text_property_list (Lisp_Object object, Lisp_Object start, Lisp_Object end, Lisp_Object prop)
2046 {
2047 struct interval *i;
2048 Lisp_Object result;
2049
2050 result = Qnil;
2051
2052 i = validate_interval_range (object, &start, &end, soft);
2053 if (i)
2054 {
2055 ptrdiff_t s = XFIXNUM (start);
2056 ptrdiff_t e = XFIXNUM (end);
2057
2058 while (s < e)
2059 {
2060 ptrdiff_t interval_end, len;
2061 Lisp_Object plist;
2062
2063 interval_end = i->position + LENGTH (i);
2064 if (interval_end > e)
2065 interval_end = e;
2066 len = interval_end - s;
2067
2068 plist = i->plist;
2069
2070 if (!NILP (prop))
2071 for (; CONSP (plist); plist = Fcdr (XCDR (plist)))
2072 if (EQ (XCAR (plist), prop))
2073 {
2074 plist = list2 (prop, Fcar (XCDR (plist)));
2075 break;
2076 }
2077
2078 if (!NILP (plist))
2079 result = Fcons (list3 (make_fixnum (s), make_fixnum (s + len),
2080 plist),
2081 result);
2082
2083 i = next_interval (i);
2084 if (!i)
2085 break;
2086 s = i->position;
2087 }
2088 }
2089
2090 return result;
2091 }
2092
2093
2094
2095
2096
2097
2098
2099 void
2100 add_text_properties_from_list (Lisp_Object object, Lisp_Object list, Lisp_Object delta)
2101 {
2102 for (; CONSP (list); list = XCDR (list))
2103 {
2104 Lisp_Object item, start, end, plist;
2105
2106 item = XCAR (list);
2107 start = make_fixnum (XFIXNUM (XCAR (item)) + XFIXNUM (delta));
2108 end = make_fixnum (XFIXNUM (XCAR (XCDR (item))) + XFIXNUM (delta));
2109 plist = XCAR (XCDR (XCDR (item)));
2110
2111 Fadd_text_properties (start, end, plist, object);
2112 }
2113 }
2114
2115
2116
2117
2118
2119
2120
2121
2122 Lisp_Object
2123 extend_property_ranges (Lisp_Object list, Lisp_Object old_end, Lisp_Object new_end)
2124 {
2125 Lisp_Object prev = Qnil, head = list;
2126 ptrdiff_t max = XFIXNUM (new_end);
2127
2128 for (; CONSP (list); prev = list, list = XCDR (list))
2129 {
2130 Lisp_Object item, beg;
2131 ptrdiff_t end;
2132
2133 item = XCAR (list);
2134 beg = XCAR (item);
2135 end = XFIXNUM (XCAR (XCDR (item)));
2136
2137 if (XFIXNUM (beg) >= max)
2138 {
2139
2140
2141 if (EQ (head, list))
2142 head = XCDR (list);
2143 else
2144 XSETCDR (prev, XCDR (list));
2145 }
2146 else if ((end == XFIXNUM (old_end) && end != max)
2147 || end > max)
2148 {
2149
2150
2151
2152
2153
2154 XSETCAR (XCDR (item), new_end);
2155 }
2156 }
2157
2158 return head;
2159 }
2160
2161
2162
2163
2164
2165 static void
2166 call_mod_hooks (Lisp_Object list, Lisp_Object start, Lisp_Object end)
2167 {
2168 while (!NILP (list))
2169 {
2170 call2 (Fcar (list), start, end);
2171 list = Fcdr (list);
2172 }
2173 }
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183 void
2184 verify_interval_modification (struct buffer *buf,
2185 ptrdiff_t start, ptrdiff_t end)
2186 {
2187 INTERVAL intervals = buffer_intervals (buf);
2188 INTERVAL i;
2189 Lisp_Object hooks;
2190 Lisp_Object prev_mod_hooks;
2191 Lisp_Object mod_hooks;
2192
2193 hooks = Qnil;
2194 prev_mod_hooks = Qnil;
2195 mod_hooks = Qnil;
2196
2197 interval_insert_behind_hooks = Qnil;
2198 interval_insert_in_front_hooks = Qnil;
2199
2200 if (!intervals)
2201 return;
2202
2203 if (start > end)
2204 {
2205 ptrdiff_t temp = start;
2206 start = end;
2207 end = temp;
2208 }
2209
2210
2211 if (start == end)
2212 {
2213 INTERVAL prev = NULL;
2214 Lisp_Object before, after;
2215
2216
2217
2218
2219 i = find_interval (intervals, start);
2220
2221 if (start == BUF_BEGV (buf))
2222 prev = 0;
2223 else if (i->position == start)
2224 prev = previous_interval (i);
2225 else if (i->position < start)
2226 prev = i;
2227 if (start == BUF_ZV (buf))
2228 i = 0;
2229
2230
2231
2232 if (NILP (Vinhibit_read_only) || CONSP (Vinhibit_read_only))
2233 {
2234
2235
2236
2237
2238
2239 if (i != prev)
2240 {
2241 if (i)
2242 {
2243 after = textget (i->plist, Qread_only);
2244
2245
2246
2247
2248 if (! NILP (after)
2249 && NILP (Fmemq (after, Vinhibit_read_only)))
2250 {
2251 Lisp_Object tem;
2252
2253 tem = textget (i->plist, Qfront_sticky);
2254 if (TMEM (Qread_only, tem)
2255 || (NILP (plist_get (i->plist, Qread_only))
2256 && TMEM (Qcategory, tem)))
2257 text_read_only (after);
2258 }
2259 }
2260
2261 if (prev)
2262 {
2263 before = textget (prev->plist, Qread_only);
2264
2265
2266
2267
2268 if (! NILP (before)
2269 && NILP (Fmemq (before, Vinhibit_read_only)))
2270 {
2271 Lisp_Object tem;
2272
2273 tem = textget (prev->plist, Qrear_nonsticky);
2274 if (! TMEM (Qread_only, tem)
2275 && (! NILP (plist_get (prev->plist,Qread_only))
2276 || ! TMEM (Qcategory, tem)))
2277 text_read_only (before);
2278 }
2279 }
2280 }
2281 else if (i)
2282 {
2283 after = textget (i->plist, Qread_only);
2284
2285
2286
2287
2288 if (! NILP (after) && NILP (Fmemq (after, Vinhibit_read_only)))
2289 {
2290 Lisp_Object tem;
2291
2292 tem = textget (i->plist, Qfront_sticky);
2293 if (TMEM (Qread_only, tem)
2294 || (NILP (plist_get (i->plist, Qread_only))
2295 && TMEM (Qcategory, tem)))
2296 text_read_only (after);
2297
2298 tem = textget (prev->plist, Qrear_nonsticky);
2299 if (! TMEM (Qread_only, tem)
2300 && (! NILP (plist_get (prev->plist, Qread_only))
2301 || ! TMEM (Qcategory, tem)))
2302 text_read_only (after);
2303 }
2304 }
2305 }
2306
2307
2308 if (prev)
2309 interval_insert_behind_hooks
2310 = textget (prev->plist, Qinsert_behind_hooks);
2311 if (i)
2312 interval_insert_in_front_hooks
2313 = textget (i->plist, Qinsert_in_front_hooks);
2314 }
2315 else
2316 {
2317
2318
2319
2320 i = find_interval (intervals, start);
2321 do
2322 {
2323 if (! INTERVAL_WRITABLE_P (i))
2324 text_read_only (textget (i->plist, Qread_only));
2325
2326 if (!inhibit_modification_hooks)
2327 {
2328 mod_hooks = textget (i->plist, Qmodification_hooks);
2329 if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
2330 {
2331 hooks = Fcons (mod_hooks, hooks);
2332 prev_mod_hooks = mod_hooks;
2333 }
2334 }
2335
2336 if (i->position + LENGTH (i) < end
2337 && (!NILP (BVAR (current_buffer, read_only))
2338 && NILP (Vinhibit_read_only)))
2339 xsignal1 (Qbuffer_read_only, Fcurrent_buffer ());
2340
2341 i = next_interval (i);
2342 }
2343
2344 while (i && i->position < end);
2345
2346 if (!inhibit_modification_hooks)
2347 {
2348 hooks = Fnreverse (hooks);
2349 while (! NILP (hooks))
2350 {
2351 call_mod_hooks (Fcar (hooks), make_fixnum (start),
2352 make_fixnum (end));
2353 hooks = Fcdr (hooks);
2354 }
2355 }
2356 }
2357 }
2358
2359
2360
2361
2362
2363
2364 void
2365 report_interval_modification (Lisp_Object start, Lisp_Object end)
2366 {
2367 if (! NILP (interval_insert_behind_hooks))
2368 call_mod_hooks (interval_insert_behind_hooks, start, end);
2369 if (! NILP (interval_insert_in_front_hooks)
2370 && ! EQ (interval_insert_in_front_hooks,
2371 interval_insert_behind_hooks))
2372 call_mod_hooks (interval_insert_in_front_hooks, start, end);
2373 }
2374
2375 void
2376 syms_of_textprop (void)
2377 {
2378 DEFVAR_LISP ("default-text-properties", Vdefault_text_properties,
2379 doc:
2380
2381 );
2382 Vdefault_text_properties = Qnil;
2383
2384 DEFVAR_LISP ("char-property-alias-alist", Vchar_property_alias_alist,
2385 doc:
2386
2387
2388
2389
2390 );
2391 Vchar_property_alias_alist = Qnil;
2392
2393 DEFVAR_LISP ("inhibit-point-motion-hooks", Vinhibit_point_motion_hooks,
2394 doc:
2395 );
2396 Vinhibit_point_motion_hooks = Qt;
2397
2398 DEFVAR_LISP ("text-property-default-nonsticky",
2399 Vtext_property_default_nonsticky,
2400 doc:
2401
2402
2403
2404
2405
2406 );
2407
2408
2409 Vtext_property_default_nonsticky
2410 = list2 (Fcons (Qsyntax_table, Qt), Fcons (Qdisplay, Qt));
2411
2412 interval_insert_behind_hooks = Qnil;
2413 interval_insert_in_front_hooks = Qnil;
2414 staticpro (&interval_insert_behind_hooks);
2415 staticpro (&interval_insert_in_front_hooks);
2416
2417
2418
2419 DEFSYM (Qfont, "font");
2420 DEFSYM (Qface, "face");
2421 DEFSYM (Qread_only, "read-only");
2422 DEFSYM (Qinvisible, "invisible");
2423 DEFSYM (Qintangible, "intangible");
2424 DEFSYM (Qcategory, "category");
2425 DEFSYM (Qlocal_map, "local-map");
2426 DEFSYM (Qfront_sticky, "front-sticky");
2427 DEFSYM (Qrear_nonsticky, "rear-nonsticky");
2428 DEFSYM (Qmouse_face, "mouse-face");
2429 DEFSYM (Qminibuffer_prompt, "minibuffer-prompt");
2430
2431
2432
2433 DEFSYM (Qpoint_left, "point-left");
2434 DEFSYM (Qpoint_entered, "point-entered");
2435
2436 defsubr (&Stext_properties_at);
2437 defsubr (&Sget_text_property);
2438 defsubr (&Sget_char_property);
2439 defsubr (&Sget_char_property_and_overlay);
2440 defsubr (&Snext_char_property_change);
2441 defsubr (&Sprevious_char_property_change);
2442 defsubr (&Snext_single_char_property_change);
2443 defsubr (&Sprevious_single_char_property_change);
2444 defsubr (&Snext_property_change);
2445 defsubr (&Snext_single_property_change);
2446 defsubr (&Sprevious_property_change);
2447 defsubr (&Sprevious_single_property_change);
2448 defsubr (&Sadd_text_properties);
2449 defsubr (&Sput_text_property);
2450 defsubr (&Sset_text_properties);
2451 defsubr (&Sadd_face_text_property);
2452 defsubr (&Sremove_text_properties);
2453 defsubr (&Sremove_list_of_text_properties);
2454 defsubr (&Stext_property_any);
2455 defsubr (&Stext_property_not_all);
2456 }