diff options
| author | Juri Linkov | 2019-09-22 23:40:04 +0300 |
|---|---|---|
| committer | Juri Linkov | 2019-09-22 23:40:04 +0300 |
| commit | 39255b9b4de0b036568b64d7170ba8076d96be1d (patch) | |
| tree | 66e9ca5f71b1f1f47e1cf35106ebc1e0454f3aef | |
| parent | ab2f42cad5259db6626f0da1eb01421c5214c799 (diff) | |
| download | emacs-39255b9b4de0b036568b64d7170ba8076d96be1d.tar.gz emacs-39255b9b4de0b036568b64d7170ba8076d96be1d.zip | |
Improve customizability and better tab separators.
* lisp/tab-bar.el (tab-bar-tabs-function): New defvar.
* lisp/tab-line.el (tab-line-tab-name-function)
(tab-line-tabs-function): New defvars.
| -rw-r--r-- | etc/images/tabs/close.xpm | 2 | ||||
| -rw-r--r-- | lisp/tab-bar.el | 45 | ||||
| -rw-r--r-- | lisp/tab-line.el | 69 | ||||
| -rw-r--r-- | src/xdisp.c | 2 |
4 files changed, 67 insertions, 51 deletions
diff --git a/etc/images/tabs/close.xpm b/etc/images/tabs/close.xpm index 48f063fa43b..1c3f4d8fd7d 100644 --- a/etc/images/tabs/close.xpm +++ b/etc/images/tabs/close.xpm | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | static char * close_xpm[] = { | 2 | static char * close_xpm[] = { |
| 3 | "9 9 4 1", | 3 | "9 9 4 1", |
| 4 | " c None", | 4 | " c None", |
| 5 | ". c #CCCCCC", | 5 | ". c #BFBFBF", |
| 6 | "+ c #000000", | 6 | "+ c #000000", |
| 7 | "@ c #808080", | 7 | "@ c #808080", |
| 8 | " ..... ", | 8 | " ..... ", |
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index 7afb39a0dda..3b6415ad13d 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | ;;; tab-bar.el --- frame-local tab bar with named persistent window configurations -*- lexical-binding: t; -*- | 1 | ;;; tab-bar.el --- frame-local tabs with named persistent window configurations -*- lexical-binding: t; -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 2019 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 2019 Free Software Foundation, Inc. |
| 4 | 4 | ||
| @@ -23,7 +23,7 @@ | |||
| 23 | 23 | ||
| 24 | ;;; Commentary: | 24 | ;;; Commentary: |
| 25 | 25 | ||
| 26 | ;; Provides `tab-bar-mode' to control display of the tab-bar and | 26 | ;; Provides `tab-bar-mode' to control display of the tab bar and |
| 27 | ;; bindings for the global tab bar. | 27 | ;; bindings for the global tab bar. |
| 28 | 28 | ||
| 29 | ;; The normal global binding for [tab-bar] (below) uses the value of | 29 | ;; The normal global binding for [tab-bar] (below) uses the value of |
| @@ -36,7 +36,7 @@ | |||
| 36 | 36 | ||
| 37 | 37 | ||
| 38 | (defgroup tab-bar nil | 38 | (defgroup tab-bar nil |
| 39 | "Frame-local tab bar." | 39 | "Frame-local tabs." |
| 40 | :group 'convenience | 40 | :group 'convenience |
| 41 | :version "27.1") | 41 | :version "27.1") |
| 42 | 42 | ||
| @@ -79,13 +79,6 @@ | |||
| 79 | :version "27.1" | 79 | :version "27.1" |
| 80 | :group 'tab-bar-faces) | 80 | :group 'tab-bar-faces) |
| 81 | 81 | ||
| 82 | (defface tab-bar-separator | ||
| 83 | '((t | ||
| 84 | :inverse-video nil)) | ||
| 85 | "Tab bar face for separator." | ||
| 86 | :version "27.1" | ||
| 87 | :group 'tab-bar-faces) | ||
| 88 | |||
| 89 | 82 | ||
| 90 | (define-minor-mode tab-bar-mode | 83 | (define-minor-mode tab-bar-mode |
| 91 | "Toggle the tab bar in all graphical frames (Tab Bar mode)." | 84 | "Toggle the tab bar in all graphical frames (Tab Bar mode)." |
| @@ -108,8 +101,8 @@ | |||
| 108 | (global-set-key [(control tab)] 'tab-bar-switch-to-next-tab))) | 101 | (global-set-key [(control tab)] 'tab-bar-switch-to-next-tab))) |
| 109 | 102 | ||
| 110 | (defun tab-bar-handle-mouse (event) | 103 | (defun tab-bar-handle-mouse (event) |
| 111 | "Text-mode emulation of switching tabs on the tab-bar. | 104 | "Text-mode emulation of switching tabs on the tab bar. |
| 112 | This command is used when you click the mouse in the tab-bar | 105 | This command is used when you click the mouse in the tab bar |
| 113 | on a console which has no window system but does have a mouse." | 106 | on a console which has no window system but does have a mouse." |
| 114 | (interactive "e") | 107 | (interactive "e") |
| 115 | (let* ((x-position (car (posn-x-y (event-start event)))) | 108 | (let* ((x-position (car (posn-x-y (event-start event)))) |
| @@ -159,8 +152,7 @@ Its main job is to show tabs in the tab bar." | |||
| 159 | (puthash key tab-bar-map tab-bar-keymap-cache))))) | 152 | (puthash key tab-bar-map tab-bar-keymap-cache))))) |
| 160 | 153 | ||
| 161 | 154 | ||
| 162 | (defvar tab-bar-separator | 155 | (defvar tab-bar-separator nil) |
| 163 | (propertize " " 'face 'tab-bar-separator)) | ||
| 164 | 156 | ||
| 165 | (defvar tab-bar-button-new | 157 | (defvar tab-bar-button-new |
| 166 | (propertize " + " | 158 | (propertize " + " |
| @@ -173,7 +165,7 @@ Its main job is to show tabs in the tab bar." | |||
| 173 | "Button for creating a new tab.") | 165 | "Button for creating a new tab.") |
| 174 | 166 | ||
| 175 | (defvar tab-bar-button-close | 167 | (defvar tab-bar-button-close |
| 176 | (propertize "x" | 168 | (propertize " x" |
| 177 | 'display `(image :type xpm | 169 | 'display `(image :type xpm |
| 178 | :file ,(expand-file-name | 170 | :file ,(expand-file-name |
| 179 | "images/tabs/close.xpm" | 171 | "images/tabs/close.xpm" |
| @@ -188,9 +180,16 @@ Its main job is to show tabs in the tab bar." | |||
| 188 | "Generate tab name in the context of the selected frame." | 180 | "Generate tab name in the context of the selected frame." |
| 189 | (mapconcat | 181 | (mapconcat |
| 190 | (lambda (w) (buffer-name (window-buffer w))) | 182 | (lambda (w) (buffer-name (window-buffer w))) |
| 191 | (window-list) | 183 | (window-list-1 (frame-first-window) 'nomini) |
| 192 | ", ")) | 184 | ", ")) |
| 193 | 185 | ||
| 186 | (defvar tab-bar-tabs-function #'tab-bar-tabs | ||
| 187 | "Function to get a list of tabs to display in the tab bar. | ||
| 188 | This function should return a list of alists with parameters | ||
| 189 | that include at least the element (name . TAB-NAME). | ||
| 190 | For example, '((tab (name . \"Tab 1\")) (current-tab (name . \"Tab 2\"))) | ||
| 191 | By default, use function `tab-bar-tabs'.") | ||
| 192 | |||
| 194 | (defun tab-bar-tabs () | 193 | (defun tab-bar-tabs () |
| 195 | "Return a list of tabs belonging to the selected frame. | 194 | "Return a list of tabs belonging to the selected frame. |
| 196 | Ensure the frame parameter `tabs' is pre-populated. | 195 | Ensure the frame parameter `tabs' is pre-populated. |
| @@ -203,13 +202,15 @@ Return its existing value or a new value." | |||
| 203 | 202 | ||
| 204 | (defun tab-bar-make-keymap-1 () | 203 | (defun tab-bar-make-keymap-1 () |
| 205 | "Generate an actual keymap from `tab-bar-map', without caching." | 204 | "Generate an actual keymap from `tab-bar-map', without caching." |
| 206 | (let ((i 0)) | 205 | (let ((separator (or tab-bar-separator (if window-system " " "|"))) |
| 206 | (i 0)) | ||
| 207 | (append | 207 | (append |
| 208 | '(keymap (mouse-1 . tab-bar-handle-mouse)) | 208 | '(keymap (mouse-1 . tab-bar-handle-mouse)) |
| 209 | (mapcan | 209 | (mapcan |
| 210 | (lambda (tab) | 210 | (lambda (tab) |
| 211 | (setq i (1+ i)) | 211 | (setq i (1+ i)) |
| 212 | (append | 212 | (append |
| 213 | `((,(intern (format "sep-%i" i)) menu-item ,separator ignore)) | ||
| 213 | (cond | 214 | (cond |
| 214 | ((eq (car tab) 'current-tab) | 215 | ((eq (car tab) 'current-tab) |
| 215 | `((current-tab | 216 | `((current-tab |
| @@ -233,13 +234,11 @@ Return its existing value or a new value." | |||
| 233 | menu-item "" | 234 | menu-item "" |
| 234 | ,(lambda () | 235 | ,(lambda () |
| 235 | (interactive) | 236 | (interactive) |
| 236 | (tab-bar-close-tab tab)))) | 237 | (tab-bar-close-tab tab)))))) |
| 237 | (when (and (stringp tab-bar-separator) | 238 | (funcall tab-bar-tabs-function)) |
| 238 | (> (length tab-bar-separator) 0)) | ||
| 239 | `((,(intern (format "sep-%i" i)) menu-item ,tab-bar-separator ignore))))) | ||
| 240 | (tab-bar-tabs)) | ||
| 241 | (when tab-bar-button-new | 239 | (when tab-bar-button-new |
| 242 | `((add-tab menu-item ,tab-bar-button-new tab-bar-add-tab | 240 | `((sep-add-tab menu-item ,separator ignore) |
| 241 | (add-tab menu-item ,tab-bar-button-new tab-bar-add-tab | ||
| 243 | :help "New tab")))))) | 242 | :help "New tab")))))) |
| 244 | 243 | ||
| 245 | 244 | ||
diff --git a/lisp/tab-line.el b/lisp/tab-line.el index 6b1ce03d26e..169f7b82042 100644 --- a/lisp/tab-line.el +++ b/lisp/tab-line.el | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | ;;; tab-line.el --- window-local tab line with window buffers -*- lexical-binding: t; -*- | 1 | ;;; tab-line.el --- window-local tabs with window buffers -*- lexical-binding: t; -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 2019 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 2019 Free Software Foundation, Inc. |
| 4 | 4 | ||
| @@ -31,7 +31,7 @@ | |||
| 31 | 31 | ||
| 32 | 32 | ||
| 33 | (defgroup tab-line nil | 33 | (defgroup tab-line nil |
| 34 | "Window-local tab line." | 34 | "Window-local tabs." |
| 35 | :group 'convenience | 35 | :group 'convenience |
| 36 | :version "27.1") | 36 | :version "27.1") |
| 37 | 37 | ||
| @@ -70,7 +70,7 @@ | |||
| 70 | :background "grey75") | 70 | :background "grey75") |
| 71 | (t | 71 | (t |
| 72 | :inverse-video t)) | 72 | :inverse-video t)) |
| 73 | "Tab line face for non-selected tabs." | 73 | "Tab line face for non-selected tab." |
| 74 | :version "27.1" | 74 | :version "27.1" |
| 75 | :group 'tab-line-faces) | 75 | :group 'tab-line-faces) |
| 76 | 76 | ||
| @@ -82,7 +82,7 @@ | |||
| 82 | 82 | ||
| 83 | (defface tab-line-close-highlight | 83 | (defface tab-line-close-highlight |
| 84 | '((t :foreground "red")) | 84 | '((t :foreground "red")) |
| 85 | "Tab line face for highlighting." | 85 | "Tab line face for highlighting of the close button." |
| 86 | :version "27.1" | 86 | :version "27.1" |
| 87 | :group 'tab-line-faces) | 87 | :group 'tab-line-faces) |
| 88 | 88 | ||
| @@ -90,11 +90,10 @@ | |||
| 90 | (defvar tab-line-tab-map | 90 | (defvar tab-line-tab-map |
| 91 | (let ((map (make-sparse-keymap))) | 91 | (let ((map (make-sparse-keymap))) |
| 92 | (define-key map [tab-line mouse-1] 'tab-line-select-tab) | 92 | (define-key map [tab-line mouse-1] 'tab-line-select-tab) |
| 93 | (define-key map [tab-line mouse-2] 'tab-line-select-tab) | 93 | (define-key map [tab-line mouse-2] 'tab-line-close-tab) |
| 94 | (define-key map [tab-line mouse-4] 'tab-line-switch-to-prev-tab) | 94 | (define-key map [tab-line mouse-4] 'tab-line-switch-to-prev-tab) |
| 95 | (define-key map [tab-line mouse-5] 'tab-line-switch-to-next-tab) | 95 | (define-key map [tab-line mouse-5] 'tab-line-switch-to-next-tab) |
| 96 | (define-key map "\C-m" 'tab-line-select-tab) | 96 | (define-key map "\C-m" 'tab-line-select-tab) |
| 97 | (define-key map [follow-link] 'mouse-face) | ||
| 98 | map) | 97 | map) |
| 99 | "Local keymap for `tab-line-mode' window tabs.") | 98 | "Local keymap for `tab-line-mode' window tabs.") |
| 100 | 99 | ||
| @@ -103,7 +102,6 @@ | |||
| 103 | (define-key map [tab-line mouse-1] 'tab-line-add-tab) | 102 | (define-key map [tab-line mouse-1] 'tab-line-add-tab) |
| 104 | (define-key map [tab-line mouse-2] 'tab-line-add-tab) | 103 | (define-key map [tab-line mouse-2] 'tab-line-add-tab) |
| 105 | (define-key map "\C-m" 'tab-line-add-tab) | 104 | (define-key map "\C-m" 'tab-line-add-tab) |
| 106 | (define-key map [follow-link] 'mouse-face) | ||
| 107 | map) | 105 | map) |
| 108 | "Local keymap to add `tab-line-mode' window tabs.") | 106 | "Local keymap to add `tab-line-mode' window tabs.") |
| 109 | 107 | ||
| @@ -111,12 +109,11 @@ | |||
| 111 | (let ((map (make-sparse-keymap))) | 109 | (let ((map (make-sparse-keymap))) |
| 112 | (define-key map [tab-line mouse-1] 'tab-line-close-tab) | 110 | (define-key map [tab-line mouse-1] 'tab-line-close-tab) |
| 113 | (define-key map [tab-line mouse-2] 'tab-line-close-tab) | 111 | (define-key map [tab-line mouse-2] 'tab-line-close-tab) |
| 114 | (define-key map [follow-link] 'mouse-face) | ||
| 115 | map) | 112 | map) |
| 116 | "Local keymap to close `tab-line-mode' window tabs.") | 113 | "Local keymap to close `tab-line-mode' window tabs.") |
| 117 | 114 | ||
| 118 | 115 | ||
| 119 | (defvar tab-line-separator " ") | 116 | (defvar tab-line-separator nil) |
| 120 | 117 | ||
| 121 | (defvar tab-line-tab-name-ellipsis | 118 | (defvar tab-line-tab-name-ellipsis |
| 122 | (if (char-displayable-p ?…) "…" "...")) | 119 | (if (char-displayable-p ?…) "…" "...")) |
| @@ -135,7 +132,7 @@ | |||
| 135 | "Button for creating a new tab.") | 132 | "Button for creating a new tab.") |
| 136 | 133 | ||
| 137 | (defvar tab-line-button-close | 134 | (defvar tab-line-button-close |
| 138 | (propertize "x" | 135 | (propertize " x" |
| 139 | 'display `(image :type xpm | 136 | 'display `(image :type xpm |
| 140 | :file ,(expand-file-name | 137 | :file ,(expand-file-name |
| 141 | "images/tabs/close.xpm" | 138 | "images/tabs/close.xpm" |
| @@ -148,9 +145,16 @@ | |||
| 148 | "Button for closing the clicked tab.") | 145 | "Button for closing the clicked tab.") |
| 149 | 146 | ||
| 150 | 147 | ||
| 148 | (defvar tab-line-tab-name-function #'tab-line-tab-name | ||
| 149 | "Function to get a tab name. | ||
| 150 | Function gets two arguments: tab to get name for and a list of tabs | ||
| 151 | to display. By default, use function `tab-line-tab-name'.") | ||
| 152 | |||
| 151 | (defun tab-line-tab-name (buffer &optional buffers) | 153 | (defun tab-line-tab-name (buffer &optional buffers) |
| 152 | "Generate tab name from BUFFER. | 154 | "Generate tab name from BUFFER. |
| 153 | Reduce tab width proportionally to space taken by other tabs." | 155 | Reduce tab width proportionally to space taken by other tabs. |
| 156 | This function can be overridden by changing the default value of the | ||
| 157 | variable `tab-line-tab-name-function'." | ||
| 154 | (let ((tab-name (buffer-name buffer)) | 158 | (let ((tab-name (buffer-name buffer)) |
| 155 | (limit (when buffers | 159 | (limit (when buffers |
| 156 | (max 1 (- (/ (window-width) (length buffers)) 3))))) | 160 | (max 1 (- (/ (window-width) (length buffers)) 3))))) |
| @@ -161,10 +165,22 @@ Reduce tab width proportionally to space taken by other tabs." | |||
| 161 | 'help-echo tab-name)))) | 165 | 'help-echo tab-name)))) |
| 162 | 166 | ||
| 163 | (defvar tab-line-tabs-limit 15 | 167 | (defvar tab-line-tabs-limit 15 |
| 164 | "Maximum number of buffer tabs displayed in the window tab-line.") | 168 | "Maximum number of buffer tabs displayed in the tab line.") |
| 165 | 169 | ||
| 166 | (defun tab-line-tabs (&optional window) | 170 | (defvar tab-line-tabs-function #'tab-line-tabs |
| 167 | (let* ((buffer (window-buffer window)) | 171 | "Function to get a list of tabs to display in the tab line. |
| 172 | This function should return either a list of buffers whose names will | ||
| 173 | be displayed, or just a list of strings to display in the tab line. | ||
| 174 | By default, use function `tab-line-tabs'.") | ||
| 175 | |||
| 176 | (defun tab-line-tabs () | ||
| 177 | "Return a list of tabs that should be displayed in the tab line. | ||
| 178 | By default returns a list of window buffers, i.e. buffers previously | ||
| 179 | shown in the same window where the tab line is displayed. | ||
| 180 | This list can be overridden by changing the default value of the | ||
| 181 | variable `tab-line-tabs-function'." | ||
| 182 | (let* ((window (selected-window)) | ||
| 183 | (buffer (window-buffer window)) | ||
| 168 | (next-buffers (seq-remove (lambda (b) (eq b buffer)) | 184 | (next-buffers (seq-remove (lambda (b) (eq b buffer)) |
| 169 | (window-next-buffers window))) | 185 | (window-next-buffers window))) |
| 170 | (next-buffers (seq-filter #'buffer-live-p next-buffers)) | 186 | (next-buffers (seq-filter #'buffer-live-p next-buffers)) |
| @@ -191,25 +207,26 @@ Reduce tab width proportionally to space taken by other tabs." | |||
| 191 | (defun tab-line-format () | 207 | (defun tab-line-format () |
| 192 | "Template for displaying tab line for selected window." | 208 | "Template for displaying tab line for selected window." |
| 193 | (let* ((window (selected-window)) | 209 | (let* ((window (selected-window)) |
| 194 | (buffer (window-buffer window)) | 210 | (selected-buffer (window-buffer window)) |
| 195 | (buffer-tabs (tab-line-tabs window))) | 211 | (tabs (funcall tab-line-tabs-function)) |
| 212 | (separator (or tab-line-separator (if window-system " " "|")))) | ||
| 196 | (append | 213 | (append |
| 197 | (mapcar | 214 | (mapcar |
| 198 | (lambda (b) | 215 | (lambda (tab) |
| 199 | (concat | 216 | (concat |
| 200 | (or tab-line-separator "") | 217 | separator |
| 201 | (apply 'propertize (concat (propertize | 218 | (apply 'propertize (concat (propertize |
| 202 | (tab-line-tab-name b buffer-tabs) | 219 | (funcall tab-line-tab-name-function tab tabs) |
| 203 | 'keymap tab-line-tab-map) | 220 | 'keymap tab-line-tab-map) |
| 204 | tab-line-button-close) | 221 | tab-line-button-close) |
| 205 | `( | 222 | `( |
| 206 | buffer ,b | 223 | tab ,tab |
| 207 | face ,(if (eq b buffer) | 224 | face ,(if (eq tab selected-buffer) |
| 208 | 'tab-line-tab | 225 | 'tab-line-tab |
| 209 | 'tab-line-tab-inactive) | 226 | 'tab-line-tab-inactive) |
| 210 | mouse-face tab-line-highlight)))) | 227 | mouse-face tab-line-highlight)))) |
| 211 | buffer-tabs) | 228 | tabs) |
| 212 | (list (concat tab-line-separator tab-line-button-new))))) | 229 | (list (concat separator tab-line-button-new))))) |
| 213 | 230 | ||
| 214 | 231 | ||
| 215 | (defun tab-line-add-tab (&optional e) | 232 | (defun tab-line-add-tab (&optional e) |
| @@ -227,7 +244,7 @@ using the `previous-buffer' command." | |||
| 227 | (interactive "e") | 244 | (interactive "e") |
| 228 | (let* ((posnp (event-start e)) | 245 | (let* ((posnp (event-start e)) |
| 229 | (window (posn-window posnp)) | 246 | (window (posn-window posnp)) |
| 230 | (buffer (get-pos-property 1 'buffer (car (posn-string posnp)))) | 247 | (buffer (get-pos-property 1 'tab (car (posn-string posnp)))) |
| 231 | (window-buffer (window-buffer window)) | 248 | (window-buffer (window-buffer window)) |
| 232 | (next-buffers (seq-remove (lambda (b) (eq b window-buffer)) | 249 | (next-buffers (seq-remove (lambda (b) (eq b window-buffer)) |
| 233 | (window-next-buffers window))) | 250 | (window-next-buffers window))) |
| @@ -260,7 +277,7 @@ using the `previous-buffer' command." | |||
| 260 | (interactive "e") | 277 | (interactive "e") |
| 261 | (let* ((posnp (event-start e)) | 278 | (let* ((posnp (event-start e)) |
| 262 | (window (posn-window posnp)) | 279 | (window (posn-window posnp)) |
| 263 | (buffer (get-pos-property 1 'buffer (car (posn-string posnp))))) | 280 | (buffer (get-pos-property 1 'tab (car (posn-string posnp))))) |
| 264 | (with-selected-window window | 281 | (with-selected-window window |
| 265 | (if (eq buffer (current-buffer)) | 282 | (if (eq buffer (current-buffer)) |
| 266 | (bury-buffer) | 283 | (bury-buffer) |
diff --git a/src/xdisp.c b/src/xdisp.c index 197493bfbb8..0fc387b8ffb 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -12764,7 +12764,7 @@ build_desired_tab_bar_string (struct frame *f) | |||
| 12764 | caption = Qnil; | 12764 | caption = Qnil; |
| 12765 | 12765 | ||
| 12766 | /* Prepare F->desired_tab_bar_string. Make a new string. */ | 12766 | /* Prepare F->desired_tab_bar_string. Make a new string. */ |
| 12767 | fset_desired_tab_bar_string (f, build_string (" ")); | 12767 | fset_desired_tab_bar_string (f, build_string ("")); |
| 12768 | 12768 | ||
| 12769 | /* Put a `display' property on the string for the captions to display, | 12769 | /* Put a `display' property on the string for the captions to display, |
| 12770 | put a `menu_item' property on tab-bar items with a value that | 12770 | put a `menu_item' property on tab-bar items with a value that |