Emacs 30.1 highlight - intuitive tab line

Srijan Choudhary Srijan Choudhary
- 2 min read
Tagged: emacs
Emacs NEWS file for 30.1
Emacs NEWS file for 30.1

The first Emacs 30.0.91 pretest for what will be the 30.1 release of Emacs was announced on the mailing list a few days ago. I was going through the NEWS file, and found something that I've wanted in Emacs for a while now.

One of the niggles I had with Emacs was its tab behavior. It worked differently from how other applications that I'm used to work (firefox, kitty, etc).

In emacs, tab-per-buffer can be achieved by using the tab-line-mode. But, before now, it had the following problems:

  1. Since tab-line-mode listed buffers sorted by recently visited, so the order or tabs kept changing
  2. There was no wrap-around when trying to go to the next tab from the last tab

Here's a video showing the old behavior:

A video showing tab-line-mode behavior when switching to next/prev tabs. The tab selection does not wrap around and behaves in an unexpected manner. It also starts showing buffers that have not previously been shown in this window.

To solve this, there is package called intuitive-tab-line-mode that solves the above two problems. But, I had problems with it because it did not work well with the beframe package that I also use.

Now, with Emacs 30.1, this behavior is what comes out-of-the-box with Emacs. The only config needed is to enable global-tab-line-mode. And because it's built-in, it works with other modes like beframe.

A video showing an intuitive tab-line-mode behavior. Tab selection wraps around and only cycles between buffers already showing in current window.

Here's my config for minimal intuitive per-buffer tabs in Emacs >= 30.0.91:

(use-package tab-line
  :demand t
  :bind
  (("C-<iso-lefttab>" . tab-line-switch-to-prev-tab)
   ("C-<tab>" . tab-line-switch-to-next-tab))
  :config
  (global-tab-line-mode 1)
  (setq
   tab-line-new-button-show nil
   tab-line-close-button-show nil))

Here, I've also added keybindings to switch to next/prev tab using C-TAB and C-S-TAB keys.

More details about this change can be found in it's bug report mail thread.

Aside: why show buffers as tabs

One of the common questions is the need to show buffers as tabs at all. After all, in a long running Emacs session, there might be hundreds of buffers, and showing all of them as tabs becomes useless.

For me, I find that I usually work on a 2 to 5 buffers for a "purpose" at a time. These might be some files on a project I'm working on, or org-agenda + a couple of org files, or mu4e-main + headers + one or two emails and a reply. When in this mode, I think looking at all of these buffers in the tab bar gives me a good understanding of where I am in the project and makes it easy to switch to the next or previous buffer easily.

I also use frames and beframe to make sure that only a single "project" is showing in a frame at a time. So, even if there are hundreds of buffers in my Emacs session, only a handful are shown as tabs. This makes it useful to me without overwhelming me with too many tabs.

Interactions

🔁 5 reposts

  • denniot

    Tab is such an incompatible concept with buffers. you would end up with multiple tabs pointing to the same buffers no matter what. 

    Reply
  • aloeveracity9

    Useful for those who use it/want tab line, I suppose. I wonder how many people will try using it now that it's more sensible.

    Reply
  • eric
    eric

    The other alternative is to lean in to the reordering. I set up bindings to select the nth most recent buffer, and modified the display of the tab to have a indication of the binding that will bring it forward. Also I show only up to the most recent, ordered left to right, so the current buffer is always the left-most tab, if that makes sense. I actually sometimes end up using these bindings without even looking when it's one of the top 3 or 4. When I need an older one, I find its tab and bring it forward. It's a nice way to navigate among your most recently visited buffers quickly.

    Reply
  • crocefisso
    crocefisso

    How can I hide a tab by default (e.g. scratch, Message)? Is there an equivalent of intuitive-tab-line-shift-tab-left and intuitive-tab-line-shift-tab-right?

    Reply
    • Srijan
      Srijan

      To hide some tabs, you can define a function and set it as tab-line-tabs-buffer-list-function.

      From what I can see, there is no direct equivalent of intuitive-tab-line-shift-tab-left and right functions. But, functions for that can be good contributions to the code.
      There is the tab-line-mouse-move-tab function that is used to reorder tab positions using mouse drag and drop.

      Reply
  • Tom
    Tom

    I highly recommend the package tabgo: https://github.com/isamert/tabgo.el. It works as described: "Go to tab, avy style."

    Tabgo presents a unified way of navigating among tabs on the tab-line AND the tab-bar. The way to keep many dozens of dozens of buffers under control is to separate your projects by tab-bar tabs. At a level down, tab-line tabs organize your project's buffers.

    Thanks for the tip about intuitive-tab-line-mode. I had not heard of it.

    Reply