diff --git a/qutebrowser/commands/runners.py b/qutebrowser/commands/runners.py index 9c1d64565..ad9ae9f08 100644 --- a/qutebrowser/commands/runners.py +++ b/qutebrowser/commands/runners.py @@ -32,6 +32,7 @@ from qutebrowser.misc import split ParseResult = collections.namedtuple('ParseResult', ['cmd', 'args', 'cmdline', 'count']) +last_command = {} def _current_url(tabbed_browser): @@ -271,6 +272,10 @@ class CommandRunner(QObject): count: The count to pass to the command. """ for result in self.parse_all(text): + mode_manager = objreg.get('mode-manager', scope='window', + window=self._win_id) + cur_mode = mode_manager.mode + args = replace_variables(self._win_id, result.args) if count is not None: if result.count is not None: @@ -282,6 +287,11 @@ class CommandRunner(QObject): else: result.cmd.run(self._win_id, args) + if result.cmdline[0] != 'repeat-command': + last_command[cur_mode] = ( + self._parse_count(text)[1], + count if count is not None else result.count) + @pyqtSlot(str, int) @pyqtSlot(str) def run_safely(self, text, count=None): diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index 5447f8ed6..c28244358 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -1458,10 +1458,8 @@ KEY_DATA = collections.OrderedDict([ ('hint all hover', [';h']), ('hint images', [';i']), ('hint images tab', [';I']), - ('hint images tab-bg', ['.i']), ('hint links fill ":open {hint-url}"', [';o']), ('hint links fill ":open -t {hint-url}"', [';O']), - ('hint links fill ":open -b {hint-url}"', ['.o']), ('hint links yank', [';y']), ('hint links yank-primary', [';Y']), ('hint --rapid links tab-bg', [';r']), @@ -1546,6 +1544,7 @@ KEY_DATA = collections.OrderedDict([ ('open qute:settings', ['Ss']), ('follow-selected', RETURN_KEYS), ('follow-selected -t', ['', '']), + ('repeat-command', ['.']), ])), ('insert', collections.OrderedDict([ diff --git a/qutebrowser/misc/utilcmds.py b/qutebrowser/misc/utilcmds.py index 1de004c90..e1d7c6a61 100644 --- a/qutebrowser/misc/utilcmds.py +++ b/qutebrowser/misc/utilcmds.py @@ -217,3 +217,20 @@ def debug_set_fake_clipboard(s=None): utils.log_clipboard = True else: utils.fake_clipboard = s + + +@cmdutils.register(hide=True) +@cmdutils.argument('win_id', win_id=True) +@cmdutils.argument('count', count=True) +def repeat_command(win_id, count=None): + """Repeat the last executed command. + + Args: + count: Which count to pass the command. + """ + mode_manager = objreg.get('mode-manager', scope='window', window=win_id) + if mode_manager.mode not in runners.last_command: + raise cmdexc.CommandError("You didn't do anything yet.") + cmd = runners.last_command[mode_manager.mode] + commandrunner = runners.CommandRunner(win_id) + commandrunner.run(cmd[0], count if count is not None else cmd[1]) diff --git a/tests/end2end/features/conftest.py b/tests/end2end/features/conftest.py index 8c9eea825..d8a0b261b 100644 --- a/tests/end2end/features/conftest.py +++ b/tests/end2end/features/conftest.py @@ -493,3 +493,28 @@ def clipboard_contains_multiline(quteproc, httpbin, content): @bdd.then("qutebrowser should quit") def should_quit(qtbot, quteproc): quteproc.wait_for_quit() + + +def _get_scroll_values(quteproc): + data = quteproc.get_session() + pos = data['windows'][0]['tabs'][0]['history'][0]['scroll-pos'] + return (pos['x'], pos['y']) + + +@bdd.then(bdd.parsers.re(r"the page should be scrolled " + r"(?Phorizontally|vertically)")) +def check_scrolled(quteproc, direction): + x, y = _get_scroll_values(quteproc) + if direction == 'horizontally': + assert x != 0 + assert y == 0 + else: + assert x == 0 + assert y != 0 + + +@bdd.then("the page should not be scrolled") +def check_not_scrolled(quteproc): + x, y = _get_scroll_values(quteproc) + assert x == 0 + assert y == 0 diff --git a/tests/end2end/features/misc.feature b/tests/end2end/features/misc.feature index 08befc45a..0781a3a70 100644 --- a/tests/end2end/features/misc.feature +++ b/tests/end2end/features/misc.feature @@ -470,3 +470,41 @@ Feature: Various utility commands. And I wait until cookies is loaded And I open cookies in a new tab Then the cookie qute-test should be set to 42 + + Scenario: :repeat-command + Given I open data/scroll.html + And I run :tab-only + When I run :scroll down + And I run :repeat-command + And I run :scroll up + Then the page should be scrolled vertically + + Scenario: :repeat-command with count + Given I open data/scroll.html + And I run :tab-only + When I run :scroll down with count 3 + And I run :scroll up + And I run :repeat-command with count 2 + Then the page should not be scrolled + + Scenario: :repeat-command with not-normal command inbetween + Given I open data/scroll.html + And I run :tab-only + When I run :scroll down with count 3 + And I run :scroll up + And I run :prompt-accept + And I run :repeat-command with count 2 + Then the page should not be scrolled + And the error "prompt-accept: This command is only allowed in prompt/yesno mode." should be shown + + Scenario: :repeat-command with mode-switching command + Given I open data/hints/link_blank.html + And I run :tab-only + When I run :hint + And I run :leave-mode + And I run :repeat-command + And I run :follow-hint a + And I wait until data/hello.txt is loaded + Then the following tabs should be open: + - data/hints/link_blank.html + - data/hello.txt (active) diff --git a/tests/end2end/features/test_misc_bdd.py b/tests/end2end/features/test_misc_bdd.py index f9cd50766..db3e53d52 100644 --- a/tests/end2end/features/test_misc_bdd.py +++ b/tests/end2end/features/test_misc_bdd.py @@ -29,7 +29,6 @@ import qutebrowser from qutebrowser.utils import docutils from qutebrowser.browser import pdfjs - bdd.scenarios('misc.feature') diff --git a/tests/end2end/features/test_scroll_bdd.py b/tests/end2end/features/test_scroll_bdd.py index 7ea63936e..de1ed3e0a 100644 --- a/tests/end2end/features/test_scroll_bdd.py +++ b/tests/end2end/features/test_scroll_bdd.py @@ -19,28 +19,3 @@ import pytest_bdd as bdd bdd.scenarios('scroll.feature') - - -def _get_scroll_values(quteproc): - data = quteproc.get_session() - pos = data['windows'][0]['tabs'][0]['history'][0]['scroll-pos'] - return (pos['x'], pos['y']) - - -@bdd.then(bdd.parsers.re(r"the page should be scrolled " - r"(?Phorizontally|vertically)")) -def check_scrolled(quteproc, direction): - x, y = _get_scroll_values(quteproc) - if direction == 'horizontally': - assert x != 0 - assert y == 0 - else: - assert x == 0 - assert y != 0 - - -@bdd.then("the page should not be scrolled") -def check_not_scrolled(quteproc): - x, y = _get_scroll_values(quteproc) - assert x == 0 - assert y == 0