diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index e1d293781..da01cd06f 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1307,6 +1307,31 @@ class CommandDispatcher: except webelem.IsNullError: raise cmdexc.CommandError("Element vanished while editing!") + @cmdutils.register(instance='command-dispatcher', + modes=[KeyMode.insert], hide=True, scope='window', + needs_js=True) + def paste_primary(self): + """Paste the primary selection at cursor position.""" + frame = self._current_widget().page().currentFrame() + try: + elem = webelem.focus_elem(frame) + except webelem.IsNullError: + raise cmdexc.CommandError("No element focused!") + if not elem.is_editable(strict=True): + raise cmdexc.CommandError("Focused element is not editable!") + + clipboard = QApplication.clipboard() + if clipboard.supportsSelection(): + sel = clipboard.text(QClipboard.Selection) + log.misc.debug("Pasting primary selection into element {}".format( + elem.debug_text())) + elem.evaluateJavaScript(""" + var sel = '{}'; + var event = document.createEvent('TextEvent'); + event.initTextEvent('textInput', true, true, null, sel); + this.dispatchEvent(event); + """.format(webelem.javascript_escape(sel))) + def _clear_search(self, view, text): """Clear search string/highlights for the given view. diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index a9fbb2669..d94ad572e 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -1324,7 +1324,8 @@ KEY_SECTION_DESC = { "Since normal keypresses are passed through, only special keys are " "supported in this mode.\n" "Useful hidden commands to map in this section:\n\n" - " * `open-editor`: Open a texteditor with the focused field."), + " * `open-editor`: Open a texteditor with the focused field.\n" + " * `paste-primary`: Paste primary selection at cursor position."), 'hint': ( "Keybindings for hint mode.\n" "Since normal keypresses are passed through, only special keys are " @@ -1495,6 +1496,7 @@ KEY_DATA = collections.OrderedDict([ ('insert', collections.OrderedDict([ ('open-editor', ['']), + ('paste-primary', ['']), ])), ('hint', collections.OrderedDict([ diff --git a/tests/integration/data/paste_primary.html b/tests/integration/data/paste_primary.html new file mode 100644 index 000000000..ff6e9ed54 --- /dev/null +++ b/tests/integration/data/paste_primary.html @@ -0,0 +1,10 @@ + + + + + Paste primary selection + + + + + diff --git a/tests/integration/features/yankpaste.feature b/tests/integration/features/yankpaste.feature index b09bf7ce5..3001a54d3 100644 --- a/tests/integration/features/yankpaste.feature +++ b/tests/integration/features/yankpaste.feature @@ -170,3 +170,49 @@ Feature: Yanking and pasting. history: - active: true url: http://localhost:*/data/hello3.txt + + Scenario: Pasting the primary selection into an empty text field + When selection is supported + And I open data/paste_primary.html + And I put "Hello world" into the primary selection + # Click the text field + And I run :hint all + And I run :follow-hint a + And I run :paste-primary + # Compare + And I run :jseval console.log(document.getElementById('qute-textarea').value); + Then the javascript message "Hello world" should be logged + + Scenario: Pasting the primary selection into a text field at specific position + When selection is supported + And I open data/paste_primary.html + And I run :jseval document.getElementById('qute-textarea').value = 'one two three four'; + And I put " Hello world" into the primary selection + # Click the text field + And I run :hint all + And I run :follow-hint a + # Move to the beginning and two words to the right + And I press the keys "" + And I press the key "" + And I press the key "" + And I run :paste-primary + # Compare + And I run :jseval console.log(document.getElementById('qute-textarea').value); + Then the javascript message "one two Hello world three four" should be logged + + Scenario: Pasting the primary selection into a text field with undo + When selection is supported + And I open data/paste_primary.html + # Click the text field + And I run :hint all + And I run :follow-hint a + # Paste and undo + And I put "This text should be undone" into the primary selection + And I run :paste-primary + And I press the key "" + # Paste final text + And I put "This text should stay" into the primary selection + And I run :paste-primary + # Compare + And I run :jseval console.log(document.getElementById('qute-textarea').value); + Then the javascript message "This text should stay" should be logged