Merge branch 'bvolpato/vertical-tab-bar-side' of https://github.com/bvolpato/kitty

This commit is contained in:
Kovid Goyal
2026-06-21 13:18:10 +05:30
13 changed files with 397 additions and 78 deletions

View File

@@ -220,6 +220,7 @@ def launcher(self):
def conf_parsing(self):
from kitty.config import defaults, load_config
from kitty.constants import is_macos
from kitty.fast_data_types import LEFT_EDGE, RIGHT_EDGE
from kitty.fonts import FontModification, ModificationType, ModificationUnit, ModificationValue
from kitty.options.utils import to_modifiers
bad_lines = []
@@ -254,6 +255,18 @@ def conf_parsing(self):
self.ae(opts.url_excluded_characters, "'''")
opts = p("url_excluded_characters abc'")
self.ae(opts.url_excluded_characters, "abc'")
opts = p('tab_bar_edge left')
self.ae(opts.tab_bar_edge, LEFT_EDGE)
opts = p('tab_bar_edge right')
self.ae(opts.tab_bar_edge, RIGHT_EDGE)
opts = p('tab_bar_align start')
self.ae(opts.tab_bar_align, 'start')
opts = p('tab_bar_align end')
self.ae(opts.tab_bar_align, 'end')
opts = p('tab_bar_align left')
self.ae(opts.tab_bar_align, 'left')
opts = p('tab_bar_align right')
self.ae(opts.tab_bar_align, 'right')
opts = p('clear_all_shortcuts y', 'map f1 next_window')
self.ae(len(opts.keyboard_modes[''].keymap), 1)
opts = p('clear_all_mouse_actions y', 'mouse_map left click ungrabbed mouse_click_url_or_select')

89
kitty_tests/tab_bar.py Normal file
View File

@@ -0,0 +1,89 @@
#!/usr/bin/env python
# License: GPL v3 Copyright: 2026, Kovid Goyal <kovid at kovidgoyal.net>
from unittest.mock import patch
from kitty.fast_data_types import LEFT_EDGE, Region
from kitty.tab_bar import TabBar, TabBarData
from . import BaseTest
def region(left: int, top: int, right: int, bottom: int) -> Region:
return Region((left, top, right, bottom, right - left, bottom - top))
class DummyBoss:
class mappings:
current_keyboard_mode_name = ''
def tab_for_id(self, tab_id: int) -> None:
return None
class TestTabBar(BaseTest):
def test_vertical_tab_bar_hit_testing(self) -> None:
self.set_options({
'tab_bar_edge': LEFT_EDGE,
'tab_bar_style': 'separator',
'tab_title_template': '{title}',
})
central = region(120, 0, 400, 160)
tab_bar = region(0, 0, 120, 160)
geometries: list[tuple[int, int, int, int]] = []
boss = DummyBoss()
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, 400, 160, 10, 20)),
patch('kitty.tab_bar.set_tab_bar_render_data', side_effect=lambda *args: geometries.append(args[2:6])),
patch('kitty.tab_bar.get_boss', return_value=boss),
):
tb = TabBar(1)
tb.layout()
tb.update((
TabBarData(title='one', tab_id=1, is_active=True),
TabBarData(title='two', tab_id=2),
TabBarData(title='three', tab_id=3),
))
self.assertTrue(tb.is_vertical)
self.ae(geometries[-1], (0, 0, 120, 160))
self.ae(tb.drag_axis_coordinate(5, 35), 35)
self.ae(tb.tab_id_at(5, 10), 1)
self.ae(tb.tab_id_at(110, 35), 1)
self.ae(tb.tab_id_at(60, 55), 2)
self.ae(tb.tab_id_at(60, 95), 3)
self.ae(tb.tab_id_at(60, 135), 0)
self.ae(tb.tab_id_at(180, 10), 0)
def test_vertical_tab_bar_alignment(self) -> None:
self.set_options({
'tab_bar_align': 'end',
'tab_bar_edge': LEFT_EDGE,
'tab_bar_style': 'separator',
'tab_title_template': '{title}',
})
central = region(120, 0, 400, 160)
tab_bar = region(0, 0, 120, 160)
boss = DummyBoss()
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, 400, 160, 10, 20)),
patch('kitty.tab_bar.set_tab_bar_render_data'),
patch('kitty.tab_bar.get_boss', return_value=boss),
):
tb = TabBar(1)
tb.layout()
tb.update((
TabBarData(title='one', tab_id=1, is_active=True),
TabBarData(title='two', tab_id=2),
))
self.ae(tb.tab_extents[0].y, (4, 5))
self.ae(tb.tab_extents[1].y, (6, 7))
self.ae(tb.tab_id_at(5, 10), 0)
self.ae(tb.tab_id_at(5, 110), 1)
self.ae(tb.tab_id_at(5, 150), 2)