From efc8b898f87db2bc71d26b7bed743b84c0d021c3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 20 Oct 2017 12:31:36 +0530 Subject: [PATCH] Allow combining multiple independent actions into a single shortcut Fixes #128 --- CHANGELOG.rst | 2 ++ kitty/boss.py | 23 ++++++++++++++++------- kitty/config.py | 26 ++++++++++++++++++-------- kitty/kitty.conf | 9 +++++++++ 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 01c5c5615..57a30b6a5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -29,3 +29,5 @@ version 0.4.0 [future] - The block cursor in now fully opaque but renders the character under it in the background color, for enhanced visibility. + +- Allow combining multiple independent actions into a single shortcut diff --git a/kitty/boss.py b/kitty/boss.py index b27c58a7a..390b57c23 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -168,11 +168,15 @@ class Boss: def dispatch_special_key(self, key, scancode, action, mods): # Handles shortcuts, return True if the key was consumed - action = get_shortcut(self.opts.keymap, mods, key, scancode) - if action is not None: - f = getattr(self, action.func, None) + key_action = get_shortcut(self.opts.keymap, mods, key, scancode) + self.current_key_press_info = key, scancode, action, mods + return self.dispatch_action(key_action) + + def dispatch_action(self, key_action): + if key_action is not None: + f = getattr(self, key_action.func, None) if f is not None: - passthrough = f(*action.args) + passthrough = f(*key_action.args) if passthrough is not True: return True tab = self.active_tab @@ -181,12 +185,13 @@ class Boss: window = self.active_window if window is None: return False - if action is not None: - f = getattr(tab, action.func, getattr(window, action.func, None)) + if key_action is not None: + f = getattr(tab, key_action.func, getattr(window, key_action.func, None)) if f is not None: - passthrough = f(*action.args) + passthrough = f(*key_action.args) if passthrough is not True: return True + key, scancode, action, mods = self.current_key_press_info data = get_sent_data( self.opts.send_text_map, key, scancode, mods, window, action ) @@ -195,6 +200,10 @@ class Boss: return True return False + def combine(self, *actions): + for key_action in actions: + self.dispatch_action(key_action) + def on_focus(self, window, focused): self.window_is_focused = focused w = self.active_window diff --git a/kitty/config.py b/kitty/config.py index 234581cb2..36af997b5 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -98,12 +98,15 @@ KeyAction = namedtuple('KeyAction', 'func args') def parse_key_action(action): parts = action.split(' ', 1) + func = parts[0] if len(parts) == 1: - return KeyAction(parts[0], ()) - safe_print( - 'Invalid shortcut action: {}. Ignoring.'.format(action), - file=sys.stderr - ) + return KeyAction(func, ()) + rest = parts[1] + if func == 'combine': + sep, rest = rest.split(' ', 1) + parts = re.split(r'\s*' + re.escape(sep) + r'\s*', rest) + args = tuple(map(parse_key_action, parts)) + return KeyAction(func, args) def parse_key(val, keymap): @@ -118,9 +121,16 @@ def parse_key(val, keymap): file=sys.stderr ) return - paction = parse_key_action(action) - if paction is not None: - keymap[(mods, key)] = paction + try: + paction = parse_key_action(action) + except Exception: + safe_print( + 'Invalid shortcut action: {}. Ignoring.'.format(action), + file=sys.stderr + ) + else: + if paction is not None: + keymap[(mods, key)] = paction def parse_symbol_map(val): diff --git a/kitty/kitty.conf b/kitty/kitty.conf index 5059db8b8..f960ef2f1 100644 --- a/kitty/kitty.conf +++ b/kitty/kitty.conf @@ -198,11 +198,20 @@ color14 #14ffff color7 #dddddd color15 #ffffff + # Key mapping # For a list of key names, see: http://www.glfw.org/docs/latest/group__keys.html # For a list of modifier names, see: http://www.glfw.org/docs/latest/group__mods.html +# # You can use the special action no_op to unmap a keyboard shortcut that is # assigned in the default configuration. +# +# You can combine multiple actions to be triggered by a single shortcut, using the +# syntax below: +# map key combine action1 action2 action3 ... +# For example: +map ctrl+shift+e combine : new_window : next_layout +# this will create a new window and switch to the next available layout # Clipboard map ctrl+shift+v paste_from_clipboard