Improve fade style for vertical tab bar

This commit is contained in:
Kovid Goyal 2026-08-02 21:40:37 +05:30
parent 70bdd4e96e
commit 75bd9d7979
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
3 changed files with 75 additions and 9 deletions

View file

@ -197,6 +197,11 @@ Detailed list of changes
lines instead of truncating them, either at the width of the tab bar or at a
specified number of cells (:iss:`10302`)
- Vertical tabs: with the ``fade`` tab bar style, trailing fade cells are now
placed flush with the right edge of the last title line instead of immediately
after the title text, and the background-coloured separator cell that followed
the fades has been removed
0.48.2 [2026-07-30]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -560,15 +560,32 @@ def draw_tab_with_fade(
if extra > 0:
screen.cursor.x -= extra + 1
screen.draw('…')
for bg in reversed(fade_colors):
if extra >= 0:
break
extra += 1
screen.cursor.bg = bg
if draw_data.tab_bar_edge in ('left', 'right'):
# For vertical tabs the background is pre-filled, so place trailing
# fade cells flush with the right edge of the last title line.
num_fade = len(fade_colors)
fade_start = screen.columns - num_fade
text_end = screen.cursor.x
last_row = screen.cursor.y
if text_end < max_tab_length:
fade_to_skip = max(0, text_end - fade_start)
screen.cursor.x = max(text_end, fade_start)
screen.cursor.y = last_row
for bg in list(reversed(fade_colors))[fade_to_skip:]:
screen.cursor.bg = bg
screen.draw(' ')
end = screen.cursor.x
screen.cursor.bg = as_rgb(color_as_int(draw_data.default_bg))
else:
for bg in reversed(fade_colors):
if extra >= 0:
break
extra += 1
screen.cursor.bg = bg
screen.draw(' ')
end = screen.cursor.x
screen.cursor.bg = as_rgb(color_as_int(draw_data.default_bg))
screen.draw(' ')
end = screen.cursor.x
screen.cursor.bg = as_rgb(color_as_int(draw_data.default_bg))
screen.draw(' ')
return end

View file

@ -3,7 +3,7 @@
from unittest.mock import patch
from kitty.fast_data_types import LEFT_EDGE, Region
from kitty.fast_data_types import LEFT_EDGE, Color, Region
from kitty.options.utils import tab_title_wrap
from kitty.tab_bar import CellRange, TabBar, TabBarData, truncate_line, wrap_title
@ -351,3 +351,47 @@ class TestTabBar(BaseTest):
tb.update(tuple(TabBarData(title=long_title, tab_id=i + 1, is_active=i == 0) for i in range(3)))
self.ae(self.screen_lines(tb), ['feature/reall', 'y-long-bran…', 'feature/reall', 'y-long-bran…', '…'])
self.ae(tuple(te.y for te in tb.tab_extents), (CellRange(0, 1), CellRange(2, 3)))
def test_vertical_tab_bar_fade_style(self) -> None:
# Use fixed colors so every fade cell blends to the same midpoint
# colour, making fade cells easy to identify by background.
self.set_options({
'tab_bar_edge': LEFT_EDGE,
'tab_bar_style': 'fade',
'tab_title_template': '{title}',
'active_tab_background': Color(200, 0, 0),
'tab_bar_background': Color(0, 0, 100),
'tab_fade': (0.5, 0.5, 0.5, 0.5),
})
central = region(120, 0, 400, 160)
tab_bar_r = region(0, 0, 120, 160)
with (
patch('kitty.tab_bar.cell_size_for_window', return_value=(10, 20)),
patch('kitty.tab_bar.viewport_for_window', return_value=(central, tab_bar_r, 400, 160, 10, 20)),
patch('kitty.tab_bar.set_tab_bar_render_data'),
patch('kitty.tab_bar.get_boss', return_value=DummyBoss()),
):
tb = TabBar(1)
tb.layout()
tb.update((TabBarData(title='t0', tab_id=1, is_active=True),))
s = tb.screen
# Screen: 12 columns (120px / 10px), max_tab_length = 11, 4 fade cells.
# Title 't0' begins at col 4 (after 4 leading fades) and ends at col 6.
# Trailing fades should occupy cols 8–11 (flush with the right edge).
def bg(col: int) -> int:
return int(s.line(0).cursor_from(col).bg)
tab_bg = bg(4) # title cell: active_tab_background
fade_bg = bg(0) # leading fade cell: midpoint blend
# Sanity: fade colour is distinct from plain tab colour.
self.assertNotEqual(tab_bg, fade_bg)
# Issue 1: trailing fades flush with the right edge (cols 8–11), not right after the text.
self.ae(bg(6), tab_bg) # col 6, right after 't0', must be plain tab bg
self.ae(bg(8), fade_bg) # col 8, fade_start = 12 - 4, must be a fade cell
# Issue 2: no background-coloured separator after the trailing fades.
self.ae(bg(11), fade_bg) # col 11, last trailing fade, must not be default_bg