For about two months now, I’ve been using
tab-bar-mode in Emacs to have multiple “workspaces” open.
I was fine with buffer switching, too. But
tab-bar-mode not only allows you to switch between buffers, but also window configurations – that means one tab will have 1 window with 1 buffer visiting a file, while another might have a gazillion split panes. So the main upside for me is to arrange stuff into panes aka windows, and then open a new tab to do something in a single-pane view.
One thing I added recently is enumeration of tabs so I can jump to them by number. The default
tab-bar-keymap is activated via C-x t, and I didn’t need C-x t 1–C-x t 9. I remapped these keys to go to tabs 1–9. Note that I leave C-x t 0 to close the current tab and switch to another, similar to how C-x 0 closes a window pane.
But with more than 3 tabs open at the same time, I had to count tabs to make this work. That sucks.
So I tried to insert the tab index into its title. But appending
(9) takes up 3 characters, which is quite a lot even with a variable pitch (aka non-monospaced font).
I eventually settled for prepending a circled unicode character. For reuse, I extracted an association list of integer values to circled unicode number characters:
(defvar ct/circle-numbers-alist '((0 . "⓪") (1 . "①") (2 . "②") (3 . "③") (4 . "④") (5 . "⑤") (6 . "⑥") (7 . "⑦") (8 . "⑧") (9 . "⑨")) "Alist of integers to strings of circled unicode numbers.")
You can use this mapping via e.g.
(alist-get 4 ct/circle-numers-alist) and would get
Now here’s how I modified the tab bar format function to display that (and a couple other things) through basic string concatenation:
(defun ct/tab-bar-tab-name-format-default (tab i) (let ((current-p (eq (car tab) 'current-tab)) (tab-num (if (and tab-bar-tab-hints (< i 10)) (alist-get i ct/circle-numbers-alist) ""))) (propertize (concat tab-num " " (alist-get 'name tab) (or (and tab-bar-close-button-show (not (eq tab-bar-close-button-show (if current-p 'non-selected 'selected))) tab-bar-close-button) "") " ") 'face (funcall tab-bar-tab-face-function tab)))) (setq tab-bar-tab-name-format-function #'ct/tab-bar-tab-name-format-default)
Update 2022-09-19: sorpet pointed out in the comments that you need to enable tab hints:
(setq tab-bar-tab-hints t)
Totally forgot about that!
Update 2022-12-29: I’ve updated my code to use SF Symbols to render the numbers a bit tighter.