From 33ff0ba715961454da244fd356023a5dae527cc9 Mon Sep 17 00:00:00 2001 From: Jan Verbeek Date: Sat, 8 Oct 2016 21:17:47 +0200 Subject: [PATCH] Interactively get macro register --- doc/help/commands.asciidoc | 14 ++----- qutebrowser/commands/runners.py | 2 + qutebrowser/keyinput/modeman.py | 6 ++- qutebrowser/keyinput/modeparsers.py | 22 ++++++---- qutebrowser/misc/utilcmds.py | 55 ++++++++++++++++--------- qutebrowser/utils/usertypes.py | 2 +- tests/end2end/features/keyinput.feature | 8 ++-- tests/end2end/features/misc.feature | 6 ++- 8 files changed, 68 insertions(+), 47 deletions(-) diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index 0eee3d918..5d7cdaf87 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -606,15 +606,12 @@ Quit qutebrowser. [[record-macro]] === record-macro -Syntax: +:record-macro ['name']+ +Syntax: +:record-macro ['register']+ Start or stop recording a macro. ==== positional arguments -* +'name'+: Which name to give the macro. - -==== note -* This command does not split arguments after the last argument and handles quotes literally. +* +'register'+: Which register to store the macro in. [[reload]] === reload @@ -653,19 +650,16 @@ Restart qutebrowser while keeping existing tabs open. [[run-macro]] === run-macro -Syntax: +:run-macro ['name']+ +Syntax: +:run-macro ['register']+ Run a recorded macro. ==== positional arguments -* +'name'+: Which macro to run. +* +'register'+: Which macro to run. ==== count How many times to run the macro. -==== note -* This command does not split arguments after the last argument and handles quotes literally. - [[save]] === save Syntax: +:save ['what' ['what' ...]]+ diff --git a/qutebrowser/commands/runners.py b/qutebrowser/commands/runners.py index e83ca7dbb..35464cb9f 100644 --- a/qutebrowser/commands/runners.py +++ b/qutebrowser/commands/runners.py @@ -34,8 +34,10 @@ from qutebrowser.misc import split ParseResult = collections.namedtuple('ParseResult', ['cmd', 'args', 'cmdline', 'count']) last_command = {} + macro = {} recording_macro = None +macro_count = {} def _current_url(tabbed_browser): diff --git a/qutebrowser/keyinput/modeman.py b/qutebrowser/keyinput/modeman.py index 71a83b9a3..e66e9711c 100644 --- a/qutebrowser/keyinput/modeman.py +++ b/qutebrowser/keyinput/modeman.py @@ -78,8 +78,10 @@ def init(win_id, parent): warn=False), KM.yesno: modeparsers.PromptKeyParser(win_id, modeman), KM.caret: modeparsers.CaretKeyParser(win_id, modeman), - KM.set_mark: modeparsers.MarkKeyParser(win_id, KM.set_mark, modeman), - KM.jump_mark: modeparsers.MarkKeyParser(win_id, KM.jump_mark, modeman), + KM.set_mark: modeparsers.RegisterKeyParser(win_id, KM.set_mark, modeman), + KM.jump_mark: modeparsers.RegisterKeyParser(win_id, KM.jump_mark, modeman), + KM.record_macro: modeparsers.RegisterKeyParser(win_id, KM.record_macro, modeman), + KM.run_macro: modeparsers.RegisterKeyParser(win_id, KM.run_macro, modeman), } objreg.register('keyparsers', keyparsers, scope='window', window=win_id) modeman.destroyed.connect( diff --git a/qutebrowser/keyinput/modeparsers.py b/qutebrowser/keyinput/modeparsers.py index aa788ddc3..c27f4fc73 100644 --- a/qutebrowser/keyinput/modeparsers.py +++ b/qutebrowser/keyinput/modeparsers.py @@ -27,6 +27,7 @@ from PyQt5.QtCore import pyqtSlot, Qt from qutebrowser.config import config from qutebrowser.keyinput import keyparser +from qutebrowser.misc import utilcmds from qutebrowser.utils import usertypes, log, objreg, utils @@ -264,12 +265,13 @@ class CaretKeyParser(keyparser.CommandKeyParser): self.read_config('caret') -class MarkKeyParser(keyparser.BaseKeyParser): +class RegisterKeyParser(keyparser.BaseKeyParser): - """KeyParser for set_mark and jump_mark mode. + """KeyParser for modes that record a register key. Attributes: - _mode: Either KeyMode.set_mark or KeyMode.jump_mark. + _mode: One of KeyMode.set_mark, KeyMode.jump_mark, KeyMode.record_macro + and KeyMode.run_macro. """ def __init__(self, win_id, mode, parent=None): @@ -278,7 +280,7 @@ class MarkKeyParser(keyparser.BaseKeyParser): self._mode = mode def handle(self, e): - """Override handle to always match the next key and create a mark. + """Override handle to always match the next key and use the register. Args: e: the KeyPressEvent from Qt. @@ -299,18 +301,22 @@ class MarkKeyParser(keyparser.BaseKeyParser): tabbed_browser.set_mark(key) elif self._mode == usertypes.KeyMode.jump_mark: tabbed_browser.jump_mark(key) + elif self._mode == usertypes.KeyMode.record_macro: + utilcmds.record_macro(key) + elif self._mode == usertypes.KeyMode.run_macro: + utilcmds.run_macro(self._win_id, key) else: - raise ValueError("{} is not a valid mark mode".format(self._mode)) + raise ValueError("{} is not a valid register key".format(self._mode)) - self.request_leave.emit(self._mode, "valid mark key") + self.request_leave.emit(self._mode, "valid register key") return True @pyqtSlot(str) def on_keyconfig_changed(self, mode): - """MarkKeyParser has no config section (no bindable keys).""" + """RegisterKeyParser has no config section (no bindable keys).""" pass def execute(self, cmdstr, _keytype, count=None): - """Should never be called on MarkKeyParser.""" + """Should never be called on RegisterKeyParser.""" assert False diff --git a/qutebrowser/misc/utilcmds.py b/qutebrowser/misc/utilcmds.py index 743ba169c..cb984d73d 100644 --- a/qutebrowser/misc/utilcmds.py +++ b/qutebrowser/misc/utilcmds.py @@ -234,42 +234,57 @@ def repeat_command(win_id, count=None): commandrunner.run(cmd[0], count if count is not None else cmd[1]) -@cmdutils.register(maxsplit=0) -@cmdutils.argument('name') -def record_macro(name=""): +@cmdutils.register(instance='mode-manager', name='record-macro', scope='window') +@cmdutils.argument('register') +def record_macro_command(self, register=None): """Start or stop recording a macro. Args: - name: Which name to give the macro. + register: Which register to store the macro in. """ if runners.recording_macro is None: - message.info("Defining macro...") - runners.macro[name] = [] - runners.recording_macro = name - elif runners.recording_macro == name: - message.info("Macro defined.") - runners.recording_macro = None + if register is None: + self.enter(usertypes.KeyMode.record_macro, 'record_macro') + else: + record_macro(register) else: - raise cmdexc.CommandError( - "Already recording macro '{}'".format(runners.recording_macro)) + message.info("Macro recorded.") + runners.recording_macro = None -@cmdutils.register(maxsplit=0) +def record_macro(register): + """Start recording a macro.""" + message.info("Recording macro...") + runners.macro[register] = [] + runners.recording_macro = register + + +@cmdutils.register(instance='mode-manager', name='run-macro', scope='window') @cmdutils.argument('win_id', win_id=True) @cmdutils.argument('count', count=True) -@cmdutils.argument('name') -def run_macro(win_id, count=1, name=""): +@cmdutils.argument('register') +def run_macro_command(self, win_id, count=1, register=None): """Run a recorded macro. Args: count: How many times to run the macro. - name: Which macro to run. + register: Which macro to run. """ - if name not in runners.macro: - raise cmdexc.CommandError("No macro defined!") + runners.macro_count[win_id] = count + if register is None: + self.enter(usertypes.KeyMode.run_macro, 'run_macro') + else: + run_macro(win_id, register) + + +def run_macro(win_id, register): + """Run a recorded macro.""" + if register not in runners.macro: + raise cmdexc.CommandError( + "No macro recorded in '{}'!".format(register)) commandrunner = runners.CommandRunner(win_id) - for _ in range(count): - for cmd in runners.macro[name]: + for _ in range(runners.macro_count[win_id]): + for cmd in runners.macro[register]: commandrunner.run(*cmd) diff --git a/qutebrowser/utils/usertypes.py b/qutebrowser/utils/usertypes.py index 6dd3d9674..39d7e4209 100644 --- a/qutebrowser/utils/usertypes.py +++ b/qutebrowser/utils/usertypes.py @@ -233,7 +233,7 @@ ClickTarget = enum('ClickTarget', ['normal', 'tab', 'tab_bg', 'window', # Key input modes KeyMode = enum('KeyMode', ['normal', 'hint', 'command', 'yesno', 'prompt', 'insert', 'passthrough', 'caret', 'set_mark', - 'jump_mark']) + 'jump_mark', 'record_macro', 'run_macro']) # Available command completions diff --git a/tests/end2end/features/keyinput.feature b/tests/end2end/features/keyinput.feature index e02b33d71..48703d940 100644 --- a/tests/end2end/features/keyinput.feature +++ b/tests/end2end/features/keyinput.feature @@ -121,11 +121,11 @@ Feature: Keyboard input When I open data/keyinput/log.html And I set general -> log-javascript-console to info And I set input -> forward-unbound-keys to all - And I press the key "q" + And I press the key "," And I press the key "" - # q - Then the javascript message "key press: 81" should be logged - And the javascript message "key release: 81" should be logged + # , + Then the javascript message "key press: 188" should be logged + And the javascript message "key release: 188" should be logged # And the javascript message "key press: 112" should be logged And the javascript message "key release: 112" should be logged diff --git a/tests/end2end/features/misc.feature b/tests/end2end/features/misc.feature index 62254f866..bb8811292 100644 --- a/tests/end2end/features/misc.feature +++ b/tests/end2end/features/misc.feature @@ -625,18 +625,20 @@ Feature: Various utility commands. Scenario: Recording a simple macro Given I open data/scroll/simple.html And I run :tab-only - When I run :scroll down with count 5 + When I run :scroll down with count 6 And I run :record-macro + And I press the key "a" And I run :scroll up And I run :scroll up And I run :record-macro And I run :run-macro with count 2 + And I press the key "a" Then the page should not be scrolled Scenario: Recording a named macro Given I open data/scroll/simple.html And I run :tab-only - When I run :scroll down with count 5 + When I run :scroll down with count 6 And I run :record-macro foo And I run :scroll up And I run :scroll up