Remove --force for :bind and config.bind(...)
Turns out --force is just in the way for most people, and at least for default bindings it's easy to reset them. Also, it makes :config-source fail when config.py contains keybindings. Closes #3049
This commit is contained in:
parent
727580d1f4
commit
22088d9f7b
@ -120,7 +120,7 @@ How many pages to go back.
|
||||
|
||||
[[bind]]
|
||||
=== bind
|
||||
Syntax: +:bind [*--mode* 'mode'] [*--force*] 'key' ['command']+
|
||||
Syntax: +:bind [*--mode* 'mode'] 'key' ['command']+
|
||||
|
||||
Bind a key to a command.
|
||||
|
||||
@ -133,7 +133,6 @@ Bind a key to a command.
|
||||
* +*-m*+, +*--mode*+: A comma-separated list of modes to bind the key in (default: `normal`). See `:help bindings.commands` for the
|
||||
available modes.
|
||||
|
||||
* +*-f*+, +*--force*+: Rebind the key if it is already bound.
|
||||
|
||||
==== note
|
||||
* This command does not split arguments after the last argument and handles quotes literally.
|
||||
|
@ -61,8 +61,6 @@ link:commands.html#unbind[`:unbind`] commands:
|
||||
- Binding the key chain `,v` to the `:spawn mpv {url}` command:
|
||||
`:bind ,v spawn mpv {url}`
|
||||
- Unbinding the same key chain: `:unbind ,v`
|
||||
- Changing an existing binding: `bind --force ,v message-info foo`. Without
|
||||
`--force`, qutebrowser will show an error because `,v` is already bound.
|
||||
|
||||
Key chains starting with a comma are ideal for custom bindings, as the comma key
|
||||
will never be used in a default keybinding.
|
||||
@ -179,13 +177,6 @@ To bind a key in a mode other than `'normal'`, add a `mode` argument:
|
||||
config.bind('<Ctrl-y>', 'prompt-yes', mode='prompt')
|
||||
----
|
||||
|
||||
If the key is already bound, `force=True` needs to be given to rebind it:
|
||||
|
||||
[source,python]
|
||||
----
|
||||
config.bind('<Ctrl-v>', 'message-info foo', force=True)
|
||||
----
|
||||
|
||||
To unbind a key (either a key which has been bound before, or a default binding):
|
||||
|
||||
[source,python]
|
||||
@ -339,10 +330,10 @@ to do so:
|
||||
|
||||
[source,python]
|
||||
----
|
||||
def bind_chained(key, *commands, force=False):
|
||||
config.bind(key, ' ;; '.join(commands), force=force)
|
||||
def bind_chained(key, *commands):
|
||||
config.bind(key, ' ;; '.join(commands))
|
||||
|
||||
bind_chained('<Escape>', 'clear-keychain', 'search', force=True)
|
||||
bind_chained('<Escape>', 'clear-keychain', 'search')
|
||||
----
|
||||
|
||||
Avoiding flake8 errors
|
||||
|
@ -168,13 +168,11 @@ class KeyConfig:
|
||||
bindings = self.get_bindings_for(mode)
|
||||
return bindings.get(key, None)
|
||||
|
||||
def bind(self, key, command, *, mode, force=False, save_yaml=False):
|
||||
def bind(self, key, command, *, mode, save_yaml=False):
|
||||
"""Add a new binding from key to command."""
|
||||
key = self._prepare(key, mode)
|
||||
log.keyboard.vdebug("Adding binding {} -> {} in mode {}.".format(
|
||||
key, command, mode))
|
||||
if key in self.get_bindings_for(mode) and not force:
|
||||
raise configexc.DuplicateKeyError(key)
|
||||
|
||||
bindings = self._config.get_obj('bindings.commands')
|
||||
if mode not in bindings:
|
||||
|
@ -92,7 +92,7 @@ class ConfigCommands:
|
||||
@cmdutils.register(instance='config-commands', maxsplit=1,
|
||||
no_cmd_split=True, no_replace_variables=True)
|
||||
@cmdutils.argument('command', completion=configmodel.bind)
|
||||
def bind(self, key, command=None, *, mode='normal', force=False):
|
||||
def bind(self, key, command=None, *, mode='normal'):
|
||||
"""Bind a key to a command.
|
||||
|
||||
Args:
|
||||
@ -102,7 +102,6 @@ class ConfigCommands:
|
||||
mode: A comma-separated list of modes to bind the key in
|
||||
(default: `normal`). See `:help bindings.commands` for the
|
||||
available modes.
|
||||
force: Rebind the key if it is already bound.
|
||||
"""
|
||||
if command is None:
|
||||
if utils.is_special_key(key):
|
||||
@ -118,11 +117,7 @@ class ConfigCommands:
|
||||
return
|
||||
|
||||
try:
|
||||
self._keyconfig.bind(key, command, mode=mode, force=force,
|
||||
save_yaml=True)
|
||||
except configexc.DuplicateKeyError as e:
|
||||
raise cmdexc.CommandError("bind: {} - use --force to override!"
|
||||
.format(e))
|
||||
self._keyconfig.bind(key, command, mode=mode, save_yaml=True)
|
||||
except configexc.KeybindingError as e:
|
||||
raise cmdexc.CommandError("bind: {}".format(e))
|
||||
|
||||
|
@ -59,14 +59,6 @@ class KeybindingError(Error):
|
||||
"""Raised for issues with keybindings."""
|
||||
|
||||
|
||||
class DuplicateKeyError(KeybindingError):
|
||||
|
||||
"""Raised when there was a duplicate key."""
|
||||
|
||||
def __init__(self, key):
|
||||
super().__init__("Duplicate key {}".format(key))
|
||||
|
||||
|
||||
class NoOptionError(Error):
|
||||
|
||||
"""Raised when an option was not found."""
|
||||
|
@ -236,13 +236,9 @@ class ConfigAPI:
|
||||
with self._handle_error('setting', name):
|
||||
self._config.set_obj(name, value)
|
||||
|
||||
def bind(self, key, command, mode='normal', *, force=False):
|
||||
def bind(self, key, command, mode='normal'):
|
||||
with self._handle_error('binding', key):
|
||||
try:
|
||||
self._keyconfig.bind(key, command, mode=mode, force=force)
|
||||
except configexc.DuplicateKeyError as e:
|
||||
raise configexc.KeybindingError('{} - use force=True to '
|
||||
'override!'.format(e))
|
||||
self._keyconfig.bind(key, command, mode=mode)
|
||||
|
||||
def unbind(self, key, mode='normal'):
|
||||
with self._handle_error('unbinding', key):
|
||||
|
@ -246,7 +246,7 @@ Feature: Using hints
|
||||
Scenario: Ignoring key presses after auto-following hints
|
||||
When I set hints.auto_follow_timeout to 1000
|
||||
And I set hints.mode to number
|
||||
And I run :bind --force , message-error "This error message was triggered via a keybinding which should have been inhibited"
|
||||
And I run :bind , message-error "This error message was triggered via a keybinding which should have been inhibited"
|
||||
And I open data/hints/html/simple.html
|
||||
And I hint with args "all"
|
||||
And I press the key "f"
|
||||
@ -259,7 +259,7 @@ Feature: Using hints
|
||||
Scenario: Turning off auto_follow_timeout
|
||||
When I set hints.auto_follow_timeout to 0
|
||||
And I set hints.mode to number
|
||||
And I run :bind --force , message-info "Keypress worked!"
|
||||
And I run :bind , message-info "Keypress worked!"
|
||||
And I open data/hints/html/simple.html
|
||||
And I hint with args "all"
|
||||
And I press the key "f"
|
||||
|
@ -120,7 +120,7 @@ def cmdutils_patch(monkeypatch, stubs, miscmodels_patch):
|
||||
|
||||
@cmdutils.argument('win_id', win_id=True)
|
||||
@cmdutils.argument('command', completion=miscmodels_patch.command)
|
||||
def bind(key, win_id, command=None, *, mode='normal', force=False):
|
||||
def bind(key, win_id, command=None, *, mode='normal'):
|
||||
"""docstring."""
|
||||
pass
|
||||
|
||||
|
@ -172,19 +172,13 @@ class TestKeyConfig:
|
||||
config_stub.val.bindings.commands = {'normal': bindings}
|
||||
assert keyconf.get_reverse_bindings_for('normal') == expected
|
||||
|
||||
@pytest.mark.parametrize('force', [True, False])
|
||||
@pytest.mark.parametrize('key', ['a', '<Ctrl-X>', 'b'])
|
||||
def test_bind_duplicate(self, keyconf, config_stub, force, key):
|
||||
def test_bind_duplicate(self, keyconf, config_stub, key):
|
||||
config_stub.val.bindings.default = {'normal': {'a': 'nop',
|
||||
'<Ctrl+x>': 'nop'}}
|
||||
config_stub.val.bindings.commands = {'normal': {'b': 'nop'}}
|
||||
if force:
|
||||
keyconf.bind(key, 'message-info foo', mode='normal', force=True)
|
||||
assert keyconf.get_command(key, 'normal') == 'message-info foo'
|
||||
else:
|
||||
with pytest.raises(configexc.DuplicateKeyError):
|
||||
keyconf.bind(key, 'message-info foo', mode='normal')
|
||||
assert keyconf.get_command(key, 'normal') == 'nop'
|
||||
keyconf.bind(key, 'message-info foo', mode='normal')
|
||||
assert keyconf.get_command(key, 'normal') == 'message-info foo'
|
||||
|
||||
@pytest.mark.parametrize('mode', ['normal', 'caret'])
|
||||
@pytest.mark.parametrize('command', [
|
||||
|
@ -418,9 +418,8 @@ class TestBind:
|
||||
match='bind: Invalid mode wrongmode!'):
|
||||
commands.bind('a', 'nop', mode='wrongmode')
|
||||
|
||||
@pytest.mark.parametrize('force', [True, False])
|
||||
@pytest.mark.parametrize('key', ['a', 'b', '<Ctrl-X>'])
|
||||
def test_bind_duplicate(self, commands, config_stub, keyconf, force, key):
|
||||
def test_bind_duplicate(self, commands, config_stub, keyconf, key):
|
||||
"""Run ':bind' with a key which already has been bound.'.
|
||||
|
||||
Also tests for https://github.com/qutebrowser/qutebrowser/issues/1544
|
||||
@ -432,15 +431,8 @@ class TestBind:
|
||||
'normal': {'b': 'nop'},
|
||||
}
|
||||
|
||||
if force:
|
||||
commands.bind(key, 'message-info foo', mode='normal', force=True)
|
||||
assert keyconf.get_command(key, 'normal') == 'message-info foo'
|
||||
else:
|
||||
with pytest.raises(cmdexc.CommandError,
|
||||
match="bind: Duplicate key .* - use --force to "
|
||||
"override"):
|
||||
commands.bind(key, 'message-info foo', mode='normal')
|
||||
assert keyconf.get_command(key, 'normal') == 'nop'
|
||||
commands.bind(key, 'message-info foo', mode='normal')
|
||||
assert keyconf.get_command(key, 'normal') == 'message-info foo'
|
||||
|
||||
def test_bind_none(self, commands, config_stub):
|
||||
config_stub.val.bindings.commands = None
|
||||
|
@ -43,12 +43,6 @@ def test_backend_error():
|
||||
assert str(e) == "This setting is not available with the QtWebKit backend!"
|
||||
|
||||
|
||||
def test_duplicate_key_error():
|
||||
e = configexc.DuplicateKeyError('asdf')
|
||||
assert isinstance(e, configexc.KeybindingError)
|
||||
assert str(e) == "Duplicate key asdf"
|
||||
|
||||
|
||||
def test_desc_with_text():
|
||||
"""Test ConfigErrorDesc.with_text."""
|
||||
old = configexc.ConfigErrorDesc("Error text", Exception("Exception text"))
|
||||
|
@ -403,12 +403,11 @@ class TestConfigPy:
|
||||
confpy.read()
|
||||
|
||||
def test_bind_duplicate_key(self, confpy):
|
||||
"""Make sure we get a nice error message on duplicate key bindings."""
|
||||
"""Make sure overriding a keybinding works."""
|
||||
confpy.write("config.bind('H', 'message-info back')")
|
||||
error = confpy.read(error=True)
|
||||
|
||||
expected = "Duplicate key H - use force=True to override!"
|
||||
assert str(error.exception) == expected
|
||||
confpy.read()
|
||||
expected = {'normal': {'H': 'message-info back'}}
|
||||
assert config.instance._values['bindings.commands'] == expected
|
||||
|
||||
def test_bind_none(self, confpy):
|
||||
confpy.write("c.bindings.commands = None",
|
||||
|
Loading…
Reference in New Issue
Block a user