0

I'm using global-tab-line-mode, and I would like the order of tabs to persist.

Say my buffer/tab order is:

| a.el | b.el | c.el |

and b.el is the current buffer.

If I call (find-file "a.el") the tab order will change to

| b.el | c.el | a.el |

I find this disorienting and would prefer if the tab/buffer order did not change. As well as the order being persistent, I would also very much like it if I could manually change the order (eg move a tab left or right).

Is this possible?

In my config tab-line-tabs-function is set to tab-line-tabs-window-buffers. I have looked in the tab-line-tabs-window-buffers function and think if I can just sort the list it returns at the end I may be able to get the behaviour I want, but have not been able to achieve this.

I also tried setting tab-line-tabs-function to bs-buffer-list, but the sorting in that was even more unpredictable.

Any help greatly appreciated.

4
  • Without writing your own tab-line-tabs-function you may be out of luck. See this thread from help-gnu-emacs@.
    – nega
    Oct 25, 2021 at 16:35
  • Hi - I did see that (although OPs snarky tone turned me off :/ ). Writing a custom tab-line-tabs-function is what I have concluded I need to do. I was just planning to copy tab-line-tabs-window-buffers and then have it sort the tabs at the end of this process, by name for instance. Do you know what code would be needed to sort a list of buffers by name? As per that thread, I'll make a new feature request if I can't get there myself.
    – randouser
    Oct 26, 2021 at 1:19
  • (sort (mapcar #'buffer-name (buffer-list)) #'string<) will get and sort all buffers, including hidden ones. You'll probably just want the list associated w/ a single frame. See buffer-list
    – nega
    Oct 26, 2021 at 2:03
  • Yes indeed. If I apply that to 'tab-line-tabs-window-buffers I get persistent tab order! But, tab-line-switch-to-next-tab and tab-line-switch-to-previous-tab behave very unexpectedly - they do not respect this new order. Looking at bs library to generate a new tab-line-tabs-function and my own function for next/previous tab.
    – randouser
    Oct 27, 2021 at 10:15

1 Answer 1

0

Ok - so I've come up with a solution. It's not too pretty, and it needs polishing, but it works. Keen to hear any suggestions anyone has.

I am declaring a list that is my list of tabs to display, and tab-line-tabs-function draws from this.

  (global-tab-line-mode)
  (setq my/current-tab-list (list (current-buffer)))
  (setq tab-line-tabs-function 'tab-line-tabs-mode-buffers) 
  (defun tab-line-tabs-mode-buffers ()
    my/current-tab-list)

The following function adds new buffers to this list. I add this as a hook to find-file and dired-mode to automatically add new buffers as I open them.

  (defun my/add-current-buffer-to-tab ()
    (interactive)
    (setq my/current-tab-list (add-to-list 'my/current-tab-list (current-buffer)))
    )
  (add-hook 'find-file-hook 'my/add-current-buffer-to-tab)
  (add-hook 'dired-mode-hook 'my/add-current-buffer-to-tab)

To remove a buffer from this list when I close it, I call this custom function.

  (defun my/close-tab ()
    (interactive)
    (setq my/current-tab-list (delete (current-buffer) my/current-tab-list))
    (kill-buffer)
    )

The following functions allow me to manually change the order of the buffers.

  (defun my/shift-tab-left ()
    (interactive)
    (let ((n (seq-position my/current-tab-list (current-buffer))))
      (when
          (> n 0)
        (progn 
          (setq my/current-tab-list
                (append
                 (seq-take my/current-tab-list (- n 1))
                 (list (elt my/current-tab-list n))
                 (list (elt my/current-tab-list (- n 1)))
                 (seq-drop my/current-tab-list (+ n 1))
                 ))))))

    (defun my/shift-tab-right ()
      (interactive)
      (let ((n (seq-position my/current-tab-list (current-buffer))))
        (when
            (< n (- (length my/current-tab-list) 1))
          (progn 
            (setq my/current-tab-list
                  (append
                   (seq-take my/current-tab-list n)
                   (list (elt my/current-tab-list (+ n 1)))
                   (list (elt my/current-tab-list n ))
                   (seq-drop my/current-tab-list (+ n 2))
                   )))))))

Sometimes I want a buffer to be loaded, but not appear in the tab list. For that situation I run the following function:

  (defun my/drop-tab ()
    (interactive)
    (setq my/current-tab-list (delete (current-buffer) my/current-tab-list))
    (switch-to-buffer (nth 0 my/current-tab-list))
    )

And I use tab-line-switch-to-next-tab and tab-line-switch-to-prev-tab to move forwards and backwards.

As I say, needs a bit more polishing, but so far seems to be meeting my needs very nicely and seems robust enough. Sometimes after reordering the tabs it takes a moment to refresh.

Keen for any feedback. Not a programmer, just bodged this together, so will be interested to hear any constructive feedback/elisp rules I have broken.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.