0

My goal is to delete all duplicate overlay values from a list, and then remove every overlay in the buffer with values equal to each remaining element in the list.

I am having trouble understanding why remove-overlays does not remove every overlay in the buffer containing a specific value. What appears to be happening is that remove-overlays removes just the first overlay it finds matching that specific value, and then it moves on to the next task without deleting the remainder of overlays with that same value.

I would like to delete duplicate values from the list using (delq nil (delete-dups ov-list)).

EXAMPLE

A test buffer contains the following text on the first line in the buffer:

############################

The code I am using is as follows:

(let* (ov-value ov-list overlay limit char-at-point)
  (save-excursion
    (goto-char (point-min))
    (setq limit (point-at-eol))
    (while (re-search-forward "#" limit t)
      (setq character (char-after (point)))
      (setq overlay (make-overlay (point) (1+ (point))))
      (setq ov-value (concat
          (propertize (char-to-string ?\uFEFF) 'face '(:background "yellow"))
          (propertize (char-to-string character) 'face '(:foreground "green"))))
      (push ov-value ov-list)
      (overlay-put overlay 'display ov-value)))
  (sit-for 2)
  (delq nil (delete-dups ov-list))
  (dolist (ov ov-list)
    (remove-overlays nil nil 'display ov)))
1
  • Try to find a different approach to whatever problem you are trying to solve. You are building a quadratic time algorithm, which is bound to scale poorly to large buffers with many overlays. At best, avoid duplicate overlays in the first place.
    – user227
    Commented Mar 6, 2015 at 8:20

2 Answers 2

1

That is because remove-overlays uses eq when testing an overlay-property's value. But two strings are only equal, if they are the same object.

Usually one adds a symbol property with a constant value, usually t, in order to keep track of one's overlays.

1
  • eq implies equal.
    – politza
    Commented Feb 2, 2015 at 8:05
0

The following snippet is an example of how to remove duplicate overlay objects from a LIST when the text properties are the same:

(require 'cl)

(setq LIST
  (remove-duplicates LIST
    :test (lambda (x y) (or (null y) (equal-including-properties x y)))
    :from-end t))

The following function is an example of how to remove overlays when the value includes text properties.

(defun lawlist-remove-overlays (beg end name val)
"Remove the overlays that are `equal-including-properties`.
Includes a unique situation when an overlay with an `'after-string` property
is at the very end of a narrowed-buffer."
  (let* (
      (point-max (point-max))
      (point-min (point-min))
      (narrowed-p (buffer-narrowed-p))
      (beg (if beg beg point-min))
      (end
        (cond
          ((and
              (not narrowed-p)
              end)
            end)
          ((and
              (not narrowed-p)
              (null end))
            point-max)
          ((and
              narrowed-p
              end
              (< end point-max))
            end)
          ((and
              narrowed-p
              end
              (= end point-max))
            (1+ end))
          ((and
              narrowed-p
              (null end))
            (1+ point-max)) )) )
    (when (and beg end name val)
      (overlay-recenter end)
      (dolist (o (overlays-in beg end))
        (when (equal-including-properties (overlay-get o name) val)
          (delete-overlay o))))))
  • Related threads:

https://stackoverflow.com/a/3817075/2112489

https://emacs.stackexchange.com/a/9836/2287

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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