reddit / emacs
How to prepend the project name to every buffer name in switch-to-buffer?
josior · 2022-05-02 23:54
When working in different projects with files with similar names and structure, it's hard to know from which project each file is when switching buffer (using ivy-switch-buffer).
For example, I have the following files/buffers open:
/project1/Delivery/Package.ext
/project2/Deliveries/Package.ext
I tried to use the Uniquify package to remedy this, I set it to show 1 parent directory like this:
Delivery/Package.ext
Deliveries/Package.ext
But since the projects share similar file names and locations, I don't always remember if the file is from a project or another, and showing more parent directories would take the whole mode-line.
What would be your suggestion to solve this issue?
I thought about placing the project name (from `projectile-project-name`) before all buffers' names, but I'm not sure how to do that.
I also tried `ivy-rich` but I thought it is a bit slow and cluttered. There's also the `bufler` package that I want to try, but it's not installing properly from MELPA, so I'm still looking for a good solution.
My current workaround is to work in different frames, and use `projectile-switch-to-buffer`, but sometimes it would be good to quickly switch in one frame.
Appreciate any help and suggestions. Thanks!
00-11 · 2022-05-03 01:48
One thing you could do, which is a bit orthogonal, is to use bookmarks.
Bookmark names are independent of the names of the bookmarked files. But if you use [*Bookmark+*](https://www.emacswiki.org/emacs/BookmarkPlus) then you can use [*autofiles*](https://www.emacswiki.org/emacs/BookmarkPlus#AutofileBookmarks), which are bookmarks whose names are provided automatically, as the nondirectory part of the file names.
This means you can have multiple bookmarks with the same name, which are differentiated in other ways. In particular, you can [*tag*](https://www.emacswiki.org/emacs/BookmarkPlus#TaggingFiles) bookmarks any way you like (e.g. with project names/info).
----
And if you use [Icicles](https://www.emacswiki.org/emacs/Icicles) then when you use `C-x j a`, to jump to an autofile bookmark, the completion candidates are *composite* ([multi-completions](https://www.emacswiki.org/emacs/Icicles_-_Multi-Completions)): you can match against the bookmark name or the file name or both.
wargxs · 2022-05-03 02:38
With projectile you can show only buffers of the current project ; or limit Ibuffer to the once of the project.
https://docs.projectile.mx/projectile/usage.html
What is the problem with projectile-switch-to-buffer?
https://github.com/purcell/ibuffer-vc could also help
deaddyfreddy · 2022-05-03 07:38
I use `ivy-rich`, works great on my machine. If it's slow for you - try to remove extra transformers and just left a file name and a project
josior · 2022-05-03 11:54
> What is the problem with projectile-switch-to-buffer?
`projectile-switch-to-buffer` helps when I want to switch to a buffer in the same project. My issue is when I have many buffers with similar names/path in different projects, and want to switch between them, I still have to find the other project buffer with `switch-to-buffer`.
`projectile-switch-to-buffer` also lacks some functionality when compared to `ivy-switch-to-buffer`, like the actions available with `M-o` and colorization.
> https://github.com/purcell/ibuffer-vc could also help
I tried that (and the `ibuffer-projectile`), they're good, but they work only in `ibuffer`, not in `switch-to-buffer`.
Thanks for the suggestions!
mclearc · 2022-05-03 14:18
[Tabspaces](https://github.com/mclear-tools/tabspaces) allows you to use `switch-to-buffer` (technically it remaps the keybinding for that function to `tabspaces-switch-to-buffer` so that you get tab/project isolated buffers. It uses the built-in project.el and tab-bar.el to implement this.
EDIT: you might also consider using [Marginalia](https://github.com/minad/marginalia), which does not depend on a specific completion platform (e.g. ido, ivy, vertico, selectrum) but can provide info , including the full path of the file in buffer.
josior · 2022-05-04 00:55
I think `projectile` already has this feature of `tabspaces` but it seems to be a great alternative for those who want to use built-in features instead.
`marginalia` seems to help, though. It doesn't show the project by default, but it seems that I can customize the information that appears in the buffer list. Thanks!
josior · 2022-05-04 00:56
I'll try again, I think I stopped using it because it was slow when using TRAMP, since I'm not using it anymore, it may work. Thanks!
josior · 2022-05-04 00:57
Lots of stuff I never heard about, thanks for the suggestion, though. I'll look into it!
mclearc · 2022-05-04 17:20
>For what it is worth, one difference between tabspaces and projectile's treatment of buffers is that projectile only recognizes buffers tied to a specific project, while you can add any buffer to a tabspace just by opening it in the space.
crawsphi · 2022-05-04 18:13
If you want to do this yourself, you would use a completion "affixation function" (prior to 28, use an "annotation function"; see the manual). This lets you provide auxiliary info to display alongside the candidates. Here's a very simple demonstration:
(defun jos/switch-to-project-buffer ()
"Run `switch-to-buffer' with the projects included as annotations."
(interactive)
(let ((completion-extra-properties
'(:affixation-function
(lambda (buffers)
(mapcar (lambda (buffer)
(list buffer
(concat
(with-current-buffer buffer
(if-let ((proj (project-current)))
(propertize (project-root proj)
'face 'dired-directory)
"<none>"))
" ")
nil))
buffers)))))
(call-interactively #'switch-to-buffer)))
If you wanted the projects to be _after_ the candidates you'd provide a list like `(buffer nil project)` instead from the inner mapping.
(You'll probably need to turn off any mode that's already providing annotations, like ivy-rich or marginalia to see the result.)
josior · 2022-05-04 21:14
Thank you! I'll try it out!
josior · 2022-05-04 21:32
It didn't seem to work. I don't get any error, but the switch-to-buffer doesn't have any annotation.
crawsphi · 2022-05-04 23:43
Using Emacs 28 or later?
What does the value of `(mapcar (lambda (b) (with-current-buffer b (project-current))) (buffer-list))` look like?
josior · 2022-05-04 23:53
> (mapcar (lambda (b) (with-current-buffer b (project-current))) (buffer-list))
No, I'm using Emacs 27.1. The return value of that expression is:
((vc . "~/") (vc . "~/") (vc . "~/") (vc . "~/") (vc . "~/") (vc . "~/") (vc . "~/") (vc . "~/") (vc . "~/") (vc . "~/") (vc . "~/") (vc . "~/") ...)
crawsphi · 2022-05-05 02:13
> No, I'm using Emacs 27.1
Ah, yes, in that case you can't use an affixation function, as I mentioned. It won't be recognized. Swap out the binding of `completion-extra-properties for this:
'(:annotation-function (lambda (buffer)
(concat
" "
(with-current-buffer buffer
(if-let ((proj (project-current)))
(propertize (project-root proj)
'face 'dired-directory)
"<none>")))))
josior · 2022-05-05 22:28
Thanks! It seems to give the same output, though. Here's its current form:
(defun jos/switch-to-project-buffer ()
"Run `switch-to-buffer' with the projects included as annotations."
(interactive)
(let '(:annotation-function (lambda (buffer)
(concat
" "
(with-current-buffer buffer
(if-let ((proj (project-current)))
(propertize (project-root proj)
'face 'dired-directory)
"<none>")))))
(call-interactively #'switch-to-buffer)))
josior · 2022-05-06 21:51
I decided to use ivy-rich for now. I could make the (projectile-project-name) show with marginalia, but since ivy-rich works, I'll keep it for now. Thanks for the help!
crawsphi · 2022-05-07 16:50
You're missing the actual binding :)
(defun jos/switch-to-project-buffer ()
"Run `switch-to-buffer' with the projects included as annotations."
(interactive)
(let ((completion-extra-properties
'(:annotation-function (lambda (buffer)
(concat
" "
(with-current-buffer buffer
(if-let ((proj (project-current)))
(propertize (project-root proj)
'face 'dired-directory)
"<none>")))))))
(call-interactively #'switch-to-buffer)))
but no matter, it was just a simple demo and you say you have found another solution that you like, that is what counts!
josior · 2022-05-07 19:29
Thanks again! It's good to know how I could it without a package too!
crawsphi · 2022-05-14 17:11
You are welcome