diff --git a/kitty/config_data.py b/kitty/config_data.py index 39ecd0bac..e7f48a809 100644 --- a/kitty/config_data.py +++ b/kitty/config_data.py @@ -679,10 +679,10 @@ Which edge to show the tab bar on, top or bottom''')) o('tab_bar_margin_width', 0.0, option_type=positive_float, long_text=_(''' The margin to the left and right of the tab bar (in pts)''')) -o('tab_bar_style', 'fade', option_type=choices('fade', 'separator', 'hidden'), long_text=_(''' -The tab bar style, can be one of: :code:`fade`, :code:`separator` or :code:`hidden`. In the fade style, -each tab's edges fade into the background color, in the separator style, tabs are -separated by a configurable separator. +o('tab_bar_style', 'fade', option_type=choices('fade', 'separator', 'powerline', 'hidden'), long_text=_(''' +The tab bar style, can be one of: :code:`fade`, :code:`separator`, :code:`powerline`, or :code:`hidden`. +In the fade style, each tab's edges fade into the background color, in the separator style, tabs are +separated by a configurable separator, and the powerline shows the tabs as a continuous line. ''')) o('tab_bar_min_tabs', 2, option_type=lambda x: max(1, positive_int(x)), long_text=_(''' diff --git a/kitty/tab_bar.py b/kitty/tab_bar.py index 9db6a5785..0e9dbfb51 100644 --- a/kitty/tab_bar.py +++ b/kitty/tab_bar.py @@ -18,7 +18,7 @@ from .rgb import alpha_blend, color_from_int TabBarData = namedtuple('TabBarData', 'title is_active needs_attention') DrawData = namedtuple( 'DrawData', 'leading_spaces sep trailing_spaces bell_on_tab' - ' bell_fg alpha active_bg inactive_bg default_bg title_template') + ' bell_fg alpha active_fg active_bg inactive_fg inactive_bg default_bg title_template') def as_rgb(x): @@ -41,7 +41,7 @@ def draw_title(draw_data, screen, tab, index): screen.draw(title) -def draw_tab_with_separator(draw_data, screen, tab, before, max_title_length, index): +def draw_tab_with_separator(draw_data, screen, tab, before, max_title_length, index, is_last): if draw_data.leading_spaces: screen.draw(' ' * draw_data.leading_spaces) draw_title(draw_data, screen, tab, index) @@ -60,7 +60,7 @@ def draw_tab_with_separator(draw_data, screen, tab, before, max_title_length, in return end -def draw_tab_with_fade(draw_data, screen, tab, before, max_title_length, index): +def draw_tab_with_fade(draw_data, screen, tab, before, max_title_length, index, is_last): tab_bg = draw_data.active_bg if tab.is_active else draw_data.inactive_bg fade_colors = [as_rgb(color_as_int(alpha_blend(tab_bg, draw_data.default_bg, alpha))) for alpha in draw_data.alpha] for bg in fade_colors: @@ -87,6 +87,55 @@ def draw_tab_with_fade(draw_data, screen, tab, before, max_title_length, index): return end +def draw_tab_with_powerline(draw_data, screen, tab, before, max_title_length, index, is_last): + tab_bg = as_rgb(color_as_int(draw_data.active_bg if tab.is_active else draw_data.inactive_bg)) + tab_fg = as_rgb(color_as_int(draw_data.active_fg if tab.is_active else draw_data.inactive_fg)) + inactive_bg = as_rgb(color_as_int(draw_data.inactive_bg)) + default_bg = as_rgb(color_as_int(draw_data.default_bg)) + + min_title_length = 1 + 2 + + if screen.cursor.x + min_title_length >= screen.columns: + screen.cursor.x -= 2 + screen.cursor.bg = default_bg + screen.cursor.fg = inactive_bg + screen.draw(' ') + return screen.cursor.x + + if tab.is_active and screen.cursor.x >= 2: + screen.cursor.x -= 2 + screen.cursor.fg = inactive_bg + screen.cursor.bg = tab_bg + screen.draw(' ') + screen.cursor.fg = tab_fg + elif screen.cursor.x == 0: + screen.draw(' ') + + if min_title_length >= max_title_length: + screen.draw('…') + else: + draw_title(draw_data, screen, tab, index) + extra = screen.cursor.x + 2 - before - max_title_length + if extra > 0 and extra + 1 < screen.cursor.x: + screen.cursor.x -= extra + 1 + screen.draw('…') + + if tab.is_active or is_last: + screen.draw(' ') + screen.cursor.fg = tab_bg + if is_last: + screen.cursor.bg = default_bg + else: + screen.cursor.bg = inactive_bg + screen.draw('') + else: + screen.draw(' ') + + end = screen.cursor.x + screen.draw(' ') + return end + + class TabBar: def __init__(self, os_window_id, opts): @@ -123,10 +172,16 @@ class TabBar: self.bell_fg = as_rgb(0xff0000) self.draw_data = DrawData( self.leading_spaces, self.sep, self.trailing_spaces, self.opts.bell_on_tab, self.bell_fg, - self.opts.tab_fade, self.opts.active_tab_background, self.opts.inactive_tab_background, + self.opts.tab_fade, self.opts.active_tab_foreground, self.opts.active_tab_background, + self.opts.inactive_tab_foreground, self.opts.inactive_tab_background, self.opts.background, self.opts.tab_title_template ) - self.draw_func = draw_tab_with_separator if self.opts.tab_bar_style == 'separator' else draw_tab_with_fade + if self.opts.tab_bar_style == 'separator': + self.draw_func = draw_tab_with_separator + elif self.opts.tab_bar_style == 'powerline': + self.draw_func = draw_tab_with_powerline + else: + self.draw_func = draw_tab_with_fade def patch_colors(self, spec): if 'active_tab_foreground' in spec: @@ -179,7 +234,7 @@ class TabBar: s.cursor.fg = self.active_fg if t.is_active else 0 s.cursor.bold, s.cursor.italic = self.active_font_style if t.is_active else self.inactive_font_style before = s.cursor.x - end = self.draw_func(self.draw_data, s, t, before, max_title_length, i + 1) + end = self.draw_func(self.draw_data, s, t, before, max_title_length, i + 1, t is last_tab) cr.append((before, end)) if s.cursor.x > s.columns - max_title_length and t is not last_tab: s.draw('…')