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

From: Juri Linkov <[email-masked]>
Date: Wed, 27 Aug 2025 20:14:07 +0300

> 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.

Thanks, good idea.

> 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.

Makes sense.  Can you do the same filtering as in internal-complete-buffer?
For example:

  (seq-filter (lambda (b) (/= (aref (buffer-name b) 0) ?\s)) (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.

Changing the default text to not mention RET would be nice.

> @@ -1853,14 +1853,20 @@ multi-occur
>    (interactive
>     (cons
>      (let* ((bufs (list (read-buffer "First buffer to search: "
> -				    (current-buffer) t)))
> +                                    (current-buffer))))

I wonder why you removed t from the REQUIRE-MATCH arg of read-buffer?
This allows the user to enter an non-existent buffer name.

>        (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)))))

Wouldn't it be more clear here to use 'bufs' instead of 'ido-ignore-item-temp-list'?