diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index 715a4a4db..6e5f4d7f4 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -22,6 +22,7 @@ import collections import functools import math +import os import re import html import enum @@ -154,6 +155,7 @@ class HintContext: to_follow: The link to follow when enter is pressed. args: Custom arguments for userscript/spawn rapid: Whether to do rapid hinting. + first_run: Whether the action is run for the 1st time in rapid hinting. add_history: Whether to add yanked or spawned link to the history. filterstr: Used to save the filter string for restoring in rapid mode. tab: The WebTab object we started hinting in. @@ -166,6 +168,7 @@ class HintContext: baseurl = attr.ib(None) to_follow = attr.ib(None) rapid = attr.ib(False) + first_run = attr.ib(True) add_history = attr.ib(False) filterstr = attr.ib(None) args = attr.ib(attr.Factory(list)) @@ -241,7 +244,18 @@ class HintActions: if url.scheme() == 'mailto': flags |= QUrl.RemoveScheme urlstr = url.toString(flags) - utils.set_clipboard(urlstr, selection=sel) + + new_content = urlstr + + # only second and consecutive yanks are to append to the clipboard + if context.rapid and not context.first_run: + try: + old_content = utils.get_clipboard(selection=sel) + except utils.ClipboardEmptyError: + pass + else: + new_content = os.linesep.join([old_content, new_content]) + utils.set_clipboard(new_content, selection=sel) msg = "Yanked URL to {}: {}".format( "primary selection" if sel else "clipboard", @@ -700,7 +714,8 @@ class HintManager(QObject): if rapid: if target in [Target.tab_bg, Target.window, Target.run, Target.hover, Target.userscript, Target.spawn, - Target.download, Target.normal, Target.current]: + Target.download, Target.normal, Target.current, + Target.yank, Target.yank_primary]: pass elif target == Target.tab and config.val.tabs.background: pass @@ -914,6 +929,9 @@ class HintManager(QObject): except HintingError as e: message.error(str(e)) + if self._context is not None: + self._context.first_run = False + @cmdutils.register(instance='hintmanager', scope='tab', modes=[usertypes.KeyMode.hint]) def follow_hint(self, select=False, keystring=None): diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py index da1ddf085..4554aef2e 100644 --- a/qutebrowser/utils/utils.py +++ b/qutebrowser/utils/utils.py @@ -510,11 +510,13 @@ def sanitize_filename(name, replacement='_'): def set_clipboard(data, selection=False): """Set the clipboard to some given data.""" + global fake_clipboard if selection and not supports_selection(): raise SelectionUnsupportedError if log_clipboard: what = 'primary selection' if selection else 'clipboard' log.misc.debug("Setting fake {}: {}".format(what, json.dumps(data))) + fake_clipboard = data else: mode = QClipboard.Selection if selection else QClipboard.Clipboard QApplication.clipboard().setText(data, mode=mode) diff --git a/tests/end2end/features/conftest.py b/tests/end2end/features/conftest.py index 4752e2393..8040d84cc 100644 --- a/tests/end2end/features/conftest.py +++ b/tests/end2end/features/conftest.py @@ -600,6 +600,7 @@ def check_open_tabs(quteproc, request, tabs): def clipboard_contains(quteproc, server, what, content): expected = content.replace('(port)', str(server.port)) expected = expected.replace('\\n', '\n') + expected = expected.replace('(linesep)', os.linesep) quteproc.wait_for(message='Setting fake {}: {}'.format( what, json.dumps(expected))) diff --git a/tests/end2end/features/hints.feature b/tests/end2end/features/hints.feature index ba05d21ed..e33b16f68 100644 --- a/tests/end2end/features/hints.feature +++ b/tests/end2end/features/hints.feature @@ -120,6 +120,15 @@ Feature: Using hints And I hint with args "links yank" and follow a Then the clipboard should contain "javascript:window.location.href='/data/hello.txt'" + Scenario: Rapid yanking + When I run :debug-set-fake-clipboard + And I open data/hints/rapid.html + And I hint with args "links yank --rapid" + And I run :follow-hint a + And I run :follow-hint s + And I run :leave-mode + Then the clipboard should contain "http://localhost:(port)/data/hello.txt(linesep)http://localhost:(port)/data/hello2.txt" + Scenario: Rapid hinting When I open data/hints/rapid.html in a new tab And I run :tab-only diff --git a/tests/unit/utils/test_utils.py b/tests/unit/utils/test_utils.py index df0eb9ecb..ef2b6c8d4 100644 --- a/tests/unit/utils/test_utils.py +++ b/tests/unit/utils/test_utils.py @@ -651,6 +651,7 @@ class TestGetSetClipboard: autospec=True) clipboard = m() clipboard.text.return_value = 'mocked clipboard text' + mocker.patch('qutebrowser.utils.utils.fake_clipboard', None) return clipboard def test_set(self, clipboard_mock, caplog):