aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuri Linkov2022-11-04 09:47:06 +0200
committerJuri Linkov2022-11-04 09:47:59 +0200
commitca3763af5cc2758ec71700029558e6ecc4379ea9 (patch)
treeabf1cebb10119b01b266c152e422219d803240ae
parent4fa8f57cc627166f4f7f1a915bb24923f413a3d0 (diff)
downloademacs-ca3763af5cc2758ec71700029558e6ecc4379ea9.tar.gz
emacs-ca3763af5cc2758ec71700029558e6ecc4379ea9.zip
* lisp/tab-bar.el (tab-bar-fixed-width): New user option.
(tab-bar-fixed-width-max): New user option. (tab-bar-fixed-width-min): New variable. (tab-bar-fixed-width-faces): New variable. (tab-bar--fixed-width-hash): New function. (tab-bar-make-keymap-1): Use 'tab-bar-fixed-width'. https://lists.gnu.org/archive/html/emacs-devel/2022-10/msg02067.html
-rw-r--r--etc/NEWS5
-rw-r--r--lisp/tab-bar.el112
2 files changed, 116 insertions, 1 deletions
diff --git a/etc/NEWS b/etc/NEWS
index a1859674835..f3a58366fe4 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1077,6 +1077,11 @@ the corresponding deleted frame.
1077** Tab Bars and Tab Lines 1077** Tab Bars and Tab Lines
1078 1078
1079--- 1079---
1080*** New user option 'tab-bar-fixed-width' to automatically resize tabs.
1081Another option 'tab-bar-fixed-width-max' defines the maximum tab width
1082that by default is 220 pixels on GUI and 20 characters on a tty.
1083
1084---
1080*** 'C-x t RET' creates a new tab when the provided tab name doesn't exist. 1085*** 'C-x t RET' creates a new tab when the provided tab name doesn't exist.
1081 1086
1082--- 1087---
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 2032689c65d..810cb4edd7f 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -963,7 +963,117 @@ on the tab bar instead."
963 963
964(defun tab-bar-make-keymap-1 () 964(defun tab-bar-make-keymap-1 ()
965 "Generate an actual keymap from `tab-bar-map', without caching." 965 "Generate an actual keymap from `tab-bar-map', without caching."
966 (append tab-bar-map (tab-bar-format-list tab-bar-format))) 966 (let ((items (tab-bar-format-list tab-bar-format)))
967 (when tab-bar-fixed-width
968 (setq items (tab-bar-fixed-width items)))
969 (append tab-bar-map items)))
970
971
972(defcustom tab-bar-fixed-width t
973 "Automatically resize tabs on the tab bar to the fixed width.
974This variable is intended to solve two problems. When switching buffers
975on the current tab, the tab changes its name to buffer names of
976various lengths, thus resizing the tab and shifting the tab positions
977on the tab bar. But with the fixed width, the size of the tab name
978doesn't change when the tab name changes, thus keeping the fixed
979tab bar layout. The second problem solved by this variable is to prevent
980wrapping the long tab bar to the second line, thus keeping the height of
981the tab bar always fixed to one line.
982
983The maximum tab width is defined by the variable `tab-bar-fixed-width-max'."
984 :type 'boolean
985 :group 'tab-bar
986 :version "29.1")
987
988(defcustom tab-bar-fixed-width-max '(220 . 20)
989 "Maximum number of pixels or characters allowed for the tab name width.
990The car of the cons cell is the maximum number of pixels when used on
991a GUI session. The cdr of the cons cell defines the maximum number of
992characters when used on a tty. When set to nil, there is no limit
993on maximum width, and tabs are resized evenly to the whole width
994of the tab bar when `tab-bar-fixed-width' is non-nil."
995 :type '(choice
996 (const :tag "No limit" nil)
997 (cons (integer :tag "Max width (pixels)" :value 220)
998 (integer :tag "Max width (chars)" :value 20)))
999 :group 'tab-bar
1000 :version "29.1")
1001
1002(defvar tab-bar-fixed-width-min '(20 . 2)
1003 "Minimum number of pixels or characters allowed for the tab name width.
1004It's not recommended to change this value since with a bigger value, the
1005tab bar might wrap to the second line.")
1006
1007(defvar tab-bar-fixed-width-faces
1008 '( tab-bar-tab tab-bar-tab-inactive
1009 tab-bar-tab-ungrouped
1010 tab-bar-tab-group-inactive)
1011 "Resize tabs only with these faces.")
1012
1013(defvar tab-bar--fixed-width-hash nil
1014 "Memoization table for `tab-bar-fixed-width'.")
1015
1016(defun tab-bar-fixed-width (items)
1017 "Return tab-bar items with resized tab names."
1018 (unless tab-bar--fixed-width-hash
1019 (define-hash-table-test 'tab-bar--fixed-width-hash-test
1020 #'equal-including-properties
1021 #'sxhash-equal-including-properties)
1022 (setq tab-bar--fixed-width-hash
1023 (make-hash-table :test 'tab-bar--fixed-width-hash-test)))
1024 (let ((tabs nil) ;; list of resizable tabs
1025 (non-tabs "") ;; concatenated names of non-resizable tabs
1026 (width 0)) ;; resize tab names to this width
1027 (dolist (item items)
1028 (when (and (eq (nth 1 item) 'menu-item) (stringp (nth 2 item)))
1029 (if (memq (get-text-property 0 'face (nth 2 item))
1030 tab-bar-fixed-width-faces)
1031 (push item tabs)
1032 (unless (eq (nth 0 item) 'align-right)
1033 (setq non-tabs (concat non-tabs (nth 2 item)))))))
1034 (when tabs
1035 (setq width (/ (- (frame-pixel-width)
1036 (string-pixel-width
1037 (propertize non-tabs 'face 'tab-bar)))
1038 (length tabs)))
1039 (when tab-bar-fixed-width-min
1040 (setq width (max width (if window-system
1041 (car tab-bar-fixed-width-min)
1042 (cdr tab-bar-fixed-width-min)))))
1043 (when tab-bar-fixed-width-max
1044 (setq width (min width (if window-system
1045 (car tab-bar-fixed-width-max)
1046 (cdr tab-bar-fixed-width-max)))))
1047 (dolist (item tabs)
1048 (setf (nth 2 item)
1049 (with-memoization (gethash (cons width (nth 2 item))
1050 tab-bar--fixed-width-hash)
1051 (let* ((name (nth 2 item))
1052 (len (length name))
1053 (close-p (get-text-property (1- len) 'close-tab name))
1054 (pixel-width (string-pixel-width
1055 (propertize name 'face 'tab-bar-tab))))
1056 (cond
1057 ((< pixel-width width)
1058 (let ((space (apply 'propertize " " (text-properties-at 0 name)))
1059 (ins-pos (- len (if close-p 1 0))))
1060 (while (< pixel-width width)
1061 (setf (substring name ins-pos ins-pos) space)
1062 (setq pixel-width (string-pixel-width
1063 (propertize name 'face 'tab-bar-tab))))))
1064 ((> pixel-width width)
1065 (let (del-pos)
1066 (while (> pixel-width width)
1067 (setq len (length name)
1068 del-pos (- len (if close-p 1 0)))
1069 (setf (substring name (1- del-pos) del-pos) "")
1070 (setq pixel-width (string-pixel-width
1071 (propertize name 'face 'tab-bar-tab))))
1072 (add-face-text-property (max (- del-pos 3) 1)
1073 (1- del-pos)
1074 'shadow nil name))))
1075 name)))))
1076 items))
967 1077
968 1078
969;; Some window-configuration parameters don't need to be persistent. 1079;; Some window-configuration parameters don't need to be persistent.