Repository: qutebrowser/qutebrowser

Issue:
Configurable minimum tab width
I prefer firefox's behavior where tabs are fixed width so that the tab title is always visible. Being able to configure the minimum width for horizontal tabs would be fine as well.



Discussion:
Would you prefer a minimum width setting, or a fixed width setting, I think both could be possible.

Do you think the setting should apply to pinned tabs as well? I think that pinned tabs should get an exemption, but I'm not sure exaclty what behavior you're looking for for that.
I'd prefer a minimum width setting personally. I agree that it would be preferable for this setting to not apply to pinned tabs, but I think in that case there should be a separate minimum width setting for pinned tabs as it could be useful when `tabs.pinned.shrink` is false and/or `tabs.title.format_pinned` has been altered.

Resolving patch:
diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py
--- a/qutebrowser/mainwindow/tabwidget.py
+++ b/qutebrowser/mainwindow/tabwidget.py
@@ -358,7 +358,9 @@ def _on_config_changed(self, option: str):
         # Clear _minimum_tab_size_hint_helper cache when appropriate
         if option in ["tabs.indicator.padding",
                       "tabs.padding",
-                      "tabs.indicator.width"]:
+                      "tabs.indicator.width",
+                      "tabs.min_width",
+                      "tabs.pinned.shrink"]:
             self._minimum_tab_size_hint_helper.cache_clear()
 
     def _on_show_switching_delay_changed(self):
@@ -477,7 +479,8 @@ def minimumTabSizeHint(self, index, ellipsis: bool = True) -> QSize:
         Args:
             index: The index of the tab to get a size hint for.
             ellipsis: Whether to use ellipsis to calculate width
-                     instead of the tab's text.
+                      instead of the tab's text.
+                      Forced to False for pinned tabs.
         Return:
             A QSize of the smallest tab size we can make.
         """
@@ -489,14 +492,19 @@ def minimumTabSizeHint(self, index, ellipsis: bool = True) -> QSize:
         else:
             icon_width = min(icon.actualSize(self.iconSize()).width(),
                              self.iconSize().width()) + icon_padding
+
+        pinned = self._tab_pinned(index)
+        if pinned:
+            # Never consider ellipsis an option for pinned tabs
+            ellipsis = False
         return self._minimum_tab_size_hint_helper(self.tabText(index),
-                                                  icon_width,
-                                                  ellipsis)
+                                                  icon_width, ellipsis,
+                                                  pinned)
 
     @functools.lru_cache(maxsize=2**9)
     def _minimum_tab_size_hint_helper(self, tab_text: str,
                                       icon_width: int,
-                                      ellipsis: bool) -> QSize:
+                                      ellipsis: bool, pinned: bool) -> QSize:
         """Helper function to cache tab results.
 
         Config values accessed in here should be added to _on_config_changed to
@@ -521,6 +529,10 @@ def _text_to_width(text):
         height = self.fontMetrics().height() + padding_v
         width = (text_width + icon_width +
                  padding_h + indicator_width)
+        min_width = config.val.tabs.min_width
+        if (not self.vertical and min_width > 0 and
+                not pinned or not config.val.tabs.pinned.shrink):
+            width = max(min_width, width)
         return QSize(width, height)
 
     def _pinned_statistics(self) -> (int, int):
@@ -550,6 +562,12 @@ def tabSizeHint(self, index: int):
         Return:
             A QSize.
         """
+        if self.count() == 0:
+            # This happens on startup on macOS.
+            # We return it directly rather than setting `size' because we don't
+            # want to ensure it's valid in this special case.
+            return QSize()
+
         minimum_size = self.minimumTabSizeHint(index)
         height = minimum_size.height()
         if self.vertical:
@@ -562,11 +580,6 @@ def tabSizeHint(self, index: int):
             else:
                 width = int(confwidth)
             size = QSize(max(minimum_size.width(), width), height)
-        elif self.count() == 0:
-            # This happens on startup on macOS.
-            # We return it directly rather than setting `size' because we don't
-            # want to ensure it's valid in this special case.
-            return QSize()
         else:
             if config.val.tabs.pinned.shrink:
                 pinned = self._tab_pinned(index)


Test patch: