Tab Bar Utilities¶
Not to be confused with the tabs you see in editors like VSCode, tab-bar tabs allow for easy switching between different collections of windows - like workspaces.
Here I define all the helper functions and utilities I use in my config that I use when working with tab-bar tabs, for the actual configuration of the tab-bar itself see this section.
Formatting Tabs¶
emacs/lisp/alc-tab-bar.el(defun alc-tab-bar-tab-name-format-hints (name _tab i)
(if tab-bar-tab-hints (concat (format "-%d-" i) "") name))
(defun alc-tab-bar-tab-group-format-function (tab i &optional current-p)
(propertize
(concat (funcall tab-bar-tab-group-function tab))
'face (if current-p 'tab-bar-tab-group-current 'tab-bar-tab-group-inactive)))
Grouping Tabs¶
I’m often switching between multiple projects and I will often have multiple tabs per project, so naturally, I want to group sets of tabs by project.
The emacs-solo/tab-group-from-project function from this article showed that it was possible to group tabs by project, but instead of explicitly moving a tab into the project group, I want tabs to be automatically placed into the correct group as they are created.
After some experimentation I was able to come up with the following function which I bind to C-x t p, overriding the default project-other-tab-command.
emacs/lisp/alc-tab-bar.el(defun alc-tab-bar-project-other-tab-command ()
"Run a project command, displaying resultant buffer in a new tab.
This implemented by hacking together parts of
`project--other-place-prefix' and `other-tab-prefix'.
The only difference between this version and `project-other-tab-command'
is that new tabs are automatically placed in a group named according to
the corresponding project.
"
(interactive)
(prefix-command-preserve-state)
(display-buffer-override-next-command
(lambda (buffer alist)
(cons (progn
(display-buffer-in-tab
buffer (append alist '((tab-group . alc-tab-bar-buffer-to-project-name)
(inhibit-same-window . nil))))
(selected-window))
'tab))
nil "[other-tab]")
(message "Display next project command buffer in a new tab...")
(set-transient-map project-prefix-map))
I don’t know what
prefix-command-preserve-statedoes… butproject--other-place-prefixuses it and the docstring makes it sound importantdisplay-buffer-override-next-commanddoes what the name suggests, changing thedisplay-bufferrules just for the next buffer shown.display-buffer-in-tabaccepts atab-groupoption withalc-tab-bar-buffer-to-project-namereturns the name of the group to place the tab into.set-transient-maplooks very interesting, in this case it takes the given keymap and makes it active just for the next command. However, the docstring looks like it is capable of much more!
Here is the implementation of alc-tab-bar-buffer-to-project-name, it uses the project-name function to return the name of the project associated with the target buffer.
emacs/lisp/alc-tab-bar.el(defun alc-tab-bar-buffer-to-project-name (buffer alist)
"Given BUFFER, return the corresponding project name, if any"
(with-current-buffer buffer
(if-let ((pr (project-current nil)))
(format "[%s]" (project-name pr)))))
Tip
By default
project-namereturns the name of the folder the project is stored in but this can be overriden by setting theproject-vc-namevariable in the project’s.dir-locals.elfile. Often I will set the project name to<owner>/<repo>, for example((nil . ((project-vc-name . "swyddfa/esbonio"))))Since I also use
project-vc-extra-root-markers, most default project names are not that meaningful so I will also include the subriectory in the name((nil . ((project-vc-name . "swyddfa/esbonio [lib/esbonio]"))))
Yes, that means names can be quite long, but they are much more useful to me!
Global Status Items¶
As well as using the tab bar to show… well tabs, the tab-bar-format-global variable can be included in tab-bar-format to show additional information.
Battery Info
emacs/lisp/alc-tab-bar.el(display-battery-mode)
Time
emacs/lisp/alc-tab-bar.el(setq display-time-format "%H:%M %d/%m/%y"
display-time-default-load-average nil)
(display-time-mode)
emacs/lisp/alc-tab-bar.el(provide 'alc-tab-bar)