Refactor key mode/parser handling in modeman.

This commit is contained in:
Florian Bruhin 2015-06-05 15:29:09 +02:00
parent 728f06e797
commit b55e22b5c3
5 changed files with 32 additions and 41 deletions

View File

@ -49,6 +49,8 @@ class BaseKeyParser(QObject):
special: execute() was called via a special key binding special: execute() was called via a special key binding
do_log: Whether to log keypresses or not. do_log: Whether to log keypresses or not.
passthrough: Whether unbound keys should be passed through with this
handler.
Attributes: Attributes:
bindings: Bound key bindings bindings: Bound key bindings
@ -69,6 +71,7 @@ class BaseKeyParser(QObject):
keystring_updated = pyqtSignal(str) keystring_updated = pyqtSignal(str)
do_log = True do_log = True
passthrough = False
Match = usertypes.enum('Match', ['partial', 'definitive', 'ambiguous', Match = usertypes.enum('Match', ['partial', 'definitive', 'ambiguous',
'other', 'none']) 'other', 'none'])

View File

@ -55,6 +55,7 @@ class PassthroughKeyParser(CommandKeyParser):
""" """
do_log = False do_log = False
passthrough = True
def __init__(self, win_id, mode, parent=None, warn=True): def __init__(self, win_id, mode, parent=None, warn=True):
"""Constructor. """Constructor.

View File

@ -84,16 +84,8 @@ def init(win_id, parent):
modeman.destroyed.connect( modeman.destroyed.connect(
functools.partial(objreg.delete, 'keyparsers', scope='window', functools.partial(objreg.delete, 'keyparsers', scope='window',
window=win_id)) window=win_id))
modeman.register(KM.normal, keyparsers[KM.normal].handle) for mode, parser in keyparsers.items():
modeman.register(KM.hint, keyparsers[KM.hint].handle) modeman.register(mode, parser)
modeman.register(KM.insert, keyparsers[KM.insert].handle, passthrough=True)
modeman.register(KM.passthrough, keyparsers[KM.passthrough].handle,
passthrough=True)
modeman.register(KM.command, keyparsers[KM.command].handle,
passthrough=True)
modeman.register(KM.prompt, keyparsers[KM.prompt].handle, passthrough=True)
modeman.register(KM.yesno, keyparsers[KM.yesno].handle)
modeman.register(KM.caret, keyparsers[KM.caret].handle, passthrough=True)
return modeman return modeman
@ -126,10 +118,9 @@ class ModeManager(QObject):
"""Manager for keyboard modes. """Manager for keyboard modes.
Attributes: Attributes:
passthrough: A list of modes in which to pass through events.
mode: The mode we're currently in. mode: The mode we're currently in.
_win_id: The window ID of this ModeManager _win_id: The window ID of this ModeManager
_handlers: A dictionary of modes and their handlers. _parsers: A dictionary of modes and their keyparsers.
_forward_unbound_keys: If we should forward unbound keys. _forward_unbound_keys: If we should forward unbound keys.
_releaseevents_to_pass: A set of KeyEvents where the keyPressEvent was _releaseevents_to_pass: A set of KeyEvents where the keyPressEvent was
passed through, so the release event should as passed through, so the release event should as
@ -151,8 +142,7 @@ class ModeManager(QObject):
def __init__(self, win_id, parent=None): def __init__(self, win_id, parent=None):
super().__init__(parent) super().__init__(parent)
self._win_id = win_id self._win_id = win_id
self._handlers = {} self._parsers = {}
self.passthrough = []
self.mode = usertypes.KeyMode.normal self.mode = usertypes.KeyMode.normal
self._releaseevents_to_pass = set() self._releaseevents_to_pass = set()
self._forward_unbound_keys = config.get( self._forward_unbound_keys = config.get(
@ -160,8 +150,7 @@ class ModeManager(QObject):
objreg.get('config').changed.connect(self.set_forward_unbound_keys) objreg.get('config').changed.connect(self.set_forward_unbound_keys)
def __repr__(self): def __repr__(self):
return utils.get_repr(self, mode=self.mode, return utils.get_repr(self, mode=self.mode)
passthrough=self.passthrough)
def _eventFilter_keypress(self, event): def _eventFilter_keypress(self, event):
"""Handle filtering of KeyPress events. """Handle filtering of KeyPress events.
@ -173,11 +162,11 @@ class ModeManager(QObject):
True if event should be filtered, False otherwise. True if event should be filtered, False otherwise.
""" """
curmode = self.mode curmode = self.mode
handler = self._handlers[curmode] parser = self._parsers[curmode]
if curmode != usertypes.KeyMode.insert: if curmode != usertypes.KeyMode.insert:
log.modes.debug("got keypress in mode {} - calling handler " log.modes.debug("got keypress in mode {} - delegating to "
"{}".format(curmode, utils.qualname(handler))) "{}".format(curmode, utils.qualname(parser)))
handled = handler(event) if handler is not None else False handled = parser.handle(event)
is_non_alnum = bool(event.modifiers()) or not event.text().strip() is_non_alnum = bool(event.modifiers()) or not event.text().strip()
focus_widget = QApplication.instance().focusWidget() focus_widget = QApplication.instance().focusWidget()
@ -187,7 +176,7 @@ class ModeManager(QObject):
filter_this = True filter_this = True
elif is_tab and not isinstance(focus_widget, QWebView): elif is_tab and not isinstance(focus_widget, QWebView):
filter_this = True filter_this = True
elif (curmode in self.passthrough or elif (parser.passthrough or
self._forward_unbound_keys == 'all' or self._forward_unbound_keys == 'all' or
(self._forward_unbound_keys == 'auto' and is_non_alnum)): (self._forward_unbound_keys == 'auto' and is_non_alnum)):
filter_this = False filter_this = False
@ -202,8 +191,8 @@ class ModeManager(QObject):
"passthrough: {}, is_non_alnum: {}, is_tab {} --> " "passthrough: {}, is_non_alnum: {}, is_tab {} --> "
"filter: {} (focused: {!r})".format( "filter: {} (focused: {!r})".format(
handled, self._forward_unbound_keys, handled, self._forward_unbound_keys,
curmode in self.passthrough, is_non_alnum, parser.passthrough, is_non_alnum, is_tab,
is_tab, filter_this, focus_widget)) filter_this, focus_widget))
return filter_this return filter_this
def _eventFilter_keyrelease(self, event): def _eventFilter_keyrelease(self, event):
@ -226,20 +215,16 @@ class ModeManager(QObject):
log.modes.debug("filter: {}".format(filter_this)) log.modes.debug("filter: {}".format(filter_this))
return filter_this return filter_this
def register(self, mode, handler, passthrough=False): def register(self, mode, parser):
"""Register a new mode. """Register a new mode.
Args: Args:
mode: The name of the mode. mode: The name of the mode.
handler: Handler for keyPressEvents. parser: The KeyParser which should be used.
passthrough: Whether to pass key bindings in this mode through to
the widgets.
""" """
if not isinstance(mode, usertypes.KeyMode): assert isinstance(mode, usertypes.KeyMode)
raise TypeError("Mode {} is no KeyMode member!".format(mode)) assert parser is not None
self._handlers[mode] = handler self._parsers[mode] = parser
if passthrough:
self.passthrough.append(mode)
def enter(self, mode, reason=None, only_if_normal=False): def enter(self, mode, reason=None, only_if_normal=False):
"""Enter a new mode. """Enter a new mode.
@ -253,8 +238,8 @@ class ModeManager(QObject):
raise TypeError("Mode {} is no KeyMode member!".format(mode)) raise TypeError("Mode {} is no KeyMode member!".format(mode))
log.modes.debug("Entering mode {}{}".format( log.modes.debug("Entering mode {}{}".format(
mode, '' if reason is None else ' (reason: {})'.format(reason))) mode, '' if reason is None else ' (reason: {})'.format(reason)))
if mode not in self._handlers: if mode not in self._parsers:
raise ValueError("No handler for mode {}".format(mode)) raise ValueError("No keyparser for mode {}".format(mode))
prompt_modes = (usertypes.KeyMode.prompt, usertypes.KeyMode.yesno) prompt_modes = (usertypes.KeyMode.prompt, usertypes.KeyMode.yesno)
if self.mode == mode or (self.mode in prompt_modes and if self.mode == mode or (self.mode in prompt_modes and
mode in prompt_modes): mode in prompt_modes):

View File

@ -224,6 +224,8 @@ class CaretKeyParser(keyparser.CommandKeyParser):
"""KeyParser for caret mode.""" """KeyParser for caret mode."""
passthrough = True
def __init__(self, win_id, parent=None): def __init__(self, win_id, parent=None):
super().__init__(win_id, parent, supports_count=True, super().__init__(win_id, parent, supports_count=True,
supports_chains=True) supports_chains=True)

View File

@ -469,9 +469,9 @@ class StatusBar(QWidget):
@pyqtSlot(usertypes.KeyMode) @pyqtSlot(usertypes.KeyMode)
def on_mode_entered(self, mode): def on_mode_entered(self, mode):
"""Mark certain modes in the commandline.""" """Mark certain modes in the commandline."""
mode_manager = objreg.get('mode-manager', scope='window', keyparsers = objreg.get('keyparsers', scope='window',
window=self._win_id) window=self._win_id)
if mode in mode_manager.passthrough: if keyparsers[mode].passthrough:
self._set_mode_text(mode.name) self._set_mode_text(mode.name)
if mode in (usertypes.KeyMode.insert, usertypes.KeyMode.caret): if mode in (usertypes.KeyMode.insert, usertypes.KeyMode.caret):
self.set_mode_active(mode, True) self.set_mode_active(mode, True)
@ -479,10 +479,10 @@ class StatusBar(QWidget):
@pyqtSlot(usertypes.KeyMode, usertypes.KeyMode) @pyqtSlot(usertypes.KeyMode, usertypes.KeyMode)
def on_mode_left(self, old_mode, new_mode): def on_mode_left(self, old_mode, new_mode):
"""Clear marked mode.""" """Clear marked mode."""
mode_manager = objreg.get('mode-manager', scope='window', keyparsers = objreg.get('keyparsers', scope='window',
window=self._win_id) window=self._win_id)
if old_mode in mode_manager.passthrough: if keyparsers[old_mode].passthrough:
if new_mode in mode_manager.passthrough: if keyparsers[new_mode].passthrough:
self._set_mode_text(new_mode.name) self._set_mode_text(new_mode.name)
else: else:
self.txt.set_text(self.txt.Text.normal, '') self.txt.set_text(self.txt.Text.normal, '')