How can I get the previous-or-equal single property change for a given property? For example, assume AAA, BBB, and CCC below have different faces.


Here is the return value that I would like to get for each position:


Contrast to what previous-single-char-property-change returns:


Essentially, the problem is that (previous-single-char-property-change (point-max) 'face) returns 4 instead of 7. I thought I could just use (previous-single-char-property-change (1+ (point) 'face) instead, but that breaks on (point-max), unfortunately.

How can I achieve get the previous-or-equal single char property change, taking into account the starting position?

Here is some code to reproduce the example:

(with-current-buffer (get-buffer-create "*test*")
  (insert "AAABBBCCC")
  (mapc #'delete-overlay (overlays-in (point-min) (point-max)))
  (overlay-put (make-overlay 1 4) 'face '(:background "red"))
  (overlay-put (make-overlay 4 7) 'face '(:background "blue"))
  (overlay-put (make-overlay 7 10) 'face '(:background "green"))
  (pop-to-buffer (current-buffer)))

Some background: for a major mode that I'm writing I need to read information from the overlay (if any) that precedes (and does not cover) the current point.

  • If point-max is the only place where you have a problem, can't you just make your own version of the function that does what you want and treats (eq (point) (point-max)) as a special case?
    – nispio
    Jun 15 '16 at 2:11
  • The function appears to have changed in the master branch, but I'm not sure when that came about -- here are the arguments I see in the help buffer: (previous-single-char-property-change POSITION PROP &optional OBJECT LIMIT)
    – lawlist
    Jun 15 '16 at 2:41
  • @lawlist: I see these arguments too.
    – Clément
    Jun 15 '16 at 18:30
  • @nispio: I could; it doesn't look very pretty, though. Do you want to make this an answer? I'll certainly upvote it, and I'll accept it if nothing else comes along.
    – Clément
    Jun 15 '16 at 18:30
  • 1
    In my package faceup (an extension to ert for testing font-lock rules) I had the same problem (but for forward searches). Effectively, the function faceup-next-property-change returns point-min if 1) nil was passed as the start position and 2) there were relevant text properties on the first character. Otherwise, the real next position was returned. Jun 16 '16 at 8:04

Something like this should work:

(defun last-prop-change (prop &optional limit)
  (let ((pos+1 (min (1+ (point)) (point-max))))
    (previous-single-char-property-change pos+1 prop nil limit)))


The following is a more complete wrapper than the one given above in that it supports arbitrary positions within object.

;; source: http://emacs.stackexchange.com/a/23989/93
(defun last-single-char-property-change (position prop &optional object limit)
  "Position of the last change of a property before or at POSITION.

This function is just a thin wrapper around
`previous-single-char-property-change', with the POSITION
argument effectively becoming POSITION+1.  This means that if the
PROP property changes at POSITION, then POSITION is returned."
  (let (pos+1)
     ((stringp object)
      (setq pos+1 (min (1+ position) (1- (length object)))))
     ((bufferp object)
      (with-current-buffer object
        (setq pos+1 (min (1+ position) (point-max)))))
      (setq pos+1 (min (1+ position) (point-max)))))
    (previous-single-char-property-change pos+1 prop object limit)))
  • Thanks! Will leave the question open a little longer to see if we get other suggestions.
    – Clément
    Jun 15 '16 at 21:28
  • If that's what OP wants then it can be described as the last change before position point+1.
    – Drew
    Jun 15 '16 at 22:11
  • After testing this a bit more, I think you need one more check, to see if the property is already set on (point-max). Otherwise this returns the wrong result on point-max.
    – Clément
    Jun 18 '16 at 3:21

How can I get the previous single property change for a given property?

You got it.

There is no face property change at position 7. The previous property change for face is at position 4.

(It's not clear why you want what you say you want, or even what it means. This really smells like an X-Y problem. Maybe say what you are really trying to do?)

  • 1
    This is exactly what I'm trying to do. I'm trying to rewind to the previous property change. Which doesn't work at position 4.
    – Clément
    Jun 15 '16 at 18:28
  • I've updated the example.
    – Clément
    Jun 15 '16 at 18:29
  • In other words: as you say, there is a change at position 4. But asking for the previous change at position 4 does not return 4.
    – Clément
    Jun 15 '16 at 18:31
  • Asking for the previous change at position 4 correctly returns the position of the previous change, which is position 1. It's still not clear what you are really asking for. Apparently you are not wanting the previous change at position 4...
    – Drew
    Jun 15 '16 at 22:08
  • Sorry for the misunderstanding :/ Maybe "previous-or-equal" would be clearer? I'm asking for a function that implements the xample that I gave in the original post.
    – Clément
    Jun 15 '16 at 22:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.