Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switching buffers is based on name, not buffer object #614

Closed
ieure opened this issue Jul 16, 2022 · 5 comments
Closed

Switching buffers is based on name, not buffer object #614

ieure opened this issue Jul 16, 2022 · 5 comments

Comments

@ieure
Copy link

ieure commented Jul 16, 2022

Looking for some thoughts about how tractable it is to solve this. The situation is rather complicated due to all the parts involved.

My setup is:

  • EXWM
  • Some code I wrote which renames the EXWM buffers to reflect the title of the X client, ex. my LibreWolf (a Firefox fork without as much crap) title is New Issue · minad/consult — LibreWolf, and the buffer name is *librewolf: New Issue · minad/consult*.
  • Consult
  • Vertico

When LibreWolf is showing an image, the title includes both the resolution and the scaling, for example 81b3ac08def00915.png (PNG Image, 549 × 2434 pixels) — Scaled (45%).

All of the above behaviors combine to produce frustration:

  1. I pull up the consult buffer swticher.
  2. Vertico makes the minibuffer tall to show the completions.
  3. I type "libre" to select a LibreWolf window.
  4. Consult switches to a LibreWolf buffer showing an image as I type, before I press RET.
  5. The tall minibuffer makes the LibreWolf window shorter, so the scaling of the image changes, so the title changes, so the buffer name changes to ex 81b3ac08def00915.png (PNG Image, 549 × 2434 pixels) — Scaled (39%).
  6. Consult still has the old buffer name, so when I press RET, it tries to switch to a buffer named 81b3ac08def00915.png (PNG Image, 549 × 2434 pixels) — Scaled (45%).
  7. There is no buffer with that name, so it creates a blank one.
  8. I get frustrated.

While there are a few approaches to solving this, I think the most correct is to have Consult either switch based on the buffer object (rather than the name), or make it completely general, by having completions include a lambda to invoke the action.

Based on a cursory reading of the code, it looks like the belief that the buffer is a string name is pretty deeply embedded into Consult.

Is this a thing that seems doable and reasonable? I guess my alternatives are disabling Vertico or going back to the iswitchb setup I've been using for 20 years.

@minad
Copy link
Owner

minad commented Jul 16, 2022

I see. That's an unfortunate interaction of the buffer renaming of EXWM buffers and the Consult preview. I see these solutions:

  1. We could modify consult--source-buffer to use buffer objects instead of strings
  2. Disable preview for consult-buffer
  3. Disable preview only for EXWM buffers (see https://github.com/minad/consult/wiki#do-not-preview-exwm-windows-or-tramp-buffers)
  4. Configure LibreWolf such that it doesn't include all this information in the window title
  5. Don't use consult-buffer, use switch-to-buffer instead. The only difference is that there is no preview. You can still use Vertico.

I am not eager in using buffer objects instead of the buffer names for multiple reasons. Your use case is a rather special edge case. It would be a little bit less efficient and slightly more complicated since we would have to attach the buffer object to the buffer name which is used as completion candidate. Previewing EXWM buffers has other issues anyway if you search through the Consult issue tracker (#178, #186, #204, #537). But the most serious issue is really that strings as completion candidates are ingrained in the design. For example Embark relies on the buffer names when acting on the candidates, e.g. C-. k to kill the currently selected buffer.

@minad
Copy link
Owner

minad commented Jul 16, 2022

I made a little test. I created a command which creates a "volatile" buffer, where the name changes over time. I cannot switch to such a buffer using the Emacs builtin switch-to-buffer after the name has changed. Therefore I think it is quite common assumption that buffer names don't fluctuate wildly and that using the buffer names as identifier in the completion process is justified. Of course I am taking it a bit further here, since I change the buffer name here with time (and not due to a user action/preview). But I could imaging that this scenario could occur with EXWM, e.g., if the window title includes some kind of progress indicator.

(defun make-volatile-buffer ()
  (interactive)
  (let ((buffer (get-buffer-create "*volatile buffer*")))
    (run-at-time 1 1 (lambda ()
                       (with-current-buffer buffer
                         (rename-buffer (format-time-string "*volatile buffer %H:%M:%S*")))))))

@ieure
Copy link
Author

ieure commented Jul 16, 2022

I am not eager in using buffer objects instead of the buffer names for multiple reasons. Your use case is a rather special edge case. It would be a little bit less efficient and slightly more complicated since we would have to attach the buffer object to the buffer name which is used as completion candidate.

Fair enough. Disabling all previewing functionality might be the simplest path forward here, as I personally don't love that behavior. Though it'll still cause problems if an EXWM window is selected, and I want to go back to it, since the completions will have the old name.

Therefore I think it is quite common assumption that buffer names don't fluctuate wildly and that using the buffer names as identifier in the completion process is justified.

I agree that it's a very common assumption, but I believe it's a poor one — though I also get that "completion" implies completion of text. Perhaps completion frameworks aren't a great tool for buffer switching, generally. Certainly, using a property of an object as a proxy for its identity is an inherently lossy proposition, even if it works in most cases.

While my situation is certainly an edge case, I think this is more likely to occur than one might think. For example, uniquify.el is bundled with Emacs (and has been for as long as I can remember) and will change buffer names dynamically based on what other buffers are open. If you have a project with a structure like:

  • src/
    • foo/
      • bar.ext
  • test/
    • foo/
      • bar.ext

If you open src/foo/bar.ext, the buffer name is bar.ext. When you open src/test/bar.ext, the first buffer is renamed to src/bar.ext and the new buffer is named test/bar.ext. If you have one file open, and preview the other one via completing off recentf-list, you'll have the same problem.

@minad
Copy link
Owner

minad commented Jul 16, 2022

Fair enough. Disabling all previewing functionality might be the simplest path forward here, as I personally don't love that behavior. Though it'll still cause problems if an EXWM window is selected, and I want to go back to it, since the completions will have the old name.

Okay, if you don't like preview anyway, there is nothing wrong about disabling it and we have the problem solved here. You can do that globally by setting consult-preview-key to nil or per command via consult-customize.

I am afraid I don't understand what you mean by "going back" where the completion context is still alive. Are you talking about recursive minibuffers?

I agree that it's a very common assumption, but I believe it's a poor one — though I also get that "completion" implies completion of text. Perhaps completion frameworks aren't a great tool for buffer switching, generally. Certainly, using a property of an object as a proxy for its identity is an inherently lossy proposition, even if it works in most cases.

I kind of disagree here. Of course the strings are a lossy representation but it somehow fits well to the spirit of Emacs which is an inherently text based system. But even if we decide to move away from the text representation here, it would be a fight against the established conventions. It would be possible to use the buffer objects instead and it would also be possible to teach Embark about it, but it is just not worth the effort given that these assumptions are so deeply ingrained. We would hit edge cases all over the place.

If you open src/foo/bar.ext, the buffer name is bar.ext. When you open src/test/bar.ext, the first buffer is renamed to src/bar.ext and the new buffer is named test/bar.ext. If you have one file open, and preview the other one via completing off recentf-list, you'll have the same problem.

No, previewed files won't lead to this issue (at least they shouldn't - I didn't test this right now). Consult uses its own specially named buffers for previewed files.

However the issue regarding uniquify exists if you open a file manually with embark-act while keeping the minibuffer alive (embark-quit-after-action=nil). Fortunately Embark offers multiple solutions to avoid this problem. You can either use embark-quit-after-action=t or you can configure Embark to restart the minibuffer, see embark-post-action-hooks. Note that the problem is even more pronounced for Embark actions like delete-file or kill-buffer, where you usually want the minibuffer command to be restarted such that the candidate list is updated and such that no stale candidates stick around.

I think it is okay to close this as wontfix. If you disable preview, the issue you are commonly observing here shouldn't occur anymore and I believe that these other potential issues we've discussed here won't occur often. I mean this whole thing is not perfect, Emacs is a messy hackable system. If you have recursive minibuffers enabled you can always do whatever, executing some random code which messes up some nested state. If it works for common workflows it is good enough.

@minad minad closed this as not planned Won't fix, can't repro, duplicate, stale Jul 16, 2022
@minad minad added the wontfix This will not be worked on label Jul 16, 2022
@minad minad removed the wontfix This will not be worked on label Mar 24, 2024
@minad
Copy link
Owner

minad commented Mar 24, 2024

Buffer renames should now be handled gracefully by consult-buffer. We now keep the buffer objects instead of the buffer names. See #979 and ec232fa.

@minad minad reopened this Mar 24, 2024
@minad minad closed this as completed Mar 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants