Add keyboard macros

This commit is contained in:
Jan Verbeek 2016-10-06 22:24:04 +02:00
parent 4801352254
commit 7aaaadac1a
5 changed files with 105 additions and 4 deletions

View File

@ -59,10 +59,12 @@ It is possible to run or bind multiple commands by separating them with `;;`.
|<<quickmark-load,quickmark-load>>|Load a quickmark.
|<<quickmark-save,quickmark-save>>|Save the current page as a quickmark.
|<<quit,quit>>|Quit qutebrowser.
|<<record-macro,record-macro>>|Start or stop recording a macro.
|<<reload,reload>>|Reload the current/[count]th tab.
|<<repeat,repeat>>|Repeat a given command.
|<<report,report>>|Report a bug in qutebrowser.
|<<restart,restart>>|Restart qutebrowser while keeping existing tabs open.
|<<run-macro,run-macro>>|Run a recorded macro.
|<<save,save>>|Save configs and state.
|<<search,search>>|Search for a text on the current page. With no text, clear results.
|<<session-delete,session-delete>>|Delete a session.
@ -602,6 +604,18 @@ Save the current page as a quickmark.
=== quit
Quit qutebrowser.
[[record-macro]]
=== record-macro
Syntax: +:record-macro ['name']+
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.
[[reload]]
=== reload
Syntax: +:reload [*--force*]+
@ -637,6 +651,21 @@ Report a bug in qutebrowser.
=== restart
Restart qutebrowser while keeping existing tabs open.
[[run-macro]]
=== run-macro
Syntax: +:run-macro ['name']+
Run a recorded macro.
==== positional arguments
* +'name'+: 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' ...]]+

View File

@ -27,13 +27,15 @@ from PyQt5.QtCore import pyqtSlot, QUrl, QObject
from qutebrowser.config import config, configexc
from qutebrowser.commands import cmdexc, cmdutils
from qutebrowser.utils import message, objreg, qtutils, utils
from qutebrowser.utils import message, objreg, qtutils, usertypes, utils
from qutebrowser.misc import split
ParseResult = collections.namedtuple('ParseResult', ['cmd', 'args', 'cmdline',
'count'])
last_command = {}
macro = {}
recording_macro = None
def _current_url(tabbed_browser):
@ -301,10 +303,17 @@ class CommandRunner(QObject):
else:
result.cmd.run(self._win_id, args)
parsed_command = (self._parse_count(text)[1],
count if count is not None else result.count)
if result.cmdline[0] != 'repeat-command':
last_command[cur_mode] = (
self._parse_count(text)[1],
count if count is not None else result.count)
last_command[cur_mode] = parsed_command
if (recording_macro is not None and
cur_mode == usertypes.KeyMode.normal and
result.cmdline[0] not in ['record-macro', 'run-macro',
'set-cmd-text']):
macro[recording_macro].append(parsed_command)
@pyqtSlot(str, int)
@pyqtSlot(str)

View File

@ -1634,6 +1634,8 @@ KEY_DATA = collections.OrderedDict([
('follow-selected', RETURN_KEYS),
('follow-selected -t', ['<Ctrl-Return>', '<Ctrl-Enter>']),
('repeat-command', ['.']),
('record-macro', ['q']),
('run-macro', ['@']),
])),
('insert', collections.OrderedDict([

View File

@ -234,6 +234,45 @@ 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=""):
"""Start or stop recording a macro.
Args:
name: Which name to give the macro.
"""
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
else:
raise cmdexc.CommandError(
"Already recording macro '{}'".format(runners.recording_macro))
@cmdutils.register(maxsplit=0)
@cmdutils.argument('win_id', win_id=True)
@cmdutils.argument('count', count=True)
@cmdutils.argument('name')
def run_macro(win_id, count=1, name=""):
"""Run a recorded macro.
Args:
count: How many times to run the macro.
name: Which macro to run.
"""
if name not in runners.macro:
raise cmdexc.CommandError("No macro defined!")
commandrunner = runners.CommandRunner(win_id)
for _ in range(count):
for cmd in runners.macro[name]:
commandrunner.run(*cmd)
@cmdutils.register(debug=True, name='debug-log-capacity')
def log_capacity(capacity: int):
"""Change the number of log lines to be stored in RAM.

View File

@ -622,6 +622,28 @@ Feature: Various utility commands.
history:
- url: http://localhost:*/data/hello3.txt
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
And I run :record-macro
And I run :scroll up
And I run :scroll up
And I run :record-macro
And I run :run-macro with count 2
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
And I run :record-macro foo
And I run :scroll up
And I run :scroll up
And I run :record-macro foo
And I run :run-macro foo with count 2
Then the page should not be scrolled
## Variables
Scenario: {url} as part of an argument