diff --git a/etc/NEWS b/etc/NEWS index e6f8eb5ba46..2f90a3067f7 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -370,11 +370,33 @@ By default it contains a keybinding 'C-TAB' to switch tabs, but only when 'C-TAB' is not bound globally. You can unbind it if it conflicts with 'C-TAB' in other modes. +--- +*** New keymap 'tab-line-mode-map'. +By default it contains keybindings for switching tabs: +'C-x ', 'C-x ', 'C-x C-', 'C-x C-'. +You can unbind them if you want to use these keys for the +commands 'previous-buffer' and 'next-buffer'. + +--- +*** Default list of tabs is changed to support a fixed order. +This means that the new default tabs function +'tab-line-tabs-fixed-window-buffers' is like the previous +'tab-line-tabs-window-buffers' where both of them show +only buffers that were previously displayed in the window. +But the difference is that the new function always keeps +the original order of buffers on the tab line, even after +switching between these buffers. + --- *** New user option 'tab-line-tabs-buffer-group-function'. It provides two choices to group tab buffers by major mode and by project name. +--- +*** Now buffers on group tabs are sorted alphabetically. +This will keep the fixed order of tabs, even after +switching between them. + +++ ** New optional argument for modifying directory-local variables. The commands 'add-dir-local-variable', 'delete-dir-local-variable' and diff --git a/lisp/tab-line.el b/lisp/tab-line.el index 48272b7b4b3..09081501705 100644 --- a/lisp/tab-line.el +++ b/lisp/tab-line.el @@ -210,6 +210,11 @@ If the value is a function, call it with no arguments." 'help-echo "Click to add tab") "Button for creating a new tab.") +(defvar tab-line-new-button-functions + '(tab-line-tabs-window-buffers + tab-line-tabs-fixed-window-buffers) + "Functions of `tab-line-tabs-function' for which to show a new button.") + (defcustom tab-line-close-button-show t "Defines where to show the close tab button. If t, show the close tab button on all tabs. @@ -333,18 +338,21 @@ If truncated, append ellipsis per `tab-line-tab-name-ellipsis'." 'help-echo tab-name)))) -(defcustom tab-line-tabs-function #'tab-line-tabs-window-buffers +(defcustom tab-line-tabs-function #'tab-line-tabs-fixed-window-buffers "Function to get a list of tabs to display in the tab line. This function should return either a list of buffers whose names will be displayed, or just a list of strings to display in the tab line. -By default, use function `tab-line-tabs-window-buffers' that -returns a list of buffers associated with the selected window. +By default, use function `tab-line-tabs-fixed-window-buffers' that +returns a list of buffers associated with the selected window where +buffers always keep the original order after switching buffers. When `tab-line-tabs-mode-buffers', return a list of buffers with the same major mode as the current buffer. When `tab-line-tabs-buffer-groups', return a list of buffers grouped by `tab-line-tabs-buffer-group-function'." :type '(choice (const :tag "Window buffers" tab-line-tabs-window-buffers) + (const :tag "Window buffers with fixed order" + tab-line-tabs-fixed-window-buffers) (const :tag "Same mode buffers" tab-line-tabs-mode-buffers) (const :tag "Grouped buffers" @@ -400,9 +408,13 @@ as a group name." :group 'tab-line :version "30.1") -(defvar tab-line-tabs-buffer-group-sort-function nil +(defvar tab-line-tabs-buffer-group-sort-function + #'tab-line-tabs-buffer-group-sort-by-name "Function to sort buffers in a group.") +(defun tab-line-tabs-buffer-group-sort-by-name (a b) + (string< (buffer-name a) (buffer-name b))) + (defvar tab-line-tabs-buffer-groups-sort-function #'string< "Function to sort group names.") @@ -515,6 +527,21 @@ variable `tab-line-tabs-function'." (list buffer) next-buffers))) +(defun tab-line-tabs-fixed-window-buffers () + "Like `tab-line-tabs-window-buffers' but keep stable sorting order. +This means that switching to a buffer previously shown in the same +window will keep the same order of tabs that was before switching. +And newly displayed buffers are added to the end of the tab line." + (let* ((old-buffers (window-parameter nil 'tab-line-fixed-window-buffers)) + (new-buffers (sort (tab-line-tabs-window-buffers) + (lambda (a b) + (< (or (seq-position old-buffers a) + most-positive-fixnum) + (or (seq-position old-buffers b) + most-positive-fixnum)))))) + (set-window-parameter nil 'tab-line-fixed-window-buffers new-buffers) + new-buffers)) + (defcustom tab-line-tab-name-format-function #'tab-line-tab-name-format-default "Function to format a tab name. @@ -599,7 +626,7 @@ This is used by `tab-line-format'." tab-line-right-button))) (if hscroll (nthcdr (truncate hscroll) strings) strings) (list separator) - (when (and (eq tab-line-tabs-function #'tab-line-tabs-window-buffers) + (when (and (memq tab-line-tabs-function tab-line-new-button-functions) tab-line-new-button-show tab-line-new-button) (list tab-line-new-button))))) @@ -940,7 +967,7 @@ buffers, which effectively hides the buffer's tab from the tab line. If `kill-buffer', kills the tab's buffer. When a function, it is called with the tab as its argument. This option is useful when `tab-line-tabs-function' has the value -`tab-line-tabs-window-buffers'." +`tab-line-tabs-window-buffers' or `tab-line-tabs-fixed-window-buffers'." :type '(choice (const :tag "Bury buffer" bury-buffer) (const :tag "Kill buffer" kill-buffer) (function :tag "Function")) @@ -1033,6 +1060,19 @@ However, return the correct mouse position list if EVENT is a (event-start event))) +(defvar-keymap tab-line-mode-map + :doc "Keymap for keys of `tab-line-mode'." + "C-x " #'tab-line-switch-to-prev-tab + "C-x C-" #'tab-line-switch-to-prev-tab + "C-x " #'tab-line-switch-to-next-tab + "C-x C-" #'tab-line-switch-to-next-tab) + +(defvar-keymap tab-line-switch-repeat-map + :doc "Keymap to repeat tab/buffer cycling. Used in `repeat-mode'." + :repeat t + "" #'tab-line-switch-to-prev-tab + "" #'tab-line-switch-to-next-tab) + ;;;###autoload (define-minor-mode tab-line-mode "Toggle display of tab line in the windows displaying the current buffer."