diff --git a/qutebrowser/keyinput/basekeyparser.py b/qutebrowser/keyinput/basekeyparser.py index 59ac51a60..3114f4663 100644 --- a/qutebrowser/keyinput/basekeyparser.py +++ b/qutebrowser/keyinput/basekeyparser.py @@ -70,10 +70,11 @@ class BaseKeyParser(QObject): request_leave: Emitted to request leaving a mode. arg 0: Mode to leave. arg 1: Reason for leaving. + arg 2: Ignore the request if we're not in that mode """ keystring_updated = pyqtSignal(str) - request_leave = pyqtSignal(usertypes.KeyMode, str) + request_leave = pyqtSignal(usertypes.KeyMode, str, bool) do_log = True passthrough = False diff --git a/qutebrowser/keyinput/modeman.py b/qutebrowser/keyinput/modeman.py index d09fb20f2..d541072ce 100644 --- a/qutebrowser/keyinput/modeman.py +++ b/qutebrowser/keyinput/modeman.py @@ -276,16 +276,24 @@ class ModeManager(QObject): raise cmdexc.CommandError("Mode {} does not exist!".format(mode)) self.enter(m, 'command') - @pyqtSlot(usertypes.KeyMode, str) - def leave(self, mode, reason=None): + @pyqtSlot(usertypes.KeyMode, str, bool) + def leave(self, mode, reason=None, maybe=False): """Leave a key mode. Args: mode: The mode to leave as a usertypes.KeyMode member. reason: Why the mode was left. + maybe: If set, ignore the request if we're not in that mode. """ if self.mode != mode: - raise NotInModeError("Not in mode {}!".format(mode)) + if maybe: + log.modes.debug("Ignoring leave request for {} (reason {}) as " + "we're in mode {}".format( + mode, reason, self.mode)) + return + else: + raise NotInModeError("Not in mode {}!".format(mode)) + log.modes.debug("Leaving mode {}{}".format( mode, '' if reason is None else ' (reason: {})'.format(reason))) # leaving a mode implies clearing keychain, see diff --git a/qutebrowser/keyinput/modeparsers.py b/qutebrowser/keyinput/modeparsers.py index b3ac47d3e..6fa881ad7 100644 --- a/qutebrowser/keyinput/modeparsers.py +++ b/qutebrowser/keyinput/modeparsers.py @@ -315,7 +315,7 @@ class RegisterKeyParser(keyparser.BaseKeyParser): except (cmdexc.CommandMetaError, cmdexc.CommandError) as err: message.error(str(err), stack=traceback.format_exc()) - self.request_leave.emit(self._mode, "valid register key") + self.request_leave.emit(self._mode, "valid register key", True) return True diff --git a/tests/end2end/features/keyinput.feature b/tests/end2end/features/keyinput.feature index 886c70761..7da83efbd 100644 --- a/tests/end2end/features/keyinput.feature +++ b/tests/end2end/features/keyinput.feature @@ -237,3 +237,15 @@ Feature: Keyboard input When I run :run-macro bar Then the error "No macro recorded in 'bar'!" should be shown And no crash should happen + + Scenario: Running a macro with a mode-switching command + When I open data/hints/html/simple.html + And I run :record-macro a + And I run :hint links normal + And I wait for "hints: *" in the log + And I run :leave-mode + And I run :record-macro a + And I run :run-macro + And I press the key "a" + And I wait for "hints: *" in the log + Then no crash should happen diff --git a/tests/unit/keyinput/test_modeman.py b/tests/unit/keyinput/test_modeman.py index 4d89b4671..b9f2db572 100644 --- a/tests/unit/keyinput/test_modeman.py +++ b/tests/unit/keyinput/test_modeman.py @@ -28,7 +28,7 @@ class FakeKeyparser(QObject): """A fake BaseKeyParser which doesn't handle anything.""" - request_leave = pyqtSignal(usertypes.KeyMode, str) + request_leave = pyqtSignal(usertypes.KeyMode, str, bool) def __init__(self): super().__init__()