diff --git a/TODO b/TODO index 43268b4b9..b1c9de953 100644 --- a/TODO +++ b/TODO @@ -4,7 +4,6 @@ keyparser foo - Get to insert mode when clicking flash plugins - Handle keybind to get out of insert mode (e.g. esc) - Pass keypresses to statusbar correctly -- Use stack for modes and .leave() - Switch to normal mode if new page loaded - Add passthrough-keys option to pass through unmapped keys - Add auto-insert-mode to switch to insert mode if editable element is focused diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index c5dde063a..775c9c4ca 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -403,7 +403,7 @@ class HintManager(QObject): self._elems = {} self._target = None self._frame = None - modemanager.enter("normal") + modemanager.leave("hint") message.clear() def handle_partial_key(self, keystr): diff --git a/qutebrowser/utils/modemanager.py b/qutebrowser/utils/modemanager.py index bc5fc7f10..88d2bb86c 100644 --- a/qutebrowser/utils/modemanager.py +++ b/qutebrowser/utils/modemanager.py @@ -47,6 +47,11 @@ def enter(mode): manager.enter(mode) +def leave(mode): + """Leave the mode 'mode'.""" + manager.leave(mode) + + class ModeManager(QObject): """Manager for keyboard modes. @@ -54,7 +59,9 @@ class ModeManager(QObject): Attributes: _handlers: A dictionary of modes and their handlers. _passthrough: A list of modes in which to pass through events. - mode: The current mode. + _mode_stack: A list of the modes we're currently in, with the active + one on the right. + mode: The current mode (readonly property). Signals: entered: Emitted when a mode is entered. @@ -70,7 +77,14 @@ class ModeManager(QObject): super().__init__(parent) self._handlers = {} self._passthrough = [] - self.mode = None + self._mode_stack = [] + + @property + def mode(self): + """Read-only property for the current mode.""" + if not self._mode_stack: + return None + return self._mode_stack[-1] def register(self, mode, handler, passthrough=False): """Register a new mode. @@ -88,19 +102,34 @@ class ModeManager(QObject): def enter(self, mode): """Enter a new mode. + Args: + mode; The name of the mode to enter. + Emit: - leaved: With the old mode name. entered: With the new mode name. """ - oldmode = self.mode - logging.debug("Switching mode: {} -> {}".format(oldmode, mode)) + logging.debug("Switching mode to {}".format(mode)) + logging.debug("Mode stack: {}".format(self._mode_stack)) if mode not in self._handlers: raise ValueError("No handler for mode {}".format(mode)) - if oldmode is not None: - self.leaved.emit(oldmode) - self.mode = mode + self._mode_stack.append(mode) self.entered.emit(mode) + def leave(self, mode): + """Leave a mode. + + Args: + mode; The name of the mode to leave. + + Emit: + leaved: With the old mode name. + """ + try: + self._mode_stack.remove(mode) + except ValueError: + raise ValueError("Mode {} not on mode stack!".format(mode)) + self.leaved.emit(mode) + def eventFilter(self, obj, evt): """Filter all events based on the currently set mode. diff --git a/qutebrowser/widgets/browsertab.py b/qutebrowser/widgets/browsertab.py index 0fd04a91f..e75291b02 100644 --- a/qutebrowser/widgets/browsertab.py +++ b/qutebrowser/widgets/browsertab.py @@ -272,7 +272,10 @@ class BrowserTab(QWebView): logging.debug("Clicked editable element!") modemanager.enter("insert") else: - modemanager.enter("normal") + try: + modemanager.leave("insert") + except ValueError: + pass if self._force_open_target is not None: self._open_target = self._force_open_target diff --git a/qutebrowser/widgets/statusbar.py b/qutebrowser/widgets/statusbar.py index 08eabab04..c2c6a311d 100644 --- a/qutebrowser/widgets/statusbar.py +++ b/qutebrowser/widgets/statusbar.py @@ -363,7 +363,7 @@ class _Command(QLineEdit): clear_completion_selection: Always emitted. hide_completion: Always emitted so the completion is hidden. """ - modemanager.enter("normal") + modemanager.leave("command") if e.reason() in [Qt.MouseFocusReason, Qt.TabFocusReason, Qt.BacktabFocusReason, Qt.OtherFocusReason]: self.setText('')