From 9c13e8a5498b2060feb9ae7a48f614314d9d087f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 1 Feb 2022 08:58:49 +0530 Subject: [PATCH] Allow controlling placement of bell and activity symbols in the tab title template Fixes #4581 --- docs/changelog.rst | 5 +++-- kitty/options/definition.py | 25 ++++++++++++++++--------- kitty/options/parse.py | 4 ++-- kitty/options/types.py | 6 +++--- kitty/options/utils.py | 15 ++++++++++++--- kitty/tab_bar.py | 34 ++++++++++------------------------ 6 files changed, 46 insertions(+), 43 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 111134bde..1fd0b141c 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -92,8 +92,9 @@ Detailed list of changes - Improve the UI of the ask kitten (:iss:`4545`) -- Allow using templates with text formatting for :opt:`tab_activity_symbol` - (:pull:`4507`) +- Allow customizing the placement and formatting of the + :opt:`tab_activity_symbol` and :opt:`bell_on_tab` symbols + by adding them to the :opt:`tab_title_template` (:iss:`4581`, :pull:`4507`) - macOS: Persist "Secure Keyboard Entry" across restarts to match the behavior of Terminal.app (:iss:`4471`) diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 1e8812ffb..bded5f131 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -695,11 +695,17 @@ taskbar flash on linux. ''' ) -opt('bell_on_tab', 'yes', - option_type='to_bool', +opt('bell_on_tab', '"🔔 "', + option_type='bell_on_tab', long_text=''' -Show a bell symbol on the tab if a bell occurs in one of the windows in the tab -and the window is not the currently focused window +Some text or a unicode symbol to show on the tab if a window in the tab that +does not have focus has a bell. If you want to use leading or trailing +spaces surround the text with quotes. See :opt:`tab_title_template` for how +this is rendered. + +For backwards compatibility, values of :code:`yes`, :code:`y`, :code:`true` are +converted to the default bell symbol and :code:`no`, :code:`n`, :code:`false`, +:code:`none` are converted to the empty string. ''' ) @@ -1054,16 +1060,15 @@ opt('tab_activity_symbol', 'none', long_text=''' Some text or a unicode symbol to show on the tab if a window in the tab that does not have focus has some activity. If you want to use leading or trailing spaces -surround the text with quotes. You can also use text formatting via the same templating -system as for :opt:`tab_title_template`. +surround the text with quotes. See :opt:`tab_title_template` for how this is rendered. ''' ) -opt('tab_title_template', '"{title}"', +opt('tab_title_template', '"{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.default}{title}"', option_type='tab_title_template', long_text=''' -A template to render the tab title. The default just renders the title. If you -wish to include the tab-index as well, use something like: :code:`{index}: +A template to render the tab title. The default just renders the title with optional symbols for bell and activity. +If you wish to include the tab-index as well, use something like: :code:`{index}: {title}`. Useful if you have shortcuts mapped for :code:`goto_tab N`. If you prefer to see the index as a superscript, use {sup.index}. In addition you can use :code:`{layout_name}` for the current layout name, @@ -1077,6 +1082,8 @@ directives, for example: :code:`{fmt.fg.red}red{fmt.fg.default}normal{fmt.bg._00FF00}green bg{fmt.bg.tab}`. Similarly, for bold and italic: :code:`{fmt.bold}bold{fmt.nobold}normal{fmt.italic}italic{fmt.noitalic}`. +Note that for backward compatibility, if :code:`{bell_symbol}` or :code:`{activity_symbol}` +are not present in the template, they are prepended to it. ''' ) diff --git a/kitty/options/parse.py b/kitty/options/parse.py index 0fd091e1e..950b08c76 100644 --- a/kitty/options/parse.py +++ b/kitty/options/parse.py @@ -7,7 +7,7 @@ from kitty.conf.utils import ( ) from kitty.options.utils import ( action_alias, active_tab_title_template, adjust_baseline, adjust_line_height, allow_hyperlinks, - allow_remote_control, box_drawing_scale, clear_all_mouse_actions, clear_all_shortcuts, + allow_remote_control, bell_on_tab, box_drawing_scale, clear_all_mouse_actions, clear_all_shortcuts, clipboard_control, config_or_absolute_path, copy_on_select, cursor_text_color, deprecated_hide_window_decorations_aliases, deprecated_macos_show_window_title_in_menubar_alias, deprecated_send_text, disable_ligatures, edge_width, env, font_features, hide_window_decorations, @@ -83,7 +83,7 @@ class Parser: ans['bell_border_color'] = to_color(val) def bell_on_tab(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: - ans['bell_on_tab'] = to_bool(val) + ans['bell_on_tab'] = bell_on_tab(val) def bell_path(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['bell_path'] = config_or_absolute_path(val) diff --git a/kitty/options/types.py b/kitty/options/types.py index 1c184d9d3..b069cf239 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -465,7 +465,7 @@ class Options: background_opacity: float = 1.0 background_tint: float = 0 bell_border_color: Color = Color(255, 90, 0) - bell_on_tab: bool = True + bell_on_tab: str = '🔔 ' bell_path: typing.Optional[str] = None bold_font: str = 'auto' bold_italic_font: str = 'auto' @@ -552,7 +552,7 @@ class Options: startup_session: typing.Optional[str] = None strip_trailing_spaces: choices_for_strip_trailing_spaces = 'never' sync_to_monitor: bool = True - tab_activity_symbol: typing.Optional[str] = None + tab_activity_symbol: str = '' tab_bar_align: choices_for_tab_bar_align = 'left' tab_bar_background: typing.Optional[kitty.fast_data_types.Color] = None tab_bar_edge: int = 3 @@ -565,7 +565,7 @@ class Options: tab_powerline_style: choices_for_tab_powerline_style = 'angled' tab_separator: str = ' ┇' tab_switch_strategy: choices_for_tab_switch_strategy = 'previous' - tab_title_template: str = '{title}' + tab_title_template: str = '{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.default}{title}' term: str = 'xterm-kitty' touch_scroll_multiplier: float = 1.0 update_check_interval: float = 24.0 diff --git a/kitty/options/utils.py b/kitty/options/utils.py index 658c44539..3449582d0 100644 --- a/kitty/options/utils.py +++ b/kitty/options/utils.py @@ -639,10 +639,19 @@ def tab_fade(x: str) -> Tuple[float, ...]: return tuple(map(unit_float, x.split())) -def tab_activity_symbol(x: str) -> Optional[str]: +def tab_activity_symbol(x: str) -> str: if x == 'none': - return None - return tab_title_template(x) or None + return '' + return tab_title_template(x) + + +def bell_on_tab(x: str) -> str: + xl = x.lower() + if xl in ('yes', 'y', 'true'): + return '🔔 ' + if xl in ('no', 'n', 'false', 'none'): + return '' + return tab_title_template(x) def tab_title_template(x: str) -> str: diff --git a/kitty/tab_bar.py b/kitty/tab_bar.py index 327dc3bcd..2d025f88d 100644 --- a/kitty/tab_bar.py +++ b/kitty/tab_bar.py @@ -38,8 +38,7 @@ class DrawData(NamedTuple): leading_spaces: int sep: str trailing_spaces: int - bell_on_tab: bool - bell_fg: int + bell_on_tab: str alpha: Sequence[float] active_fg: Color active_bg: Color @@ -48,7 +47,7 @@ class DrawData(NamedTuple): default_bg: Color title_template: str active_title_template: Optional[str] - tab_activity_symbol: Optional[str] + tab_activity_symbol: str powerline_style: PowerlineStyle tab_bar_edge: EdgeLiteral @@ -182,28 +181,16 @@ def draw_title(draw_data: DrawData, screen: Screen, tab: TabBarData, index: int) 'fmt': Formatter, 'sup': SupSub(data), 'sub': SupSub(data, True), + 'bell_symbol': draw_data.bell_on_tab if tab.needs_attention else '', + 'activity_symbol': draw_data.tab_activity_symbol if tab.has_activity_since_last_focus else '', } - if tab.needs_attention and draw_data.bell_on_tab: - fg = screen.cursor.fg - screen.cursor.fg = draw_data.bell_fg - screen.draw('🔔 ') - screen.cursor.fg = fg - if tab.has_activity_since_last_focus and draw_data.tab_activity_symbol: - template = draw_data.tab_activity_symbol - fg = screen.cursor.fg - screen.cursor.fg = draw_data.bell_fg - try: - text = eval(compile_template(template), {'__builtins__': {}}, eval_locals) - except Exception as e: - report_template_failure(template, str(e)) - else: - draw_attributed_string(text, screen) - if screen.cursor.fg == draw_data.bell_fg: - screen.cursor.fg = fg - template = draw_data.title_template if tab.is_active and draw_data.active_title_template is not None: template = draw_data.active_title_template + if '{activity_symbol' not in template: + template = '{fmt.fg.red}{activity_symbol}{fmt.fg.default}' + template + if '{bell_symbol' not in template: + template = '{fmt.fg.red}{bell_symbol}{fmt.fg.default}' + template try: title = eval(compile_template(template), {'__builtins__': {}}, eval_locals) except Exception as e: @@ -445,9 +432,8 @@ class TabBar: self.active_bg = as_rgb(color_as_int(opts.active_tab_background)) self.active_fg = as_rgb(color_as_int(opts.active_tab_foreground)) - self.bell_fg = as_rgb(0xff0000) self.draw_data = DrawData( - self.leading_spaces, self.sep, self.trailing_spaces, opts.bell_on_tab, self.bell_fg, + self.leading_spaces, self.sep, self.trailing_spaces, opts.bell_on_tab, opts.tab_fade, opts.active_tab_foreground, opts.active_tab_background, opts.inactive_tab_foreground, opts.inactive_tab_background, opts.tab_bar_background or opts.background, opts.tab_title_template, @@ -567,7 +553,7 @@ class TabBar: if s.cursor.x > s.columns - max_title_length and t is not last_tab: s.cursor.x = s.columns - 2 s.cursor.bg = as_rgb(color_as_int(self.draw_data.default_bg)) - s.cursor.fg = self.bell_fg + s.cursor.fg = as_rgb(0xff0000) s.draw(' …') break s.erase_in_line(0, False) # Ensure no long titles bleed after the last tab