-;;; tab-bar.el --- frame-local tab bar with named persistent window configurations -*- lexical-binding: t; -*-
+;;; tab-bar.el --- frame-local tabs with named persistent window configurations -*- lexical-binding: t; -*-
;; Copyright (C) 2019 Free Software Foundation, Inc.
;;; Commentary:
-;; Provides `tab-bar-mode' to control display of the tab-bar and
+;; Provides `tab-bar-mode' to control display of the tab bar and
;; bindings for the global tab bar.
;; The normal global binding for [tab-bar] (below) uses the value of
\f
(defgroup tab-bar nil
- "Frame-local tab bar."
+ "Frame-local tabs."
:group 'convenience
:version "27.1")
:version "27.1"
:group 'tab-bar-faces)
-(defface tab-bar-separator
- '((t
- :inverse-video nil))
- "Tab bar face for separator."
- :version "27.1"
- :group 'tab-bar-faces)
-
\f
(define-minor-mode tab-bar-mode
"Toggle the tab bar in all graphical frames (Tab Bar mode)."
(global-set-key [(control tab)] 'tab-bar-switch-to-next-tab)))
(defun tab-bar-handle-mouse (event)
- "Text-mode emulation of switching tabs on the tab-bar.
-This command is used when you click the mouse in the tab-bar
+ "Text-mode emulation of switching tabs on the tab bar.
+This command is used when you click the mouse in the tab bar
on a console which has no window system but does have a mouse."
(interactive "e")
(let* ((x-position (car (posn-x-y (event-start event))))
(puthash key tab-bar-map tab-bar-keymap-cache)))))
\f
-(defvar tab-bar-separator
- (propertize " " 'face 'tab-bar-separator))
+(defvar tab-bar-separator nil)
(defvar tab-bar-button-new
(propertize " + "
"Button for creating a new tab.")
(defvar tab-bar-button-close
- (propertize "x"
+ (propertize " x"
'display `(image :type xpm
:file ,(expand-file-name
"images/tabs/close.xpm"
"Generate tab name in the context of the selected frame."
(mapconcat
(lambda (w) (buffer-name (window-buffer w)))
- (window-list)
+ (window-list-1 (frame-first-window) 'nomini)
", "))
+(defvar tab-bar-tabs-function #'tab-bar-tabs
+ "Function to get a list of tabs to display in the tab bar.
+This function should return a list of alists with parameters
+that include at least the element (name . TAB-NAME).
+For example, '((tab (name . \"Tab 1\")) (current-tab (name . \"Tab 2\")))
+By default, use function `tab-bar-tabs'.")
+
(defun tab-bar-tabs ()
"Return a list of tabs belonging to the selected frame.
Ensure the frame parameter `tabs' is pre-populated.
(defun tab-bar-make-keymap-1 ()
"Generate an actual keymap from `tab-bar-map', without caching."
- (let ((i 0))
+ (let ((separator (or tab-bar-separator (if window-system " " "|")))
+ (i 0))
(append
'(keymap (mouse-1 . tab-bar-handle-mouse))
(mapcan
(lambda (tab)
(setq i (1+ i))
(append
+ `((,(intern (format "sep-%i" i)) menu-item ,separator ignore))
(cond
((eq (car tab) 'current-tab)
`((current-tab
menu-item ""
,(lambda ()
(interactive)
- (tab-bar-close-tab tab))))
- (when (and (stringp tab-bar-separator)
- (> (length tab-bar-separator) 0))
- `((,(intern (format "sep-%i" i)) menu-item ,tab-bar-separator ignore)))))
- (tab-bar-tabs))
+ (tab-bar-close-tab tab))))))
+ (funcall tab-bar-tabs-function))
(when tab-bar-button-new
- `((add-tab menu-item ,tab-bar-button-new tab-bar-add-tab
+ `((sep-add-tab menu-item ,separator ignore)
+ (add-tab menu-item ,tab-bar-button-new tab-bar-add-tab
:help "New tab"))))))
\f
-;;; tab-line.el --- window-local tab line with window buffers -*- lexical-binding: t; -*-
+;;; tab-line.el --- window-local tabs with window buffers -*- lexical-binding: t; -*-
;; Copyright (C) 2019 Free Software Foundation, Inc.
\f
(defgroup tab-line nil
- "Window-local tab line."
+ "Window-local tabs."
:group 'convenience
:version "27.1")
:background "grey75")
(t
:inverse-video t))
- "Tab line face for non-selected tabs."
+ "Tab line face for non-selected tab."
:version "27.1"
:group 'tab-line-faces)
(defface tab-line-close-highlight
'((t :foreground "red"))
- "Tab line face for highlighting."
+ "Tab line face for highlighting of the close button."
:version "27.1"
:group 'tab-line-faces)
(defvar tab-line-tab-map
(let ((map (make-sparse-keymap)))
(define-key map [tab-line mouse-1] 'tab-line-select-tab)
- (define-key map [tab-line mouse-2] 'tab-line-select-tab)
+ (define-key map [tab-line mouse-2] 'tab-line-close-tab)
(define-key map [tab-line mouse-4] 'tab-line-switch-to-prev-tab)
(define-key map [tab-line mouse-5] 'tab-line-switch-to-next-tab)
(define-key map "\C-m" 'tab-line-select-tab)
- (define-key map [follow-link] 'mouse-face)
map)
"Local keymap for `tab-line-mode' window tabs.")
(define-key map [tab-line mouse-1] 'tab-line-add-tab)
(define-key map [tab-line mouse-2] 'tab-line-add-tab)
(define-key map "\C-m" 'tab-line-add-tab)
- (define-key map [follow-link] 'mouse-face)
map)
"Local keymap to add `tab-line-mode' window tabs.")
(let ((map (make-sparse-keymap)))
(define-key map [tab-line mouse-1] 'tab-line-close-tab)
(define-key map [tab-line mouse-2] 'tab-line-close-tab)
- (define-key map [follow-link] 'mouse-face)
map)
"Local keymap to close `tab-line-mode' window tabs.")
\f
-(defvar tab-line-separator " ")
+(defvar tab-line-separator nil)
(defvar tab-line-tab-name-ellipsis
(if (char-displayable-p ?…) "…" "..."))
"Button for creating a new tab.")
(defvar tab-line-button-close
- (propertize "x"
+ (propertize " x"
'display `(image :type xpm
:file ,(expand-file-name
"images/tabs/close.xpm"
"Button for closing the clicked tab.")
\f
+(defvar tab-line-tab-name-function #'tab-line-tab-name
+ "Function to get a tab name.
+Function gets two arguments: tab to get name for and a list of tabs
+to display. By default, use function `tab-line-tab-name'.")
+
(defun tab-line-tab-name (buffer &optional buffers)
"Generate tab name from BUFFER.
-Reduce tab width proportionally to space taken by other tabs."
+Reduce tab width proportionally to space taken by other tabs.
+This function can be overridden by changing the default value of the
+variable `tab-line-tab-name-function'."
(let ((tab-name (buffer-name buffer))
(limit (when buffers
(max 1 (- (/ (window-width) (length buffers)) 3)))))
'help-echo tab-name))))
(defvar tab-line-tabs-limit 15
- "Maximum number of buffer tabs displayed in the window tab-line.")
-
-(defun tab-line-tabs (&optional window)
- (let* ((buffer (window-buffer window))
+ "Maximum number of buffer tabs displayed in the tab line.")
+
+(defvar tab-line-tabs-function #'tab-line-tabs
+ "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'.")
+
+(defun tab-line-tabs ()
+ "Return a list of tabs that should be displayed in the tab line.
+By default returns a list of window buffers, i.e. buffers previously
+shown in the same window where the tab line is displayed.
+This list can be overridden by changing the default value of the
+variable `tab-line-tabs-function'."
+ (let* ((window (selected-window))
+ (buffer (window-buffer window))
(next-buffers (seq-remove (lambda (b) (eq b buffer))
(window-next-buffers window)))
(next-buffers (seq-filter #'buffer-live-p next-buffers))
(defun tab-line-format ()
"Template for displaying tab line for selected window."
(let* ((window (selected-window))
- (buffer (window-buffer window))
- (buffer-tabs (tab-line-tabs window)))
+ (selected-buffer (window-buffer window))
+ (tabs (funcall tab-line-tabs-function))
+ (separator (or tab-line-separator (if window-system " " "|"))))
(append
(mapcar
- (lambda (b)
+ (lambda (tab)
(concat
- (or tab-line-separator "")
+ separator
(apply 'propertize (concat (propertize
- (tab-line-tab-name b buffer-tabs)
+ (funcall tab-line-tab-name-function tab tabs)
'keymap tab-line-tab-map)
tab-line-button-close)
`(
- buffer ,b
- face ,(if (eq b buffer)
+ tab ,tab
+ face ,(if (eq tab selected-buffer)
'tab-line-tab
'tab-line-tab-inactive)
mouse-face tab-line-highlight))))
- buffer-tabs)
- (list (concat tab-line-separator tab-line-button-new)))))
+ tabs)
+ (list (concat separator tab-line-button-new)))))
\f
(defun tab-line-add-tab (&optional e)
(interactive "e")
(let* ((posnp (event-start e))
(window (posn-window posnp))
- (buffer (get-pos-property 1 'buffer (car (posn-string posnp))))
+ (buffer (get-pos-property 1 'tab (car (posn-string posnp))))
(window-buffer (window-buffer window))
(next-buffers (seq-remove (lambda (b) (eq b window-buffer))
(window-next-buffers window)))
(interactive "e")
(let* ((posnp (event-start e))
(window (posn-window posnp))
- (buffer (get-pos-property 1 'buffer (car (posn-string posnp)))))
+ (buffer (get-pos-property 1 'tab (car (posn-string posnp)))))
(with-selected-window window
(if (eq buffer (current-buffer))
(bury-buffer)