Subject: bug#79310: [PATCH] Filter out selected buffers in multi-occur

From: Gabriel do Nascimento Ribeiro <[email-masked]>
Date: Mon, 25 Aug 2025 15:53:51 +0000

The proposed patch below adds a predicate function to read-buffer in multi-occur
to filter out previous selected buffers.  The current behavior does not have
such filter, allowing users to select the same buffer over and over, which can
be confusing when selecting multiple buffers, since users should keep in memory
what they have already selected, and shows duplicated results in the *Occur*
buffer.  I don't see a reason for the current behavior, so I propose the patch
below.

Potential improvements:

1) When the buffer list is empty (user has selected all the buffers), it could
skip the read-buffer and go directly to next step (ask 'List lines matching
regexp').  Not sure how to implement it, since internal-complete-buffer does
some filtering of Vbuffer_alist to remove internal buffers, and I could not find
an easy way to get the length of this filtered buffer list.

2) I believe multi-occur--prompt is not very accurate in case an user changes or
remaps related functions in minibuffer.  For instance, I use
icomplete-vertical-mode with different keybindings, but it always show '(RET to
end)'.  We could make it smarter, or change the prompt to indicate that an empty
string terminates the buffer selection instead of trying to guess the
keybinding.

>From e3c2932ee551db6a008f078579ae6550356647fb Mon Sep 17 00:00:00 2001
From: Gabriel Ribeiro <[email-masked]>
Date: Mon, 25 Aug 2025 12:38:12 -0300
Subject: [PATCH] Filter out already selected buffers in multi-occur

* lisp/replace.el (multi-occur): Add predicate to
read-buffer to filter out previous selected buffers.
---
 lisp/replace.el | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/lisp/replace.el b/lisp/replace.el
index 8227056e012..03b274c59af 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -1853,14 +1853,20 @@ multi-occur
   (interactive
    (cons
     (let* ((bufs (list (read-buffer "First buffer to search: "
-				    (current-buffer) t)))
-	   (buf nil)
-	   (ido-ignore-item-temp-list bufs))
+                                    (current-buffer))))
+           (ido-ignore-item-temp-list bufs)
+           (buf nil))
       (while (not (string-equal
-		   (setq buf (read-buffer (multi-occur--prompt) nil t))
-		   ""))
-	(cl-pushnew buf bufs)
-	(setq ido-ignore-item-temp-list bufs))
+                   (setq buf (read-buffer
+                              (multi-occur--prompt)
+                              nil t
+                              (lambda (b)
+                                (not (member
+                                      (if (stringp b) b (car b))
+                                      ido-ignore-item-temp-list)))))
+                   ""))
+        (cl-pushnew buf bufs)
+        (setq ido-ignore-item-temp-list bufs))
       (nreverse (mapcar #'get-buffer bufs)))
     (occur-read-primary-args)))
   (occur-1 regexp nlines bufs))
-- 
2.34.1

---
Gabriel