Automatically detect current buffer’s workspace and prioritize its buffers when using bufler-switch-buffer
For the case where the user hasn’t set the current frame’s workspace, the bufler-switch-buffer
command could automatically find the group the current buffer is in and sort other buffers from that group first.
- https://cestlaz.github.io/post/using-emacs-75-bufler/
- https://www.reddit.com/r/emacs/comments/ixs73j/using_emacs_75_bufler/
i.e. call Bufler like (bufler :groups GROUPS :buffer-name "*Matrix Bufler*")
, and those variables should be set buffer-locally, and refreshing should use those values instead of the global ones. That would allow multiple, unique Bufler buffers.
e.g. the grouping rules should probably be rules
rather than groups
, to distinguish the rules from the groups of buffers that they produce.
Here’s a common scenario:
bufler-list
.- Switch to a buffer showing a file in a project.
- Make changes, save file, switch to
magit-status
, commit. bufler-list
. Even though the file is now up-to-date, it shows asedited
becausevc-state
only gets updated when the buffer is saved, and the buffer hasn’t been saved since it was committed.
Unfortunately, calling vc-state-refresh
every time bufler-list
is updated seems far too slow.
project
is on ELPA, and the version there is newer than the one included with Emacs 26.3, and it declares project-roots
obsolete.
Can probably use with-simulated-input
to do some testing, which will help with refactoring.
The WIP branch works pretty well already.
[2021-09-22 Wed 02:49] Using taxy
will make this much simpler.
Should be covered with taxy-magit-section
, when sorting columns is added to it.
Rather than replacing the tab-bar-tabs-function
and having Bufler groups be the only tabs displayed in the tab bar, selecting a Bufler group would add a tab to the bar, prefixed with Bflr:
. Selecting that tab would set the frame’s bufler-workspace-path
(probably by advising tab-bar-switch-to-tab
). There also needs to be an easy way to make a new tab for a Bufler group.
Selecting a tab bar tab would also cause the tab line to only display buffers in that tab’s Bufler group.
I think this would generally be more useful than the current implementation, but it means completely changing the design.
Also, I’m noticing that the tab bar redisplays from scratch every time Emacs does (i.e. on every keystroke, scroll event, etc.), so having bufler-workspace-mode
active makes redisplay slow. The code will need to be very optimized, and it might need another cache of some kind.
Jonas Bernoulli uses it in epkg-desc.el, and it looks very nice. However, I’m guessing there are reasons he made or uses magit-section
instead.
Of special interest is how it uses display properties to align text in columns. That might be a good alternative to using format
for alignment.
e.g. see Amit’s Thoughts: Emacs: prettier tab-line.
The idea to have buffers appear in multiple groups which they match was mentioned in this comment by Gerry Agbobada. Here’s a rough concept of how the alternative to bufler-group-tree
could work.
(defun group-tree-non-consuming (fns sequence)
(cl-labels ((rec (fns sequence)
(cl-loop for fn in fns
collect (pcase fn
((pred functionp)
(cons fn (cl-loop for item in sequence
when (funcall fn item)
collect item)))
(`(,(and (pred stringp) label) ,(and (pred functionp) fn))
(cons label (cl-loop for item in sequence
when (funcall fn item)
collect item)))
((pred listp)
(cons (get-label (car fn))
(rec (cdr fn) (cl-remove-if-not (get-fn (car fn)) sequence)))))))
(get-fn (fn)
(pcase-exhaustive fn
(`(,(pred stringp) ,(pred functionp))
(cadr fn))
((pred functionp)
fn)))
(get-label (fn)
(pcase-exhaustive fn
(`(,(and (pred stringp) label) ,(pred functionp))
label)
((pred functionp)
fn))))
(rec fns sequence)))
(cl-labels ((<5-p (n) (< n 5)))
(group-tree-non-consuming (list (list (list "< 5" #'<5-p)
(list "even" #'evenp)
(list "non-zero" (-not #'zerop)))
#'evenp)
'(0 1 2 3 4 5 6 7 8 9)))
;; (("< 5"
;; ("even" 0 2 4)
;; ("non-zero" 1 2 3 4))
;; (evenp 0 2 4 6 8))
Was working fine in the prototype, so it should work fine here too. But I want to release 0.2 before making any changes like this.
[2021-09-22 Wed 02:44] Will be covered by using taxy
.
e.g. instead of:
(group-not "*Special*" (group ...) ...)
Something like:
(group-not :name "*Special*" (group ...) ...)
Which should also allow:
(group-not (group ...) ...)
That would provide a lot of flexibility.
[2021-09-22 Wed 02:44] Will be covered by using taxy
.
In these functions. I’d expect cl-loop
to be faster.
(defun bufler-and (name &rest preds)
;; Copied from dash-functional.el.
"Return a grouping function that groups buffers matching all of PREDS.
The resulting group is named NAME. This can also be used with a
single predicate to apply a name to a group."
(byte-compile (lambda (x)
(when (-all? (-cut funcall <> x) preds)
name))))
(defun bufler-or (name &rest preds)
;; Copied from dash-functional.el.
"Return a grouping function that groups buffers matching any of PREDS.
The resulting group is named NAME."
(byte-compile (lambda (x)
(when (-any? (-cut funcall <> x) preds)
name))))
[2021-09-22 Wed 02:45] Will be covered by using taxy
.
From comment:
- A macro like
bufler-defpred
would define a grouping predicate. It would define a function likebufler--predicate-NAME
, and it would add itsmacrolet
form to a variable likebufler-predicates
. - A function like
bufler-define-expand-groups
would define a functionbufler-expand-groups
which would splice in the predicatemacrolet
forms into thecl-macrolet
form. - Users would do something like
(setf bufler-groups (bufler-expand-groups ...))
. - New groups could be added with
bufler-defpred
, which would also callbufler-define-expand-groups
to redefine the expansion function to include the new predicate.
[2021-09-22 Wed 02:49] Will be covered using taxy
.
There should be a companion library to group-tree
that provides the section-based view with columns.
[2021-09-22 Wed 02:52] Covered by taxy-magit-section
.
Sort of like “buffer butler.” Maybe a buffalo for a mascot?
…Yep, works great!
Sort of cute and catchy. Maybe some clip art available.
As Mike Zamansky mentioned, it would be nice to be able to control how the bufler-list
window opens.
- [X] Check comment TODOs (using
magit-todos
). - [X] Check issues.
- [X] Check plans (in this file).
- [X] Check linters.
- [X] Check tests.
- [X] Update version numbers in file headers.
- [X] bufler.el
- [X] helm-bufler.el
- [X] Tag and sign new version (using Magit’s
t r
). - [X] Push
master
. - [X] Push tags.
- [X] Post-release changes:
- [X] Bump version numbers to n+1-pre:
- [X] bufler.el
- [X] helm-bufler.el
- [X] README.org
- [X] Bump version numbers to n+1-pre:
Sometimes changing bufler-groups
doesn’t seem to take effect because buffer-list
hasn’t changed and bufler-buffers
is cached.
I think the big 4 features now are basically:
bufler-list
bufler-switch-buffer
bufler-workspace-mode
bufler-tabs-mode
And while they all work together, they can also be used independently. bufler-list
and bufler-switch-buffer
don’t even require bufler-workspace-mode
to be activated.
- [ ] Check comment TODOs (using
magit-todos
). - [ ] Check issues.
- [ ] Check plans (in this file).
- [ ] Check linters.
- [ ] Check tests.
- [ ] Update version numbers in file headers.
- [ ] bufler.el
- [ ] helm-bufler.el
- [ ] README.org
- [ ] Update changelog in
README.org
. - [ ] Tag and sign new version (using Magit’s
t r
). - [ ] Push
master
. - [ ] Push tags.
- [ ] Post-release changes:
- [ ] Bump version numbers to n+1-pre:
- [ ] bufler.el
- [ ] helm-bufler.el
- [ ] README.org
- [ ] Bump version numbers to n+1-pre: