abo-abo / swiper

Ivy - a generic completion frontend for Emacs, Swiper - isearch with an overview, and more. Oh, man!
https://oremacs.com/swiper/
2.3k stars 338 forks source link

Way to show EXWM buffers from all frames during counsel-switch-buffer? #3058

Closed anoopemacs closed 1 week ago

anoopemacs commented 1 week ago

I am running emacs with more than one frame. Is there a builtin way to switch to a buffer in any frame. ie C-x b: (The completion list should show candidates from all frames)

I dont want to create any new frames. Hence, the builtin switch-to-buffer-other-frame isnt suitable.

Here's my attempt at adding an advice aroundcounsel-switch-buffer:-

(defun my/counsel-switch-to-buffer-other-frame (buffer)
  "Switch to BUFFER, even if it's displayed in another frame."
  (let* ((wind (get-buffer-window buffer t))
         (frame (window-frame wind)))
    (if wind
        (progn
          (select-frame-set-input-focus frame)
          (select-window wind))
      (switch-to-buffer buffer))))

(defun my/counsel-switch-buffer-advice (orig-fun &rest args)
  "Advice function for `counsel-switch-buffer' to switch across frames."
  (let ((ivy-update-fn
         (lambda ()
           (ivy-update-candidates
            (mapcar #'buffer-name (buffer-list))))))
    (ivy-read "Switch to buffer: "
              #'ivy-update-fn
              :action #'my/counsel-switch-to-buffer-other-frame
              :caller 'counsel-switch-buffer)))

(advice-add 'counsel-switch-buffer :around #'my/counsel-switch-buffer-advice)

PS: wonderful package, soo snappy when compared to helm!

basil-conto commented 1 week ago

Is there a builtin way to switch to a buffer in any frame. ie C-x b: (The completion list should show candidates from all frames)

Just to be clear, this is exactly what counsel-switch-buffer does: it offers as completion candidates all applicable buffers, regardless of whether they're being displayed on the current frame, a different frame, or indeed no live frame at all.

I dont want to create any new frames. Hence, the builtin switch-to-buffer-other-frame isnt suitable.

So am I correct in understanding that what you want is exactly switch-to-buffer-other-frame, except that the selected frame should be reused in the case that the buffer is not already displayed somewhere?

If so, I would suggest looking at some of the buffer display actions under (elisp) Displaying Buffers: e.g. display-buffer-reuse-window, display-buffer-use-some-frame, reusable-frames, pop-up-frames, etc.

For example, you could bind display-buffer-overriding-action around the call to counsel-switch-buffer or its action.

anoopemacs commented 1 week ago

So am I correct in understanding that what you want is exactly switch-to-buffer-other-frame, except that the selected frame should be reused in the case that the buffer is not already displayed somewhere?

Yes, this is exactly what I want.

The problem may be due to me using EXWM. I should have specified this in my original message. Have updated the issue title to include this.

counsel-switch-buffer does not list EXWM buffers that arent on the current frame. However, it does show EXWM buffers that are in the current frame.

Is there some way to confirm this is a bug on the EXWM side and not on the Ivy side? helm-buffers-list does not face this problem. So, this may not be an EXWM issue.

Is it correct to assert that the following two should be equal?

(length (buffer-list)) is 52.

(length (ivy--buffer-list)) is 19.

Even after accounting for ivy-ignore-buffers, the EXWM buffers are missing from the second list.

anoopemacs commented 1 week ago

This fixes my problem:-

(defun my/ivy-switch-buffer ()
  "Switch to another buffer."
  (interactive)
  (ivy-read "Switch to buffer: " (mapcar #'buffer-name (buffer-list))
            :keymap ivy-switch-buffer-map
            :preselect (buffer-name (other-buffer (current-buffer)))
            :action #'ivy--switch-buffer-action
            :matcher #'ivy--switch-buffer-matcher
            :caller 'ivy-switch-buffer))