Remove support for ambiguous keybindings
This commit is contained in:
parent
bf9d401198
commit
1fc9817cd4
@ -191,7 +191,6 @@
|
||||
|<<hints.uppercase,hints.uppercase>>|Make chars in hint strings uppercase.
|
||||
|<<history_gap_interval,history_gap_interval>>|The maximum time in minutes between two history items for them to be considered being from the same browsing session.
|
||||
|<<ignore_case,ignore_case>>|Find text on a page case-insensitively.
|
||||
|<<input.ambiguous_timeout,input.ambiguous_timeout>>|Timeout (in milliseconds) for ambiguous key bindings.
|
||||
|<<input.forward_unbound_keys,input.forward_unbound_keys>>|Forward unbound keys to the webview in normal mode.
|
||||
|<<input.insert_mode.auto_leave,input.insert_mode.auto_leave>>|Leave insert mode if a non-editable element is clicked.
|
||||
|<<input.insert_mode.auto_load,input.insert_mode.auto_load>>|Automatically enter insert mode if an editable element is focused after loading the page.
|
||||
@ -2050,13 +2049,6 @@ Valid values:
|
||||
|
||||
Default: +pass:[smart]+
|
||||
|
||||
[[input.ambiguous_timeout]]
|
||||
== input.ambiguous_timeout
|
||||
Timeout (in milliseconds) for ambiguous key bindings.
|
||||
If the current input forms both a complete match and a partial match, the complete match will be executed after this time.
|
||||
|
||||
Default: +pass:[500]+
|
||||
|
||||
[[input.forward_unbound_keys]]
|
||||
== input.forward_unbound_keys
|
||||
Forward unbound keys to the webview in normal mode.
|
||||
|
@ -794,19 +794,6 @@ hints.uppercase:
|
||||
|
||||
## input
|
||||
|
||||
# FIXME:conf get rid of this?
|
||||
input.ambiguous_timeout:
|
||||
default: 500
|
||||
type:
|
||||
name: Int
|
||||
minval: 0
|
||||
maxval: maxint
|
||||
desc: >-
|
||||
Timeout (in milliseconds) for ambiguous key bindings.
|
||||
|
||||
If the current input forms both a complete match and a partial match, the complete
|
||||
match will be executed after this time.
|
||||
|
||||
input.forward_unbound_keys:
|
||||
default: auto
|
||||
type:
|
||||
|
@ -20,7 +20,6 @@
|
||||
"""Base class for vim-like key sequence parser."""
|
||||
|
||||
import re
|
||||
import functools
|
||||
import unicodedata
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, QObject
|
||||
@ -41,7 +40,6 @@ class BaseKeyParser(QObject):
|
||||
partial: No keychain matched yet, but it's still possible in the
|
||||
future.
|
||||
definitive: Keychain matches exactly.
|
||||
ambiguous: There are both a partial and a definitive match.
|
||||
none: No more matches possible.
|
||||
|
||||
Types: type of a key binding.
|
||||
@ -59,7 +57,6 @@ class BaseKeyParser(QObject):
|
||||
_warn_on_keychains: Whether a warning should be logged when binding
|
||||
keychains in a section which does not support them.
|
||||
_keystring: The currently entered key sequence
|
||||
_ambiguous_timer: Timer for delayed execution with ambiguous bindings.
|
||||
_modename: The name of the input mode associated with this keyparser.
|
||||
_supports_count: Whether count is supported
|
||||
_supports_chains: Whether keychains are supported
|
||||
@ -78,16 +75,13 @@ class BaseKeyParser(QObject):
|
||||
do_log = True
|
||||
passthrough = False
|
||||
|
||||
Match = usertypes.enum('Match', ['partial', 'definitive', 'ambiguous',
|
||||
'other', 'none'])
|
||||
Match = usertypes.enum('Match', ['partial', 'definitive', 'other', 'none'])
|
||||
Type = usertypes.enum('Type', ['chain', 'special'])
|
||||
|
||||
def __init__(self, win_id, parent=None, supports_count=None,
|
||||
supports_chains=False):
|
||||
super().__init__(parent)
|
||||
self._win_id = win_id
|
||||
self._ambiguous_timer = usertypes.Timer(self, 'ambiguous-match')
|
||||
self._ambiguous_timer.setSingleShot(True)
|
||||
self._modename = None
|
||||
self._keystring = ''
|
||||
if supports_count is None:
|
||||
@ -189,7 +183,6 @@ class BaseKeyParser(QObject):
|
||||
self._debug_log("Ignoring, no text char")
|
||||
return self.Match.none
|
||||
|
||||
self._stop_timers()
|
||||
key_mappings = config.val.bindings.key_mappings
|
||||
txt = key_mappings.get(txt, txt)
|
||||
self._keystring += txt
|
||||
@ -207,10 +200,6 @@ class BaseKeyParser(QObject):
|
||||
self._keystring))
|
||||
self.clear_keystring()
|
||||
self.execute(binding, self.Type.chain, count)
|
||||
elif match == self.Match.ambiguous:
|
||||
self._debug_log("Ambiguous match for '{}'.".format(
|
||||
self._keystring))
|
||||
self._handle_ambiguous_match(binding, count)
|
||||
elif match == self.Match.partial:
|
||||
self._debug_log("No match for '{}' (added {})".format(
|
||||
self._keystring, txt))
|
||||
@ -230,11 +219,9 @@ class BaseKeyParser(QObject):
|
||||
|
||||
Return:
|
||||
A tuple (matchtype, binding).
|
||||
matchtype: Match.definitive, Match.ambiguous, Match.partial or
|
||||
Match.none
|
||||
binding: - None with Match.partial/Match.none
|
||||
- The found binding with Match.definitive/
|
||||
Match.ambiguous
|
||||
matchtype: Match.definitive, Match.partial or Match.none.
|
||||
binding: - None with Match.partial/Match.none.
|
||||
- The found binding with Match.definitive.
|
||||
"""
|
||||
# A (cmd_input, binding) tuple (k, v of bindings) or None.
|
||||
definitive_match = None
|
||||
@ -252,58 +239,13 @@ class BaseKeyParser(QObject):
|
||||
elif binding.startswith(cmd_input):
|
||||
partial_match = True
|
||||
break
|
||||
if definitive_match is not None and partial_match:
|
||||
return (self.Match.ambiguous, definitive_match[1])
|
||||
elif definitive_match is not None:
|
||||
if definitive_match is not None:
|
||||
return (self.Match.definitive, definitive_match[1])
|
||||
elif partial_match:
|
||||
return (self.Match.partial, None)
|
||||
else:
|
||||
return (self.Match.none, None)
|
||||
|
||||
def _stop_timers(self):
|
||||
"""Stop a delayed execution if any is running."""
|
||||
if self._ambiguous_timer.isActive() and self.do_log:
|
||||
log.keyboard.debug("Stopping delayed execution.")
|
||||
self._ambiguous_timer.stop()
|
||||
try:
|
||||
self._ambiguous_timer.timeout.disconnect()
|
||||
except TypeError:
|
||||
# no connections
|
||||
pass
|
||||
|
||||
def _handle_ambiguous_match(self, binding, count):
|
||||
"""Handle an ambiguous match.
|
||||
|
||||
Args:
|
||||
binding: The command-string to execute.
|
||||
count: The count to pass.
|
||||
"""
|
||||
self._debug_log("Ambiguous match for '{}'".format(self._keystring))
|
||||
time = config.val.input.ambiguous_timeout
|
||||
if time == 0:
|
||||
# execute immediately
|
||||
self.clear_keystring()
|
||||
self.execute(binding, self.Type.chain, count)
|
||||
else:
|
||||
# execute in `time' ms
|
||||
self._debug_log("Scheduling execution of {} in {}ms".format(
|
||||
binding, time))
|
||||
self._ambiguous_timer.setInterval(time)
|
||||
self._ambiguous_timer.timeout.connect(
|
||||
functools.partial(self.delayed_exec, binding, count))
|
||||
self._ambiguous_timer.start()
|
||||
|
||||
def delayed_exec(self, command, count):
|
||||
"""Execute a delayed command.
|
||||
|
||||
Args:
|
||||
command/count: As if passed to self.execute()
|
||||
"""
|
||||
self._debug_log("Executing delayed command now!")
|
||||
self.clear_keystring()
|
||||
self.execute(command, self.Type.chain, count)
|
||||
|
||||
def handle(self, e):
|
||||
"""Handle a new keypress and call the respective handlers.
|
||||
|
||||
|
@ -7,11 +7,13 @@ Feature: Keyboard input
|
||||
# :clear-keychain
|
||||
|
||||
Scenario: Clearing the keychain
|
||||
When I run :bind foo message-error test12
|
||||
And I run :bind bar message-info test12-2
|
||||
And I press the keys "fo"
|
||||
When I run :bind ,foo message-error test12
|
||||
And I run :bind ,bar message-info test12-2
|
||||
And I press the keys ",fo"
|
||||
And I run :clear-keychain
|
||||
And I press the keys "bar"
|
||||
And I press the keys ",bar"
|
||||
And I run :unbind ,foo
|
||||
And I run :unbind ,bar
|
||||
Then the message "test12-2" should be shown
|
||||
|
||||
# input.forward_unbound_keys
|
||||
|
@ -37,7 +37,6 @@ def keyparser(key_config_stub):
|
||||
0, supports_count=True, supports_chains=True)
|
||||
kp.execute = mock.Mock()
|
||||
yield kp
|
||||
assert not kp._ambiguous_timer.isActive()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@ -242,51 +241,15 @@ class TestKeyChain:
|
||||
'message-info 0', keyparser.Type.chain, None)
|
||||
assert keyparser._keystring == ''
|
||||
|
||||
def test_ambiguous_keychain(self, qapp, handle_text, config_stub,
|
||||
keyparser):
|
||||
config_stub.val.input.ambiguous_timeout = 100
|
||||
timer = keyparser._ambiguous_timer
|
||||
assert not timer.isActive()
|
||||
# We start with 'a' where the keychain gives us an ambiguous result.
|
||||
# Then we check if the timer has been set up correctly
|
||||
handle_text((Qt.Key_A, 'a'))
|
||||
assert not keyparser.execute.called
|
||||
assert timer.isSingleShot()
|
||||
assert timer.interval() == 100
|
||||
assert timer.isActive()
|
||||
# Now we type an 'x' and check 'ax' has been executed and the timer
|
||||
# stopped.
|
||||
handle_text((Qt.Key_X, 'x'))
|
||||
keyparser.execute.assert_called_once_with(
|
||||
'message-info ax', keyparser.Type.chain, None)
|
||||
assert not timer.isActive()
|
||||
assert keyparser._keystring == ''
|
||||
|
||||
def test_ambiguous_keychain_no_timeout(self, handle_text, config_stub,
|
||||
keyparser):
|
||||
config_stub.val.input.ambiguous_timeout = 0
|
||||
def test_ambiguous_keychain(self, handle_text, keyparser):
|
||||
handle_text((Qt.Key_A, 'a'))
|
||||
assert keyparser.execute.called
|
||||
assert not keyparser._ambiguous_timer.isActive()
|
||||
|
||||
def test_invalid_keychain(self, handle_text, keyparser):
|
||||
handle_text((Qt.Key_B, 'b'))
|
||||
handle_text((Qt.Key_C, 'c'))
|
||||
assert keyparser._keystring == ''
|
||||
|
||||
def test_ambiguous_delayed_exec(self, handle_text, config_stub, qtbot,
|
||||
keyparser):
|
||||
config_stub.val.input.ambiguous_timeout = 100
|
||||
|
||||
# 'a' is an ambiguous result.
|
||||
handle_text((Qt.Key_A, 'a'))
|
||||
assert not keyparser.execute.called
|
||||
assert keyparser._ambiguous_timer.isActive()
|
||||
# We wait for the timeout to occur.
|
||||
with qtbot.waitSignal(keyparser.keystring_updated):
|
||||
pass
|
||||
assert keyparser.execute.called
|
||||
|
||||
|
||||
class TestCount:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user