3 (defvar *inhibit-point-motion-hooks
* nil
4 "If non-nil, don't run `point-left' and `point-entered' text properties.
5 This also inhibits the use of the `intangible' text property.")
7 ;; This function is not translated well
8 (defun validate-interval-range (object begin end force
)
10 ;; /* If we are asked for a point, but from a subr which operates
11 ;; on a range, then return nothing. */
12 ;; if (EQ (*begin, *end) && begin != end)
13 ;; return NULL_INTERVAL;
15 ;; MOVITZ doesn't have psetf
22 (if (typep object
'buffer
)
24 (when (not (and (<= (buffer-min object
) begin
)
26 (<= end
(buffer-max object
))))
27 (signal 'args-out-of-range
))
28 (setf i
(intervals object
))
29 (when (= (buffer-min object
) (buffer-max object
))
30 (return-from validate-interval-range
(values nil begin end
)))
31 (setf searchpos begin
))
32 (let ((len (length (pstring-data object
))))
33 (when (not (and (<= 0 begin
)
36 (signal 'args-out-of-range
))
37 (setf i
(intervals object
))
39 (return-from validate-interval-range
(values nil begin end
)))
40 (setf searchpos begin
)))
42 (values (find-interval i searchpos
) begin end
)
44 (values (create-root-interval object
) begin end
)
45 (values i begin end
)))))
47 (defun validate-plist (list)
48 "/* Validate LIST as a property list. If LIST is not a list, then
49 make one consisting of (LIST nil). Otherwise, verify that LIST is
50 even numbered and thus suitable as a plist. */"
51 (cond ((null list
) nil
)
53 (if (oddp (length list
))
54 (error "odd length property list")
56 (t (list (list list nil
)))))
58 (defun set-text-properties (start end properties
&optional
(object (current-buffer)))
59 (let ((start-bk start
)
62 (setf properties
(validate-plist properties
))
63 ;; If we want no properties for a whole string, get rid of its
65 (when (and (null properties
)
66 (typep object
'pstring
)
68 (= end
(length (pstring-data object
))))
69 (when (null (intervals object
))
70 (return-from set-text-properties t
))
71 (setf (intervals object
) nil
)
72 (return-from set-text-properties t
))
73 (multiple-value-setq (i start end
)
74 (validate-interval-range object start end nil
))
76 (when (null properties
)
77 (return-from set-text-properties nil
))
78 ;; /* Restore the original START and END values because
79 ;; validate_interval_range increments them for strings. */
82 (multiple-value-setq (i start end
)
83 (validate-interval-range object start end t
))
84 ;; /* This can return if start == end. */
86 (return-from set-text-properties nil
)))
89 ;; (when (typep object 'buffer)
90 ;; ;; modify_region (XBUFFER (object), XINT (start), XINT (end));
91 (set-text-properties-1 start end properties object i
)
93 ;; if (BUFFERP (object) && !NILP (signal_after_change_p))
94 ;; signal_after_change (XINT (start), XINT (end) - XINT (start),
95 ;; XINT (end) - XINT (start));
98 (defun add-properties (plist i object
)
99 "Add the properties in plist to interval I. OBJECT should be the
100 string of buffer containing the interval."
101 (declare (ignore object
))
103 (doplist (sym val plist changed
)
104 (let ((found (getf (interval-plist i
) sym
)))
107 ;; record-property-change
108 (when (not (eql found val
))
109 (setf (getf (interval-plist i
) sym
) val
112 ;; record-property-change
113 (setf (getf (interval-plist i
) sym
) val
116 (defun interval-has-all-properties (plist i
)
117 "/* Return nonzero if interval I has all the properties, with the same
118 values, of list PLIST. */"
119 (doplist (sym val plist t
)
120 (let ((found (getf (interval-plist i
) sym
)))
122 (when (not (eql found val
))
123 (return-from interval-has-all-properties nil
))
124 (return-from interval-has-all-properties nil
)))))
126 (defun add-text-properties (start end properties
&optional
(object (current-buffer)))
127 "Add properties to the text from START to END. The third argument
128 PROPERTIES is a property list specifying the property values to add.
129 If the optional fourth argument OBJECT is a buffer (or nil, which
130 means the current buffer), START and END are buffer positions
131 (integers or markers). If OBJECT is a string, START and END are
132 0-based indices into it. Return t if any property value actually
133 changed, nil otherwise."
134 (let ((len (- end start
))
137 (setf properties
(validate-plist properties
))
138 (when (null properties
)
139 (return-from add-text-properties nil
))
140 (multiple-value-setq (i start end
) (validate-interval-range object start end t
))
142 (return-from add-text-properties nil
))
143 ;; If we're not starting on an interval boundary, we have to split
145 (when (/= (interval-pt i
) start
)
146 (if (interval-has-all-properties properties i
)
147 (let ((got (- (interval-text-length i
) (- start
(interval-pt i
)))))
149 (return-from add-text-properties nil
))
151 (setf i
(next-interval i
)))
154 (setf i
(split-interval-right unchanged
(- start
(interval-pt unchanged
))))
155 (copy-properties unchanged i
))))
156 ;; if (BUFFERP (object))
157 ;; modify_region (XBUFFER (object), XINT (start), XINT (end));
159 ;; We are at the beginning of interval I, with LEN chars to scan.
163 (when (>= (interval-text-length i
) len
)
164 (when (interval-has-all-properties properties i
)
165 (return-from add-text-properties modified
))
166 (when (= (interval-text-length i
) len
)
167 (add-properties properties i object
)
168 (return-from add-text-properties t
))
170 i
(split-interval-left unchanged len
))
171 (copy-properties unchanged i
)
172 (add-properties properties i object
)
173 (return-from add-text-properties t
))
174 (decf len
(interval-text-length i
))
175 (setf modified
(add-properties properties i object
)
176 i
(next-interval i
)))))
178 (defun put-text-property (start end property value object
)
179 "Set one property of the text from START to END. The third and
180 fourth arguments PROPERTY and VALUE specify the property to add. If
181 the optional fifth argument OBJECT is a buffer (or nil, which means
182 the current buffer), START and END are buffer positions (integers or
183 markers). If OBJECT is a string, START and END are 0-based indices
185 (add-text-properties start end
(list property value
) object
))
187 (defun remove-properties (plist list i object
)
188 (declare (ignore object
))
189 (doplist (sym val plist
)
190 (declare (ignore val
))
191 (remf sym
(interval-plist i
)))
193 (remf sym
(interval-plist i
))))
195 (defun remove-text-properties (start end properties
&optional
(object (current-buffer)))
196 "Remove some properties from text from START to END. The third
197 argument PROPERTIES is a property list whose property names specify
198 the properties to remove. \(The values stored in PROPERTIES are
199 ignored.) If the optional fourth argument OBJECT is a buffer (or nil,
200 which means the current buffer), START and END are buffer positions
201 (integers or markers). If OBJECT is a string, START and END are
202 0-based indices into it. Return t if any property was actually
203 removed, nil otherwise.
205 Use set-text-properties if you want to remove all text properties."
206 (let (i unchanged len
(modified nil
))
207 (multiple-value-setq (i start end
)
208 (validate-interval-range object start end nil
))
210 (return-from remove-text-properties nil
))
211 (setf len
(- end start
))
212 (when (/= (interval-pt i
) start
)
213 (if (not (interval-has-all-properties properties i
))
214 (let ((got (- (interval-text-length i
) (- start
(interval-pt i
)))))
216 (return-from remove-text-properties nil
))
218 (setf i
(next-interval i
)))
221 i
(split-interval-right unchanged
(- start
(interval-pt unchanged
))))
222 (copy-properties unchanged i
))))
226 (when (>= (interval-text-length i
) len
)
227 (unless (interval-has-all-properties properties i
)
228 (return-from remove-text-properties modified
))
229 (when (= (interval-text-length i
) len
)
230 (remove-properties properties nil i object
)
231 (return-from remove-text-properties t
))
233 i
(split-interval-left i len
))
234 (copy-properties unchanged i
)
235 (remove-properties properties nil i object
)
236 (return-from remove-text-properties t
))
237 (decf len
(interval-text-length i
))
238 (setf modified
(remove-properties properties nil i object
)
239 i
(next-interval i
)))))
241 (defun text-properties-at (position &optional
(object (current-buffer)))
242 (multiple-value-bind (i position
) (validate-interval-range object position position t
)
244 ;; If POSITION is at the end of the interval,
245 ;; it means it's the end of OBJECT.
246 ;; There are no properties at the very end,
247 ;; since no character follows.
248 (unless (= position
(+ (interval-text-length i
) (interval-pt i
)))
249 (interval-plist i
)))))
251 (defun get-text-property (position prop
&optional
(object (current-buffer)))
252 (getf (text-properties-at position object
) prop
))
254 (defun get-char-property-and-overlay (position prop object overlay
)
255 (declare (ignore overlay
))
256 (get-text-property position prop object
))
258 (defun get-char-property (position prop
&optional
(object (current-buffer)))
259 (get-char-property-and-overlay position prop object
0))
261 (defun previous-property-change (position &optional
(object (current-buffer)) limit
)
262 "Return the position of previous property change.
263 Scans characters backwards from POSITION in OBJECT till it finds
264 a change in some text property, then returns the position of the change.
265 If the optional second argument OBJECT is a buffer (or nil, which means
266 the current buffer), POSITION is a buffer position (integer or marker).
267 If OBJECT is a string, POSITION is a 0-based index into it.
268 Return nil if the property is constant all the way to the start of OBJECT.
269 If the value is non-nil, it is a position less than POSITION, never equal.
271 If the optional third argument LIMIT is non-nil, don't search
272 back past position LIMIT; return LIMIT if nothing is found until LIMIT."
274 (multiple-value-setq (i position
) (validate-interval-range object position position nil
))
276 (return-from previous-property-change limit
))
277 (when (= (interval-pt i
) position
)
278 (setf i
(previous-interval i
)))
279 (setf previous
(previous-interval i
))
281 (intervals-equal previous i
)
283 (> (+ (interval-pt previous
)
284 (interval-text-length previous
))
286 (setf previous
(previous-interval previous
)))
287 ;; FIXME: this code needs cleaning
288 (when (null previous
)
289 (return-from previous-property-change limit
))
290 (setf limit
(or limit
291 (cond ((typep object
'pstring
) 0)
292 ((typep object
'buffer
) (buffer-min object
)))))
293 (when (<= (+ (interval-pt previous
) (interval-text-length previous
))
295 (return-from previous-property-change limit
))
296 (+ (interval-pt previous
) (interval-text-length previous
))))
298 (defun next-property-change (position &optional object limit
)
299 "Return the position of next property change.
300 Scans characters forward from POSITION in OBJECT till it finds
301 a change in some text property, then returns the position of the change.
302 If the optional second argument OBJECT is a buffer (or nil, which means
303 the current buffer), POSITION is a buffer position (integer or marker).
304 If OBJECT is a string, POSITION is a 0-based index into it.
305 Return nil if the property is constant all the way to the end of OBJECT.
306 If the value is non-nil, it is a position greater than POSITION, never equal.
308 If the optional third argument LIMIT is non-nil, don't search
309 past position LIMIT; return LIMIT if nothing is found before LIMIT."
311 (multiple-value-setq (i position
) (validate-interval-range object position position nil
))
313 (setf next
(if (null i
)
316 (setf position
(if (null next
)
317 (cond ((typep object
'pstring
) (pstring-length object
))
318 ((typep object
'buffer
) (buffer-max object
)))
320 (return-from next-property-change position
))
323 (return-from next-property-change limit
))
324 (setf next
(next-interval i
))
326 (intervals-equal i next
)
328 (< (interval-pt next
)
330 (setf next
(next-interval next
)))
332 (return-from next-property-change limit
))
334 (setf limit
(cond ((typep object
'pstring
) (pstring-length object
))
335 ((typep object
'buffer
) (buffer-max object
)))))
336 (unless (< (interval-pt next
) limit
)
337 (return-from next-property-change limit
))
338 ;; FIXME: This is silly code.
339 (setf position
(interval-pt next
))
342 (defun next-char-property-change (position &optional limit
(buffer (current-buffer)))
343 "Return the position of next text property or overlay change.
344 This scans characters forward in the current buffer from POSITION till
345 it finds a change in some text property, or the beginning or end of an
346 overlay, and returns the position of that.
347 If none is found, the function returns (point-max).
349 If the optional third argument LIMIT is non-nil, don't search
350 past position LIMIT; return LIMIT if nothing is found before LIMIT."
351 ;; temp = Fnext_overlay_change (position);
352 (next-property-change position buffer
(or limit
(buffer-max buffer
))))
354 (defun next-single-property-change (position prop
&optional
(object (current-buffer)) limit
)
355 (let (i next here-val
)
356 (multiple-value-setq (i position
)
357 (validate-interval-range object position position nil
))
359 (return-from next-single-property-change limit
))
360 (setf here-val
(getf (interval-plist i
) prop
)
361 next
(next-interval i
))
362 ;; walk the intervals til we find one with a different plist val
365 (eql here-val
(getf (interval-plist next
) prop
))
367 (< (interval-pt next
) limit
)))
368 (setf next
(next-interval next
)))
369 ;; FIXME: this code should be cleaned.
371 (return-from next-single-property-change limit
))
372 (setf limit
(or limit
373 (cond ((typep object
'pstring
) (pstring-length object
))
374 ((typep object
'buffer
) (buffer-max object
)))))
375 (when (>= (interval-pt next
) limit
)
376 (return-from next-single-property-change limit
))
379 (defun previous-single-property-change (position prop
&optional
(object (current-buffer)) limit
)
380 (let (i previous here-val
)
381 (multiple-value-setq (i position
) (validate-interval-range object position position nil
))
383 (= (interval-pt i
) position
))
384 (setf i
(previous-interval i
)))
386 (return-from previous-single-property-change limit
))
387 (setf here-val
(getf (interval-plist i
) prop
)
388 previous
(previous-interval i
))
390 (eql here-val
(getf (interval-plist previous
) prop
))
392 (> (+ (interval-pt previous
) (interval-text-length previous
))
394 (setf previous
(previous-interval previous
)))
395 ;; FIXME: this code should be cleaned.
396 (when (null previous
)
397 (return-from previous-single-property-change limit
))
398 (setf limit
(or limit
399 (cond ((typep object
'pstring
) 0)
400 ((typep object
'buffer
) (buffer-min object
)))))
401 (when (<= (+ (interval-pt previous
) (interval-text-length previous
))
403 (return-from previous-single-property-change limit
))
404 (+ (interval-pt previous
) (interval-text-length previous
))))
406 (defun previous-char-property-change (position &optional limit
(buffer (current-buffer)))
407 "Return the position of previous text property or overlay change.
408 Scans characters backward in the current buffer from POSITION till it
409 finds a change in some text property, or the beginning or end of an
410 overlay, and returns the position of that.
411 If none is found, the function returns (point-max).
413 If the optional third argument LIMIT is non-nil, don't search
414 past position LIMIT; return LIMIT if nothing is found before LIMIT."
415 (previous-property-change position buffer
(or limit
(buffer-min buffer
))))
417 (defun next-single-char-property-change (position prop
&optional
(object (current-buffer)) limit
)
418 "/* Return the position of next text property or overlay change for a specific property.
419 Scans characters forward from POSITION till it finds
420 a change in the PROP property, then returns the position of the change.
421 If the optional third argument OBJECT is a buffer (or nil, which means
422 the current buffer), POSITION is a buffer position (integer or marker).
423 If OBJECT is a string, POSITION is a 0-based index into it.
425 The property values are compared with `eql' by default.
426 If the property is constant all the way to the end of OBJECT, return the
427 last valid position in OBJECT.
428 If the optional fourth argument LIMIT is non-nil, don't search
429 past position LIMIT; return LIMIT if nothing is found before LIMIT. */"
430 (if (typep object
'pstring
)
432 (setf position
(next-single-property-change position prop object limit
))
435 (setf position
(pstring-length object
))
436 (setf position limit
))))
437 (let ((initial-value (get-char-property position prop object
))
439 ;; (when (and (typep object 'buffer)
440 ;; (not (eq object (current-buffer))))
443 (setf limit
(buffer-max object
)))
445 (setf position
(next-char-property-change position limit object
))
446 (when (>= position limit
)
448 (setf value
(get-char-property position prop object
))
449 (unless (eq value initial-value
)
450 (return position
))))))
452 (defun previous-single-char-property-change (position prop
&optional
(object (current-buffer)) limit
)
453 (cond ((typep object
'pstring
)
454 (setf position
(previous-single-property-change position prop object limit
))
455 (when (null position
)
456 (setf position
(or limit
457 (pstring-length object
)))))
460 (setf limit
(buffer-min object
)))
461 (if (<= position limit
)
462 (setf position limit
)
463 (let ((initial-value (get-char-property (1- position
) prop object
))
466 (setf position
(previous-char-property-change position limit object
))
467 (when (<= position limit
)
469 (setf value
(get-char-property (1- position
) prop object
))
470 (unless (eq value initial-value
)
471 (return position
))))))))
473 (defun text-property-stickiness (prop pos
&optional
(buffer (current-buffer)))
474 "Return the direction from which the text-property PROP would be
475 inherited by any new text inserted at POS: AFTER if it would be
476 inherited from the char after POS, BEFORE if it would be inherited from
477 the char before POS, and NIL if from neither.
478 BUFFER can be either a buffer or nil (meaning current buffer)."
479 (labels ((tmem (sym set
)
480 ;; Test for membership, allowing for t (actually any
481 ;; non-cons) to mean the universal set."
485 (let ((is-rear-sticky t
)
486 (is-front-sticky nil
)
487 prev-pos front-sticky
)
488 (when (> pos
(begv buffer
))
489 ;; Consider previous character.
490 (setf prev-pos
(1- pos
))
491 (let ((rear-non-sticky (get-text-property prev-pos
'rear-nonsticky buffer
)))
492 (when (tmem prop rear-non-sticky
)
493 ;; PROP is rear-non-sticky
494 (setf is-rear-sticky nil
))))
495 ;; Consider following character.
496 (setf front-sticky
(get-text-property pos
'front-sticky buffer
))
497 (when (or (eq front-sticky t
)
498 (and (consp front-sticky
)
499 (find prop front-sticky
)))
500 ;; PROP is inherited from after
501 (setf is-front-sticky t
))
504 ;; Simple cases, where the properties are consistent.
506 (not is-front-sticky
))
508 ((and (not is-rear-sticky
)
511 ((and (not is-rear-sticky
)
512 (not is-front-sticky
))
514 ((or (= pos
(begv buffer
))
515 (null (get-text-property prev-pos prop buffer
)))
520 (provide :lice-0.1
/textprop
)