1

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.

Drew
  • 75,699
  • 9
  • 109
  • 225
randouser
  • 91
  • 7
  • Without writing your own `tab-line-tabs-function` you may be out of luck. See [this thread from help-gnu-emacs@](https://lists.gnu.org/archive/html/help-gnu-emacs/2020-08/msg00047.html). – nega Oct 25 '21 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 '21 at 01: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`](https://www.gnu.org/software/emacs/manual/html_node/elisp/Buffer-List.html) – nega Oct 26 '21 at 02: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 '21 at 10:15

1 Answers1

1

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.

randouser
  • 91
  • 7