From dc69a90e69642a39dcacd4764f1d29ee1357834f Mon Sep 17 00:00:00 2001 From: Jan Verbeek Date: Sun, 7 Aug 2016 02:43:08 +0200 Subject: [PATCH 01/10] Add :insert-text command See #1790. :paste-primary now calls :insert-text and can be deprecated by :insert-text {primary} after #1791 is merged. --- doc/help/commands.asciidoc | 13 +++++++++++++ qutebrowser/browser/commands.py | 27 +++++++++++++++++---------- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index f43be5822..13487a823 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -918,6 +918,7 @@ How many steps to zoom out. |<>|Enter a key mode. |<>|Follow a hint. |<>|Follow the selected text. +|<>|Insert text at cursor position. |<>|Jump to the mark named by `key`. |<>|Leave the mode we're currently in. |<>|Show an error message in the statusbar. @@ -1028,6 +1029,18 @@ Follow the selected text. ==== optional arguments * +*-t*+, +*--tab*+: Load the selected link in a new tab. +[[insert-text]] +=== insert-text +Syntax: +:insert-text 'text'+ + +Insert text at cursor position. + +==== positional arguments +* +'text'+: The text to insert. + +==== note +* This command does not split arguments after the last argument and handles quotes literally. + [[jump-mark]] === jump-mark Syntax: +:jump-mark 'key'+ diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 3728ebac4..cd60510dd 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1431,6 +1431,19 @@ class CommandDispatcher: needs_js=True, backend=usertypes.Backend.QtWebKit) def paste_primary(self): """Paste the primary selection at cursor position.""" + try: + self.insert_text(utils.get_clipboard(selection=True)) + except utils.SelectionUnsupportedError: + self.insert_text(utils.get_clipboard()) + + @cmdutils.register(instance='command-dispatcher', maxsplit=0, + modes=[KeyMode.insert], hide=True, scope='window', + needs_js=True, backend=usertypes.Backend.QtWebKit) + def insert_text(self, text): + """Insert text at cursor position. + + Args: + text: The text to insert.""" # FIXME:qtwebengine have a proper API for this tab = self._current_widget() page = tab._widget.page() # pylint: disable=protected-access @@ -1440,20 +1453,14 @@ class CommandDispatcher: raise cmdexc.CommandError("No element focused!") if not elem.is_editable(strict=True): raise cmdexc.CommandError("Focused element is not editable!") - - try: - sel = utils.get_clipboard(selection=True) - except utils.SelectionUnsupportedError: - sel = utils.get_clipboard() - - log.misc.debug("Pasting primary selection into element {}".format( + log.misc.debug("Inserting text into element {}".format( elem.debug_text())) elem.run_js_async(""" - var sel = '{}'; + var text = '{}'; var event = document.createEvent('TextEvent'); - event.initTextEvent('textInput', true, true, null, sel); + event.initTextEvent('textInput', true, true, null, text); this.dispatchEvent(event); - """.format(javascript.string_escape(sel))) + """.format(javascript.string_escape(text))) def _search_cb(self, found, *, tab, old_scroll_pos, options, text, prev): """Callback called from search/search_next/search_prev. From 864c95007fb5083da2de4ce9f6d35a8ec7523e8f Mon Sep 17 00:00:00 2001 From: Jan Verbeek Date: Sun, 7 Aug 2016 14:29:52 +0200 Subject: [PATCH 02/10] Unhide :insert-text and allow outside insert mode :insert-text works if a text element is focused, even outside insert mode. --- qutebrowser/browser/commands.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index cd60510dd..d60ba3c49 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1437,8 +1437,8 @@ class CommandDispatcher: self.insert_text(utils.get_clipboard()) @cmdutils.register(instance='command-dispatcher', maxsplit=0, - modes=[KeyMode.insert], hide=True, scope='window', - needs_js=True, backend=usertypes.Backend.QtWebKit) + scope='window', needs_js=True, + backend=usertypes.Backend.QtWebKit) def insert_text(self, text): """Insert text at cursor position. From 4966debd61426bea25a4c82fbfeeb27d17dcca5e Mon Sep 17 00:00:00 2001 From: Jan Verbeek Date: Wed, 10 Aug 2016 21:55:16 +0200 Subject: [PATCH 03/10] Deprecate :paste-primary to :insert-text {primary} --- doc/help/commands.asciidoc | 26 +++++------ qutebrowser/browser/commands.py | 1 + qutebrowser/config/configdata.py | 4 +- tests/end2end/features/yankpaste.feature | 59 ++++++++---------------- tests/end2end/test_insert_mode.py | 2 +- 5 files changed, 36 insertions(+), 56 deletions(-) diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index be151f6ee..97fd8fcb5 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -32,6 +32,7 @@ |<>|Start hinting. |<>|Clear all browsing history. |<>|Open main startpage in current tab. +|<>|Insert text at cursor position. |<>|Toggle the web inspector. |<>|Evaluate a JavaScript string. |<>|Execute a command after some time. @@ -402,6 +403,18 @@ Note this only clears the global history (e.g. `~/.local/share/qutebrowser/histo === home Open main startpage in current tab. +[[insert-text]] +=== insert-text +Syntax: +:insert-text 'text'+ + +Insert text at cursor position. + +==== positional arguments +* +'text'+: The text to insert. + +==== note +* This command does not split arguments after the last argument and handles quotes literally. + [[inspector]] === inspector Toggle the web inspector. @@ -919,7 +932,6 @@ How many steps to zoom out. |<>|Enter a key mode. |<>|Follow a hint. |<>|Follow the selected text. -|<>|Insert text at cursor position. |<>|Jump to the mark named by `key`. |<>|Leave the mode we're currently in. |<>|Show an error message in the statusbar. @@ -1031,18 +1043,6 @@ Follow the selected text. ==== optional arguments * +*-t*+, +*--tab*+: Load the selected link in a new tab. -[[insert-text]] -=== insert-text -Syntax: +:insert-text 'text'+ - -Insert text at cursor position. - -==== positional arguments -* +'text'+: The text to insert. - -==== note -* This command does not split arguments after the last argument and handles quotes literally. - [[jump-mark]] === jump-mark Syntax: +:jump-mark 'key'+ diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index e0ac9f495..e0202f277 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1486,6 +1486,7 @@ class CommandDispatcher: raise cmdexc.CommandError("Element vanished while editing!") @cmdutils.register(instance='command-dispatcher', + deprecated="Use :insert-text {primary}", modes=[KeyMode.insert], hide=True, scope='window', needs_js=True, backend=usertypes.Backend.QtWebKit) def paste_primary(self): diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index b62968904..be004b943 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -1585,7 +1585,7 @@ KEY_DATA = collections.OrderedDict([ ('insert', collections.OrderedDict([ ('open-editor', ['']), - ('paste-primary', ['']), + ('insert-text {primary}', ['']), ])), ('hint', collections.OrderedDict([ @@ -1705,4 +1705,6 @@ CHANGED_KEY_COMMANDS = [ (re.compile(r'^completion-item-next'), r'completion-item-focus next'), (re.compile(r'^completion-item-prev'), r'completion-item-focus prev'), + + (re.compile(r'^paste-primary$'), r'insert-text {primary}'), ] diff --git a/tests/end2end/features/yankpaste.feature b/tests/end2end/features/yankpaste.feature index c453b2e42..8c02612a0 100644 --- a/tests/end2end/features/yankpaste.feature +++ b/tests/end2end/features/yankpaste.feature @@ -227,25 +227,21 @@ Feature: Yanking and pasting. And I run :open -t {clipboard} Then no crash should happen - #### :paste-primary + #### :insert-text - 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 + Scenario: Inserting text into an empty text field + When I open data/paste_primary.html # Click the text field And I run :hint all And I run :follow-hint a And I wait for "Clicked editable element!" in the log - And I run :paste-primary + And I run :insert-text Hello world # Compare Then the text field should contain "Hello world" - Scenario: Pasting the primary selection into a text field at specific position - When selection is supported - And I open data/paste_primary.html + Scenario: Inserting text into a text field at specific position + When I open data/paste_primary.html And I set the text field to "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 @@ -254,55 +250,36 @@ Feature: Yanking and pasting. And I press the keys "" And I press the key "" And I press the key "" - And I run :paste-primary + And I run :insert-text Hello world # Compare - Then the text field should contain "one two Hello world three four" + Then the text field should contain "one twoHello world three four" - Scenario: Pasting the primary selection into a text field with undo - When selection is supported - And I open data/paste_primary.html + Scenario: Inserting text into a text field with undo + When I open data/paste_primary.html # Click the text field And I run :hint all And I run :follow-hint a And I wait for "Clicked editable element!" in the log # Paste and undo - And I put "This text should be undone" into the primary selection - And I run :paste-primary + And I run :insert-text This text should be undone And I press the key "" # Paste final text - And I put "This text should stay" into the primary selection - And I run :paste-primary + And I run :insert-text This text should stay # Compare Then the text field should contain "This text should stay" - Scenario: Pasting the primary selection without a focused field - When selection is supported - And I open data/paste_primary.html - And I put "test" into the primary selection + Scenario: Inserting text without a focused field + When I open data/paste_primary.html And I run :enter-mode insert - And I run :paste-primary + And I run :insert-text test Then the error "No element focused!" should be shown - Scenario: Pasting the primary selection with a read-only field - When selection is supported - And I open data/paste_primary.html + Scenario: Inserting text with a read-only field + When I open data/paste_primary.html # Click the text field And I run :hint all And I run :follow-hint s And I wait for "Clicked non-editable element!" in the log - And I put "test" into the primary selection And I run :enter-mode insert - And I run :paste-primary + And I run :insert-text test Then the error "Focused element is not editable!" should be shown - - Scenario: :paste-primary without primary selection supported - When selection is not supported - And I open data/paste_primary.html - And I put "Hello world" into the clipboard - # Click the text field - And I run :hint all - And I run :follow-hint a - And I wait for "Clicked editable element!" in the log - And I run :paste-primary - # Compare - Then the text field should contain "Hello world" diff --git a/tests/end2end/test_insert_mode.py b/tests/end2end/test_insert_mode.py index c8a7f32de..d6c5022aa 100644 --- a/tests/end2end/test_insert_mode.py +++ b/tests/end2end/test_insert_mode.py @@ -46,7 +46,7 @@ def test_insert_mode(file_name, source, input_text, auto_insert, quteproc): quteproc.press_keys(input_text) elif source == 'clipboard': quteproc.send_cmd(':debug-set-fake-clipboard "{}"'.format(input_text)) - quteproc.send_cmd(':paste-primary') + quteproc.send_cmd(':insert-text {primary}') quteproc.send_cmd(':hint all') quteproc.send_cmd(':follow-hint a') From d6dff8b05e499f588e73a18c1792b477d9ee7bc8 Mon Sep 17 00:00:00 2001 From: Jan Verbeek Date: Wed, 10 Aug 2016 21:59:03 +0200 Subject: [PATCH 04/10] Regenerate asciidoc after 4a14ab5 --- doc/help/commands.asciidoc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index 97fd8fcb5..32b8bd413 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -953,7 +953,6 @@ How many steps to zoom out. |<>|Move the cursor or selection to the start of next block. |<>|Move the cursor or selection to the start of previous block. |<>|Open an external editor with the currently selected form field. -|<>|Paste the primary selection at cursor position. |<>|Accept the current prompt. |<>|Answer no to a yes/no prompt. |<>|Immediately open a download. @@ -1182,10 +1181,6 @@ Open an external editor with the currently selected form field. The editor which should be launched can be configured via the `general -> editor` config option. -[[paste-primary]] -=== paste-primary -Paste the primary selection at cursor position. - [[prompt-accept]] === prompt-accept Accept the current prompt. From d2d92c9f2e3315b95e4bbc2f345630fe9b580088 Mon Sep 17 00:00:00 2001 From: Jan Verbeek Date: Wed, 10 Aug 2016 22:29:19 +0200 Subject: [PATCH 05/10] Fix docstring --- qutebrowser/browser/commands.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index e0202f277..199fcd33b 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1503,7 +1503,8 @@ class CommandDispatcher: """Insert text at cursor position. Args: - text: The text to insert.""" + text: The text to insert. + """ # FIXME:qtwebengine have a proper API for this tab = self._current_widget() page = tab._widget.page() # pylint: disable=protected-access From 28430a4e4306c2698c16e82c74df736c28828049 Mon Sep 17 00:00:00 2001 From: Jan Verbeek Date: Thu, 11 Aug 2016 01:36:03 +0200 Subject: [PATCH 06/10] Make test_insert_mode Windows-compatible --- tests/end2end/test_insert_mode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/end2end/test_insert_mode.py b/tests/end2end/test_insert_mode.py index d6c5022aa..941c2cc74 100644 --- a/tests/end2end/test_insert_mode.py +++ b/tests/end2end/test_insert_mode.py @@ -46,7 +46,7 @@ def test_insert_mode(file_name, source, input_text, auto_insert, quteproc): quteproc.press_keys(input_text) elif source == 'clipboard': quteproc.send_cmd(':debug-set-fake-clipboard "{}"'.format(input_text)) - quteproc.send_cmd(':insert-text {primary}') + quteproc.send_cmd(':insert-text {clipboard}') quteproc.send_cmd(':hint all') quteproc.send_cmd(':follow-hint a') From e7367bd949a7ad85327e27f4cec0858a3ec666ff Mon Sep 17 00:00:00 2001 From: Jan Verbeek Date: Thu, 11 Aug 2016 02:26:48 +0200 Subject: [PATCH 07/10] Make :insert-text test platform-independent The test for inserting text at a specific position failed because doesn't behave the same on Windows and Linux. This changes it to move the cursor using other keys. --- tests/end2end/features/yankpaste.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/end2end/features/yankpaste.feature b/tests/end2end/features/yankpaste.feature index 8c02612a0..2b6a84cb7 100644 --- a/tests/end2end/features/yankpaste.feature +++ b/tests/end2end/features/yankpaste.feature @@ -248,11 +248,11 @@ Feature: Yanking and pasting. And I wait for "Clicked editable element!" in the log # 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 press the key "" + And I press the key "" And I run :insert-text Hello world # Compare - Then the text field should contain "one twoHello world three four" + Then the text field should contain "onHello worlde two three four" Scenario: Inserting text into a text field with undo When I open data/paste_primary.html From 79ab5da45b34e92b66e578945ba2b9cc86437a99 Mon Sep 17 00:00:00 2001 From: Jan Verbeek Date: Thu, 11 Aug 2016 14:04:30 +0200 Subject: [PATCH 08/10] Update test comment --- tests/end2end/features/yankpaste.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/end2end/features/yankpaste.feature b/tests/end2end/features/yankpaste.feature index 2b6a84cb7..8b098e545 100644 --- a/tests/end2end/features/yankpaste.feature +++ b/tests/end2end/features/yankpaste.feature @@ -246,7 +246,7 @@ Feature: Yanking and pasting. And I run :hint all And I run :follow-hint a And I wait for "Clicked editable element!" in the log - # Move to the beginning and two words to the right + # Move to the beginning and two characters to the right And I press the keys "" And I press the key "" And I press the key "" From 9c76ce1255d18d0c96ba40a42adb88b23492e61e Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 16 Aug 2016 13:31:41 +0200 Subject: [PATCH 09/10] Update docs --- CHANGELOG.asciidoc | 4 ++++ README.asciidoc | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 21fcfb461..353aadfa2 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -32,6 +32,8 @@ Added in rapid mode. - New `{clipboard}` and `{primary}` replacements for the commandline which replace the `:paste` command. +- New `:insert-text` command to insert a given text into a field on the page, + which replaces `:paste-primary` together with the `{primary}` replacement. - New `:window-only` command to close all other windows. - New `prev-category` and `next-category` arguments to `:completion-item-focus` to focus the previous/next category in the completion (bound to `` @@ -80,6 +82,8 @@ Deprecated - The `:paste` command got deprecated as `:open` with `{clipboard}` and `{primary}` can be used instead. +- The `:paste-primary` command got deprecated as `:insert-text {primary}` can + be used instead. Removed ~~~~~~~ diff --git a/README.asciidoc b/README.asciidoc index 7a1510e29..2c416f4e4 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -145,8 +145,8 @@ Contributors, sorted by the number of commits in descending order: * Jakub Klinkovský * Antoni Boucher * Lamar Pavel -* Bruno Oliveira * Jan Verbeek +* Bruno Oliveira * Alexander Cogneau * Marshall Lochbaum * Felix Van der Jeugt From 5ecef0004cb7b7fc5f504bc6fbc48fa16e7c247c Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 16 Aug 2016 13:31:53 +0200 Subject: [PATCH 10/10] Add some docs for command replacements --- doc/help/commands.asciidoc | 12 ++++++++++++ qutebrowser/commands/__init__.py | 13 ++++++++++++- scripts/dev/src2asciidoc.py | 5 +++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index 45f2fc1ef..082997884 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -4,6 +4,18 @@ = Commands +In qutebrowser, all keybindings are mapped to commands. + +Some commands are hidden, which means they don't show up in the command +completion when pressing `:`, as they're typically not useful to run by hand. + +In the commandline, there are also some variables you can use: + +- `{url}` expands to the URL of the current page +- `{url:pretty}` expands to the URL in decoded format +- `{clipboard}` expands to the clipboard contents +- `{primary}` expands to the primary selection contents + == Normal commands .Quick reference [options="header",width="75%",cols="25%,75%"] diff --git a/qutebrowser/commands/__init__.py b/qutebrowser/commands/__init__.py index 07a5cba0a..bf44e449a 100644 --- a/qutebrowser/commands/__init__.py +++ b/qutebrowser/commands/__init__.py @@ -17,4 +17,15 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -"""Utilities and classes regarding to commands.""" +"""In qutebrowser, all keybindings are mapped to commands. + +Some commands are hidden, which means they don't show up in the command +completion when pressing `:`, as they're typically not useful to run by hand. + +In the commandline, there are also some variables you can use: + +- `{url}` expands to the URL of the current page +- `{url:pretty}` expands to the URL in decoded format +- `{clipboard}` expands to the clipboard contents +- `{primary}` expands to the primary selection contents +""" diff --git a/scripts/dev/src2asciidoc.py b/scripts/dev/src2asciidoc.py index 0ca72d860..6a29c3410 100755 --- a/scripts/dev/src2asciidoc.py +++ b/scripts/dev/src2asciidoc.py @@ -37,7 +37,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir, # We import qutebrowser.app so all @cmdutils-register decorators are run. import qutebrowser.app from scripts import asciidoc2html, utils -from qutebrowser import qutebrowser +from qutebrowser import qutebrowser, commands from qutebrowser.commands import cmdutils, argparser from qutebrowser.config import configdata from qutebrowser.utils import docutils, usertypes @@ -320,7 +320,8 @@ def generate_commands(filename): """Generate the complete commands section.""" with _open_file(filename) as f: f.write(FILE_HEADER) - f.write("= Commands\n") + f.write("= Commands\n\n") + f.write(commands.__doc__) normal_cmds = [] hidden_cmds = [] debug_cmds = []