diff --git a/qutebrowser/config/config.py b/qutebrowser/config/config.py index 7e2bba403..c1c0e790b 100644 --- a/qutebrowser/config/config.py +++ b/qutebrowser/config/config.py @@ -131,10 +131,20 @@ class KeyConfig: def __init__(self, config): self._config = config + def get_bindings_for(self, mode): + """Get the combined bindings for the given mode.""" + if val.bindings.default: + bindings = dict(val.bindings.default[mode]) + else: + bindings = {} + if val.bindings.commands: + bindings.update(val.bindings.default[mode]) + return bindings + def get_reverse_bindings_for(self, mode): """Get a dict of commands to a list of bindings for the mode.""" cmd_to_keys = {} - bindings = val.bindings.commands[mode] + bindings = self.get_bindings_for(mode) if bindings is None: return cmd_to_keys for key, full_cmd in bindings.items(): @@ -150,7 +160,7 @@ class KeyConfig: def _prepare(self, key, mode): """Make sure the given mode exists and normalize the key.""" - if mode not in val.bindings.commands: + if mode not in configdata.DATA['bindings.default'].default: raise configexc.KeybindingError("Invalid mode {}!".format(mode)) if utils.is_special_key(key): # , , and should be considered equivalent @@ -173,24 +183,29 @@ class KeyConfig: except cmdexc.PrerequisitesError as e: raise configexc.KeybindingError(str(e)) - bindings = instance.get_obj('bindings.commands')[mode] - log.keyboard.vdebug("Adding binding {} -> {} in mode {}.".format( key, command, mode)) - if key in bindings and not force: + if key in self.get_bindings_for(mode) and not force: raise configexc.DuplicateKeyError(key) - bindings[key] = command + + val.bindings.commands[mode][key] = command self._config.update_mutables(save_yaml=save_yaml) def unbind(self, key, *, mode='normal', save_yaml=False): """Unbind the given key in the given mode.""" key = self._prepare(key, mode) - bindings = instance.get_obj('bindings.commands')[mode] - try: - del bindings[key] - except KeyError: + + if val.bindings.commands[mode] and key in val.bindings.commands[mode]: + # In custom bindings -> remove it + del val.bindings.commands[mode][key] + elif val.bindings.default[mode] and key in val.bindings.default[mode]: + # In default bindings -> shadow it with + # FIXME:conf what value to use here? + val.bindings.commands[mode][key] = '' + else: raise configexc.KeybindingError("Can't find binding '{}' in section '{}'!" .format(key, mode)) + self._config.update_mutables(save_yaml=save_yaml) def get_command(self, key, mode): @@ -302,14 +317,11 @@ class ConfigCommands: (default: `normal`). force: Rebind the key if it is already bound. """ - if utils.is_special_key(key): - # , , and should be considered equivalent - key = utils.normalize_keystr(key) - - if mode not in val.bindings.commands: - raise cmdexc.CommandError("Invalid mode {}!".format(mode)) - if command is None: + if utils.is_special_key(key): + # key_instance.get_command does this, but we also need it + # normalized for the output below + key = utils.normalize_keystr(key) cmd = key_instance.get_command(key, mode) if cmd is None: message.info("{} is unbound in {} mode".format(key, mode)) diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index bd34cd1bc..bcb3ab548 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -1822,7 +1822,7 @@ bindings.key_mappings: This is useful for global remappings of keys, for example to map Ctrl-[ to Escape. -bindings.commands: +bindings.default: default: normal: : clear-keychain ;; search ;; fullscreen --leave @@ -2067,6 +2067,38 @@ bindings.commands: : leave-mode type: name: Dict + none_ok: true + keytype: String # section name + fixed_keys: ['normal', 'insert', 'hint', 'passthrough', 'command', + 'prompt', 'caret', 'register'] + valtype: + name: Dict + keytype: Key + valtype: Command + desc: >- + Default keybindings. If you want to add bindings, modify + `bindings.commands` instead. + + The main purpose of this setting is that you can set it to an empty dictionary if you + want to load no default keybindings at all. + + If you want to preserve default bindings (and get new bindings when there is + an update), add new bindings to `bindings.commands` (or use `:bind`) and + leave this setting alone. + +bindings.commands: + default: {} + # normal: {} + # insert: {} + # hint: {} + # passthrough: {} + # command: {} + # prompt: {} + # caret: {} + # register: {} + type: + name: Dict + none_ok: true keytype: String # section name fixed_keys: ['normal', 'insert', 'hint', 'passthrough', 'command', 'prompt', 'caret', 'register'] diff --git a/qutebrowser/keyinput/basekeyparser.py b/qutebrowser/keyinput/basekeyparser.py index 5726962db..3f62f025a 100644 --- a/qutebrowser/keyinput/basekeyparser.py +++ b/qutebrowser/keyinput/basekeyparser.py @@ -345,7 +345,7 @@ class BaseKeyParser(QObject): self.bindings = {} self.special_bindings = {} - for key, cmd in config.val.bindings.commands[modename].items(): + for key, cmd in config.key_instance.get_bindings_for(modename).items(): assert cmd self._parse_key_command(modename, key, cmd) diff --git a/qutebrowser/misc/keyhintwidget.py b/qutebrowser/misc/keyhintwidget.py index 06edaab68..4592c39b2 100644 --- a/qutebrowser/misc/keyhintwidget.py +++ b/qutebrowser/misc/keyhintwidget.py @@ -96,11 +96,12 @@ class KeyHintView(QLabel): return any(fnmatch.fnmatchcase(keychain, glob) for glob in blacklist) - if config.val.bindings.commands[modename] is None: + bindings_dict = config.key_instance.get_bindings_for(modename) + if not bindings_dict: bindings = [] else: bindings = [(k, v) for (k, v) - in config.val.bindings.commands[modename].items() + in bindings_dict.items() if k.startswith(prefix) and not utils.is_special_key(k) and not blacklisted(k)]