Skip to content

Commit 8d93548

Browse files
committed
tabbar: address vertical alignment feedback
1 parent 19ea73f commit 8d93548

7 files changed

Lines changed: 98 additions & 49 deletions

File tree

kitty/options/definition.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,12 +1679,12 @@
16791679
are automatically restricted to work only on matching tabs.
16801680
''')
16811681

1682-
opt('tab_bar_align', 'left',
1683-
choices=('left', 'center', 'right'),
1682+
opt('tab_bar_align', 'start',
1683+
choices=('start', 'center', 'end', 'left', 'right'),
16841684
long_text='''
1685-
The horizontal alignment of the tab bar. For vertical tab bars this controls the
1686-
alignment of each tab title within the sidebar. Can be one of: :code:`left`,
1687-
:code:`center`, :code:`right`.
1685+
The alignment of the tab bar, can be one of: :code:`start`, :code:`center`,
1686+
:code:`end`, :code:`left`, :code:`right`. The values :code:`left` and
1687+
:code:`right` are aliases for :code:`start` and :code:`end` respectively.
16881688
'''
16891689
)
16901690

kitty/options/parse.py

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

kitty/options/to-c-generated.h

Lines changed: 15 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

kitty/options/types.py

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

kitty/tab_bar.py

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ def as_rgb(x: int) -> int:
103103

104104

105105
VERTICAL_EDGES = frozenset({LEFT_EDGE, RIGHT_EDGE})
106+
MAX_VERTICAL_TAB_LINES = 2
106107

107108

108109
def is_vertical_edge(edge: int) -> bool:
@@ -118,6 +119,14 @@ def edge_name(edge: int) -> EdgeLiteral:
118119
}.get(edge, 'bottom')
119120

120121

122+
def normalized_tab_bar_align(align: str) -> str:
123+
if align == 'left':
124+
return 'start'
125+
if align == 'right':
126+
return 'end'
127+
return align
128+
129+
121130
@lru_cache
122131
def report_template_failure(template: str, e: str) -> None:
123132
log_error(f'Invalid tab title template: "{template}" with error: {e}')
@@ -657,15 +666,16 @@ def apply_options(self) -> None:
657666
self.draw_func = load_custom_draw_tab()
658667
else:
659668
self.draw_func = draw_tab_with_fade
660-
if opts.tab_bar_align == 'center':
669+
self.tab_bar_align = normalized_tab_bar_align(opts.tab_bar_align)
670+
if self.tab_bar_align == 'center':
661671
self.align_factor = 2
662-
elif opts.tab_bar_align == 'right':
672+
elif self.tab_bar_align == 'end':
663673
self.align_factor = 1
664674
else:
665675
self.align_factor = 0
666-
if opts.tab_bar_align == 'center':
676+
if self.tab_bar_align == 'center':
667677
self.align: Callable[[], None] = partial(self.align_with_factor, 2)
668-
elif opts.tab_bar_align == 'right':
678+
elif self.tab_bar_align == 'end':
669679
self.align = self.align_with_factor
670680
else:
671681
self.align = lambda: None
@@ -886,23 +896,33 @@ def update_vertical(self, data: Sequence[TabBarData]) -> None:
886896
if not data:
887897
return
888898
max_tab_length = max(1, s.columns - 1)
889-
rows_to_draw = min(len(data), s.lines)
890-
draw_ellipsis = len(data) > s.lines and s.lines > 1
899+
tab_line_height = max(1, min(MAX_VERTICAL_TAB_LINES, s.lines // max(1, len(data))))
900+
rows_to_draw = min(len(data), max(1, s.lines // tab_line_height))
901+
draw_ellipsis = len(data) > rows_to_draw and s.lines > 1
891902
if draw_ellipsis:
903+
tab_line_height = 1
904+
rows_to_draw = min(len(data), s.lines)
892905
rows_to_draw -= 1
906+
total_lines = rows_to_draw * tab_line_height + int(draw_ellipsis)
907+
if self.tab_bar_align == 'center':
908+
start_row = max(0, (s.lines - total_lines) // 2)
909+
elif self.tab_bar_align == 'end':
910+
start_row = max(0, s.lines - total_lines)
911+
else:
912+
start_row = 0
893913
cr: list[TabExtent] = []
894914
for i, t in enumerate(data[:rows_to_draw]):
895915
s.cursor.x = 0
896-
s.cursor.y = i
916+
row = start_row + i * tab_line_height
917+
s.cursor.y = row
897918
s.cursor.bg = as_rgb(self.draw_data.tab_bg(t))
898919
s.cursor.fg = as_rgb(self.draw_data.tab_fg(t))
899920
s.cursor.bold, s.cursor.italic = self.active_font_style if t.is_active else self.inactive_font_style
900-
end = self.draw_func(self.draw_data, s, t, 0, max_tab_length, i + 1, True, ExtraData())
901-
self.align_row(i, end)
902-
cr.append(TabExtent(tab_id=t.tab_id, x=CellRange(0, s.columns - 1), y=CellRange(i, i)))
921+
self.draw_func(self.draw_data, s, t, 0, max_tab_length, i + 1, True, ExtraData())
922+
cr.append(TabExtent(tab_id=t.tab_id, x=CellRange(0, s.columns - 1), y=CellRange(row, min(s.lines - 1, row + tab_line_height - 1))))
903923
if draw_ellipsis:
904924
s.cursor.x = 0
905-
s.cursor.y = s.lines - 1
925+
s.cursor.y = start_row + rows_to_draw * tab_line_height
906926
s.cursor.bg = as_rgb(color_as_int(self.draw_data.default_bg))
907927
s.cursor.fg = as_rgb(0xff0000)
908928
s.draw('…')
@@ -918,16 +938,6 @@ def align_with_factor(self, factor: int = 1) -> None:
918938
self.screen.insert_characters(shift)
919939
self.tab_extents = tuple(te.shifted(x=shift) for te in self.tab_extents)
920940

921-
def align_row(self, row: int, end: int) -> None:
922-
if not self.align_factor:
923-
return
924-
if end < self.screen.columns - 1:
925-
shift = (self.screen.columns - end) // self.align_factor
926-
if shift > 0:
927-
self.screen.cursor.y = row
928-
self.screen.cursor.x = 0
929-
self.screen.insert_characters(shift)
930-
931941
def destroy(self) -> None:
932942
self.screen.reset_callbacks()
933943
del self.screen

kitty_tests/options.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,14 @@ def keys_for_func(opts, name):
259259
self.ae(opts.tab_bar_edge, LEFT_EDGE)
260260
opts = p('tab_bar_edge right')
261261
self.ae(opts.tab_bar_edge, RIGHT_EDGE)
262+
opts = p('tab_bar_align start')
263+
self.ae(opts.tab_bar_align, 'start')
264+
opts = p('tab_bar_align end')
265+
self.ae(opts.tab_bar_align, 'end')
266+
opts = p('tab_bar_align left')
267+
self.ae(opts.tab_bar_align, 'left')
268+
opts = p('tab_bar_align right')
269+
self.ae(opts.tab_bar_align, 'right')
262270
opts = p('clear_all_shortcuts y', 'map f1 next_window')
263271
self.ae(len(opts.keyboard_modes[''].keymap), 1)
264272
opts = p('clear_all_mouse_actions y', 'mouse_map left click ungrabbed mouse_click_url_or_select')

kitty_tests/tab_bar.py

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,38 @@ def test_vertical_tab_bar_hit_testing(self) -> None:
5252
self.ae(geometries[-1], (0, 0, 120, 160))
5353
self.ae(tb.drag_axis_coordinate(5, 35), 35)
5454
self.ae(tb.tab_id_at(5, 10), 1)
55-
self.ae(tb.tab_id_at(110, 35), 2)
56-
self.ae(tb.tab_id_at(60, 55), 3)
57-
self.ae(tb.tab_id_at(60, 95), 0)
55+
self.ae(tb.tab_id_at(110, 35), 1)
56+
self.ae(tb.tab_id_at(60, 55), 2)
57+
self.ae(tb.tab_id_at(60, 95), 3)
58+
self.ae(tb.tab_id_at(60, 135), 0)
5859
self.ae(tb.tab_id_at(180, 10), 0)
60+
61+
def test_vertical_tab_bar_alignment(self) -> None:
62+
self.set_options({
63+
'tab_bar_align': 'end',
64+
'tab_bar_edge': LEFT_EDGE,
65+
'tab_bar_style': 'separator',
66+
'tab_title_template': '{title}',
67+
})
68+
central = region(120, 0, 400, 160)
69+
tab_bar = region(0, 0, 120, 160)
70+
boss = DummyBoss()
71+
72+
with (
73+
patch('kitty.tab_bar.cell_size_for_window', return_value=(10, 20)),
74+
patch('kitty.tab_bar.viewport_for_window', return_value=(central, tab_bar, 400, 160, 10, 20)),
75+
patch('kitty.tab_bar.set_tab_bar_render_data'),
76+
patch('kitty.tab_bar.get_boss', return_value=boss),
77+
):
78+
tb = TabBar(1)
79+
tb.layout()
80+
tb.update((
81+
TabBarData(title='one', tab_id=1, is_active=True),
82+
TabBarData(title='two', tab_id=2),
83+
))
84+
85+
self.ae(tb.tab_extents[0].y, (4, 5))
86+
self.ae(tb.tab_extents[1].y, (6, 7))
87+
self.ae(tb.tab_id_at(5, 10), 0)
88+
self.ae(tb.tab_id_at(5, 110), 1)
89+
self.ae(tb.tab_id_at(5, 150), 2)

0 commit comments

Comments
 (0)