diff --git a/docs/changelog.rst b/docs/changelog.rst index 6bae033dc..ef8a1ce61 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -34,6 +34,9 @@ To update |kitty|, :doc:`follow the instructions `. - A new remote control command to :program:`visually select a window ` (:iss:`4165`) +- A new :opt:`visual_window_select_characters` option to specify the preferred + alphanumeric characters for visual window select (:pull:`4215`) + - A new option :opt:`background_image_anchor` to *anchor* the background image to a position in the OS Window, useful for displaying images with logos or similar (:pull:`4167`) diff --git a/kitty/boss.py b/kitty/boss.py index 4109a9303..e7ef78292 100755 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -963,18 +963,16 @@ class Boss: return pending_sequences: SubSequenceMap = {} fmap = get_name_to_functional_number_map() - alphabet = '0' + string.ascii_uppercase + alphanumerics = get_options().visual_window_select_characters + if not alphanumerics: + alphanumerics = string.digits[1:] + string.digits[0] + string.ascii_uppercase for idx, window in tab.windows.iter_windows_with_number(only_visible=True): if only_window_ids and window.id not in only_window_ids: continue ac = KeyAction('visual_window_select_action_trigger', (window.id,)) - if idx >= 9: - num = idx - 9 - if num >= len(alphabet): - break - ch = alphabet[num] - else: - ch = str(idx + 1) + if idx >= len(alphanumerics): + break + ch = alphanumerics[idx] window.screen.set_window_char(ch) self.current_visual_select.window_ids.append(window.id) for mods in (0, GLFW_MOD_CONTROL, GLFW_MOD_CONTROL | GLFW_MOD_SHIFT, GLFW_MOD_SUPER, GLFW_MOD_ALT, GLFW_MOD_SHIFT): diff --git a/kitty/options/definition.py b/kitty/options/definition.py index e6dfe618a..79f2bb621 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -888,6 +888,16 @@ does not currently work on Wayland. ''' ) +opt('visual_window_select_characters', '', + option_type='visual_window_select_characters', + long_text=''' +The list of characters to use for visual window select. The value should be a +series of unique numbers or alphabets, case insensitive. The default is the +numbers 1 to 9, 0, and the alphabets A to Z. Specify your preference as a string +of characters. +''' + ) + opt('confirm_os_window_close', '0', option_type='int', long_text=''' diff --git a/kitty/options/parse.py b/kitty/options/parse.py index 45e8d08d0..69e1424f9 100644 --- a/kitty/options/parse.py +++ b/kitty/options/parse.py @@ -15,7 +15,8 @@ from kitty.options.utils import ( parse_mouse_map, resize_draw_strategy, scrollback_lines, scrollback_pager_history_size, symbol_map, tab_activity_symbol, tab_bar_edge, tab_bar_margin_height, tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator, tab_title_template, to_cursor_shape, to_font_size, to_layout_names, - to_modifiers, url_prefixes, url_style, watcher, window_border_width, window_size + to_modifiers, url_prefixes, url_style, visual_window_select_characters, watcher, + window_border_width, window_size ) @@ -1254,6 +1255,9 @@ class Parser: def visual_bell_duration(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['visual_bell_duration'] = positive_float(val) + def visual_window_select_characters(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['visual_window_select_characters'] = visual_window_select_characters(val) + def watcher(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: for k, v in watcher(val, ans["watcher"]): ans["watcher"][k] = v diff --git a/kitty/options/types.py b/kitty/options/types.py index 3c8914140..2c913949e 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -433,6 +433,7 @@ option_names = ( # {{{ 'url_style', 'visual_bell_color', 'visual_bell_duration', + 'visual_window_select_characters', 'watcher', 'wayland_titlebar_color', 'wheel_scroll_multiplier', @@ -573,6 +574,7 @@ class Options: url_style: int = 3 visual_bell_color: typing.Optional[kitty.fast_data_types.Color] = None visual_bell_duration: float = 0 + visual_window_select_characters: str = '' wayland_titlebar_color: int = 0 wheel_scroll_multiplier: float = 5.0 window_alert_on_bell: bool = True diff --git a/kitty/options/utils.py b/kitty/options/utils.py index 3cca64b21..d88e74db3 100644 --- a/kitty/options/utils.py +++ b/kitty/options/utils.py @@ -590,6 +590,17 @@ def resize_draw_strategy(x: str) -> int: return cmap.get(x.lower(), 0) +def visual_window_select_characters(x: str) -> str: + import string + valid_characters = string.digits + string.ascii_uppercase + ans = x.upper() + if not all(ch in valid_characters for ch in ans): + raise ValueError(f'Invalid characters: {x} Only numbers (0-9) and alphabets (a-z,A-Z) are allowed. Ignoring.') + if len(set(ans)) < len(x): + raise ValueError(f'Invalid characters: {x} Contains identical numbers or alphabets, case insensitive. Ignoring.') + return ans + + def tab_separator(x: str) -> str: for q in '\'"': if x.startswith(q) and x.endswith(q):