From d77c9ae00903325de2ca2e114436c201b837d425 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Wed, 24 Jan 2018 18:53:06 -0500 Subject: [PATCH 1/8] Add prompt-yank command add yank_text property to utils.usertypes.Question class Resolves #2591 --- qutebrowser/browser/downloads.py | 1 + qutebrowser/mainwindow/prompt.py | 13 +++++++++++++ qutebrowser/utils/usertypes.py | 2 ++ 3 files changed, 16 insertions(+) diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index c064d700e..94dc2b471 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -166,6 +166,7 @@ def get_filename_question(*, suggested_filename, url, parent=None): q.title = "Save file to:" q.text = "Please enter a location for {}".format( html.escape(url.toDisplayString())) + q.yank_text = url.toString() q.mode = usertypes.PromptMode.download q.completed.connect(q.deleteLater) q.default = _path_suggestion(suggested_filename) diff --git a/qutebrowser/mainwindow/prompt.py b/qutebrowser/mainwindow/prompt.py index 3d21a52e0..f9c685c86 100644 --- a/qutebrowser/mainwindow/prompt.py +++ b/qutebrowser/mainwindow/prompt.py @@ -422,6 +422,18 @@ class PromptContainer(QWidget): except UnsupportedOperationError: pass + @cmdutils.register(instance='prompt-container', scope='window', + modes=[usertypes.KeyMode.prompt]) + def prompt_yank(self): + """Yank URLs or other data in prompts.""" + question = self._prompt.question + s = None + if question and hasattr(question, 'yank_text'): + s = question.yank_text + utils.set_clipboard(s) + message.info("Yanked download URL to clipboard: {}".format(s)) + + class LineEdit(QLineEdit): @@ -721,6 +733,7 @@ class DownloadFilenamePrompt(FilenamePrompt): ('prompt-accept', 'Accept'), ('leave-mode', 'Abort'), ('prompt-open-download', "Open download"), + ('prompt-yank', "Yank URLs in prompts"), ] return cmds diff --git a/qutebrowser/utils/usertypes.py b/qutebrowser/utils/usertypes.py index aad685d07..da1c2f00b 100644 --- a/qutebrowser/utils/usertypes.py +++ b/qutebrowser/utils/usertypes.py @@ -266,6 +266,7 @@ class Question(QObject): For user_pwd, a default username as string. title: The question title to show. text: The prompt text to display to the user. + yank_text: The prompt text available to prompt-yank command. answer: The value the user entered (as password for user_pwd). is_aborted: Whether the question was aborted. interrupted: Whether the question was interrupted by another one. @@ -296,6 +297,7 @@ class Question(QObject): self.default = None self.title = None self.text = None + self.yank_text = None self.answer = None self.is_aborted = False self.interrupted = False From 3b1fb92b11e9560732da3cf0e6e3df23ea403b73 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Wed, 24 Jan 2018 19:13:28 -0500 Subject: [PATCH 2/8] remove extra line to satisfy flake8 --- qutebrowser/mainwindow/prompt.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qutebrowser/mainwindow/prompt.py b/qutebrowser/mainwindow/prompt.py index f9c685c86..0a1142b81 100644 --- a/qutebrowser/mainwindow/prompt.py +++ b/qutebrowser/mainwindow/prompt.py @@ -434,7 +434,6 @@ class PromptContainer(QWidget): message.info("Yanked download URL to clipboard: {}".format(s)) - class LineEdit(QLineEdit): """A line edit used in prompts.""" From 520b4733501a274a03482d25a7d5c08dabcacbea Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Thu, 25 Jan 2018 17:48:45 -0500 Subject: [PATCH 3/8] modify Question.yank_text to Question.url error out when question.url is None add url to yesno prompts add default binding in prompt mode (ctrl-y) --- doc/help/commands.asciidoc | 5 +++++ doc/help/settings.asciidoc | 1 + qutebrowser/browser/downloads.py | 4 ++-- qutebrowser/browser/qtnetworkdownloads.py | 7 ++++-- qutebrowser/browser/shared.py | 22 +++++++++++++------ qutebrowser/browser/urlmarks.py | 5 +++-- .../browser/webengine/webenginedownloads.py | 2 ++ qutebrowser/browser/webengine/webenginetab.py | 3 ++- qutebrowser/browser/webkit/webpage.py | 3 ++- qutebrowser/config/configdata.yml | 1 + qutebrowser/mainwindow/prompt.py | 19 +++++++++------- qutebrowser/utils/message.py | 4 +++- qutebrowser/utils/usertypes.py | 4 ++-- 13 files changed, 54 insertions(+), 26 deletions(-) diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index 1008de1bf..16473c547 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -1404,6 +1404,7 @@ How many steps to zoom out. |<>|Accept the current prompt. |<>|Shift the focus of the prompt file completion menu to another item. |<>|Immediately open a download. +|<>|Yank URL. |<>|Move back a character. |<>|Delete the character before the cursor. |<>|Remove chars from the cursor to the beginning of the word. @@ -1609,6 +1610,10 @@ If no specific command is given, this will use the system's default application ==== note * This command does not split arguments after the last argument and handles quotes literally. +[[prompt-yank]] +=== prompt-yank +Yank URL. + [[rl-backward-char]] === rl-backward-char Move back a character. diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index 73aae6fb2..b648a65c4 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -627,6 +627,7 @@ Default: * +pass:[<Ctrl-W>]+: +pass:[rl-unix-word-rubout]+ * +pass:[<Ctrl-X>]+: +pass:[prompt-open-download]+ * +pass:[<Ctrl-Y>]+: +pass:[rl-yank]+ +* +pass:[<Ctrl-y>]+: +pass:[prompt-yank]+ * +pass:[<Down>]+: +pass:[prompt-item-focus next]+ * +pass:[<Escape>]+: +pass:[leave-mode]+ * +pass:[<Return>]+: +pass:[prompt-accept]+ diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index 94dc2b471..d174ebdd2 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -31,7 +31,7 @@ import enum import sip from PyQt5.QtCore import (pyqtSlot, pyqtSignal, Qt, QObject, QModelIndex, - QTimer, QAbstractListModel) + QTimer, QAbstractListModel, QUrl) from qutebrowser.commands import cmdexc, cmdutils from qutebrowser.config import config @@ -166,7 +166,7 @@ def get_filename_question(*, suggested_filename, url, parent=None): q.title = "Save file to:" q.text = "Please enter a location for {}".format( html.escape(url.toDisplayString())) - q.yank_text = url.toString() + q.url = url.toString(QUrl.RemoveUserInfo) q.mode = usertypes.PromptMode.download q.completed.connect(q.deleteLater) q.default = _path_suggestion(suggested_filename) diff --git a/qutebrowser/browser/qtnetworkdownloads.py b/qutebrowser/browser/qtnetworkdownloads.py index 378bc72b5..6e3dd7b29 100644 --- a/qutebrowser/browser/qtnetworkdownloads.py +++ b/qutebrowser/browser/qtnetworkdownloads.py @@ -20,6 +20,7 @@ """Download manager.""" import io +import os import shutil import functools @@ -198,21 +199,23 @@ class DownloadItem(downloads.AbstractDownloadItem): def _ask_confirm_question(self, title, msg): no_action = functools.partial(self.cancel, remove_data=False) + url = 'file://{}'.format(self._filename) message.confirm_async(title=title, text=msg, yes_action=self._after_set_filename, no_action=no_action, cancel_action=no_action, - abort_on=[self.cancelled, self.error]) + abort_on=[self.cancelled, self.error], url=url) def _ask_create_parent_question(self, title, msg, force_overwrite, remember_directory): no_action = functools.partial(self.cancel, remove_data=False) + url = 'file://{}'.format(os.path.dirname(self._filename)) message.confirm_async(title=title, text=msg, yes_action=(lambda: self._after_create_parent_question( force_overwrite, remember_directory)), no_action=no_action, cancel_action=no_action, - abort_on=[self.cancelled, self.error]) + abort_on=[self.cancelled, self.error], url=url) def _set_fileobj(self, fileobj, *, autoclose=True): """Set the file object to write the download to. diff --git a/qutebrowser/browser/shared.py b/qutebrowser/browser/shared.py index b6bfefe7b..43486b8f8 100644 --- a/qutebrowser/browser/shared.py +++ b/qutebrowser/browser/shared.py @@ -21,13 +21,14 @@ import html +from PyQt5.QtCore import QUrl + from qutebrowser.config import config from qutebrowser.utils import usertypes, message, log, objreg, jinja, utils from qutebrowser.mainwindow import mainwindow class CallSuper(Exception): - """Raised when the caller should call the superclass instead.""" @@ -61,9 +62,10 @@ def authentication_required(url, authenticator, abort_on): else: msg = '{} needs authentication'.format( html.escape(url.toDisplayString())) + urlstr = url.toString(QUrl.RemoveUserInfo) answer = message.ask(title="Authentication required", text=msg, mode=usertypes.PromptMode.user_pwd, - abort_on=abort_on) + abort_on=abort_on, url=urlstr) if answer is not None: authenticator.setUser(answer.user) authenticator.setPassword(answer.password) @@ -78,9 +80,10 @@ def javascript_confirm(url, js_msg, abort_on): msg = 'From {}:
{}'.format(html.escape(url.toDisplayString()), html.escape(js_msg)) + urlstr = url.toString(QUrl.RemoveUserInfo) ans = message.ask('Javascript confirm', msg, mode=usertypes.PromptMode.yesno, - abort_on=abort_on) + abort_on=abort_on, url=urlstr) return bool(ans) @@ -94,10 +97,11 @@ def javascript_prompt(url, js_msg, default, abort_on): msg = '{} asks:
{}'.format(html.escape(url.toDisplayString()), html.escape(js_msg)) + urlstr = url.toString(QUrl.RemoveUserInfo) answer = message.ask('Javascript prompt', msg, mode=usertypes.PromptMode.text, default=default, - abort_on=abort_on) + abort_on=abort_on, url=urlstr) if answer is None: return (False, "") @@ -116,8 +120,9 @@ def javascript_alert(url, js_msg, abort_on): msg = 'From {}:
{}'.format(html.escape(url.toDisplayString()), html.escape(js_msg)) + urlstr = url.toString(QUrl.RemoveUserInfo) message.ask('Javascript alert', msg, mode=usertypes.PromptMode.alert, - abort_on=abort_on) + abort_on=abort_on, url=urlstr) def javascript_log_message(level, source, line, msg): @@ -164,9 +169,10 @@ def ignore_certificate_errors(url, errors, abort_on): """.strip()) msg = err_template.render(url=url, errors=errors) + urlstr = url.toString(QUrl.RemoveUserInfo) ignore = message.ask(title="Certificate errors - continue?", text=msg, mode=usertypes.PromptMode.yesno, default=False, - abort_on=abort_on) + abort_on=abort_on, url=urlstr) if ignore is None: # prompt aborted ignore = False @@ -202,15 +208,17 @@ def feature_permission(url, option, msg, yes_action, no_action, abort_on): config_val = config.instance.get(option) if config_val == 'ask': if url.isValid(): + urlstr = url.toString(QUrl.RemoveUserInfo) text = "Allow the website at {} to {}?".format( html.escape(url.toDisplayString()), msg) else: + urlstr = None text = "Allow the website to {}?".format(msg) return message.confirm_async( yes_action=yes_action, no_action=no_action, cancel_action=no_action, abort_on=abort_on, - title='Permission request', text=text) + title='Permission request', text=text, url=urlstr) elif config_val: yes_action() return None diff --git a/qutebrowser/browser/urlmarks.py b/qutebrowser/browser/urlmarks.py index 5e2c60dfb..0ef8b9cb6 100644 --- a/qutebrowser/browser/urlmarks.py +++ b/qutebrowser/browser/urlmarks.py @@ -161,7 +161,7 @@ class QuickmarkManager(UrlMarkManager): "Add quickmark:", usertypes.PromptMode.text, functools.partial(self.quickmark_add, urlstr), text="Please enter a quickmark name for
{}".format( - html.escape(url.toDisplayString()))) + html.escape(url.toDisplayString())), url=urlstr) @cmdutils.register(instance='quickmark-manager') def quickmark_add(self, url, name): @@ -189,10 +189,11 @@ class QuickmarkManager(UrlMarkManager): self.changed.emit() log.misc.debug("Added quickmark {} for {}".format(name, url)) + urlstr = url.toString(QUrl.RemoveUserInfo) if name in self.marks: message.confirm_async( title="Override existing quickmark?", - yes_action=set_mark, default=True) + yes_action=set_mark, default=True, url=urlstr) else: set_mark() diff --git a/qutebrowser/browser/webengine/webenginedownloads.py b/qutebrowser/browser/webengine/webenginedownloads.py index d467724d5..506f4fccc 100644 --- a/qutebrowser/browser/webengine/webenginedownloads.py +++ b/qutebrowser/browser/webengine/webenginedownloads.py @@ -125,6 +125,7 @@ class DownloadItem(downloads.AbstractDownloadItem): question = usertypes.Question() question.title = title question.text = msg + question.url = 'file://{}'.format(self._filename) question.mode = usertypes.PromptMode.yesno question.answered_yes.connect(self._after_set_filename) question.answered_no.connect(no_action) @@ -139,6 +140,7 @@ class DownloadItem(downloads.AbstractDownloadItem): question = usertypes.Question() question.title = title question.text = msg + question.url = 'file://{}'.format(os.path.dirname(self._filename)) question.mode = usertypes.PromptMode.yesno question.answered_yes.connect(lambda: self._after_create_parent_question( diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 0523972df..c7e6dfef3 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -753,10 +753,11 @@ class WebEngineTab(browsertab.AbstractTab): """Called when a proxy needs authentication.""" msg = "{} requires a username and password.".format( html_utils.escape(proxy_host)) + urlstr = url.toString(QUrl.RemoveUserInfo) answer = message.ask( title="Proxy authentication required", text=msg, mode=usertypes.PromptMode.user_pwd, - abort_on=[self.shutting_down, self.load_started]) + abort_on=[self.shutting_down, self.load_started], url=urlstr) if answer is not None: authenticator.setUser(answer.user) authenticator.setPassword(answer.password) diff --git a/qutebrowser/browser/webkit/webpage.py b/qutebrowser/browser/webkit/webpage.py index 89407fcdf..b1aaf3a45 100644 --- a/qutebrowser/browser/webkit/webpage.py +++ b/qutebrowser/browser/webkit/webpage.py @@ -147,7 +147,8 @@ class BrowserPage(QWebPage): title="Open external application for {}-link?".format(scheme), text="URL: {}".format( html.escape(url.toDisplayString())), - yes_action=functools.partial(QDesktopServices.openUrl, url)) + yes_action=functools.partial(QDesktopServices.openUrl, url), + url=urlstr) return True elif (info.domain, info.error) in ignored_errors: log.webview.debug("Ignored error on {}: {} (error domain: {}, " diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index a118a8b59..8e7f9d8a8 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -2350,6 +2350,7 @@ bindings.default: : rl-unix-word-rubout : rl-backward-kill-word : rl-yank + : prompt-yank : rl-delete-char : rl-backward-delete-char : leave-mode diff --git a/qutebrowser/mainwindow/prompt.py b/qutebrowser/mainwindow/prompt.py index 0a1142b81..29afc62a4 100644 --- a/qutebrowser/mainwindow/prompt.py +++ b/qutebrowser/mainwindow/prompt.py @@ -422,16 +422,18 @@ class PromptContainer(QWidget): except UnsupportedOperationError: pass - @cmdutils.register(instance='prompt-container', scope='window', - modes=[usertypes.KeyMode.prompt]) + @cmdutils.register( + instance='prompt-container', scope='window', + modes=[usertypes.KeyMode.prompt, usertypes.KeyMode.yesno]) def prompt_yank(self): - """Yank URLs or other data in prompts.""" + """Yank URL.""" question = self._prompt.question - s = None - if question and hasattr(question, 'yank_text'): - s = question.yank_text + if not question.url: + message.error('No URL found.') + return + s = question.url utils.set_clipboard(s) - message.info("Yanked download URL to clipboard: {}".format(s)) + message.info("Yanked to clipboard: {}".format(s)) class LineEdit(QLineEdit): @@ -732,7 +734,7 @@ class DownloadFilenamePrompt(FilenamePrompt): ('prompt-accept', 'Accept'), ('leave-mode', 'Abort'), ('prompt-open-download', "Open download"), - ('prompt-yank', "Yank URLs in prompts"), + ('prompt-yank', "Yank URL"), ] return cmds @@ -823,6 +825,7 @@ class YesNoPrompt(_BasePrompt): cmds = [ ('prompt-accept yes', "Yes"), ('prompt-accept no', "No"), + ('prompt-yank', "Yank URL"), ] if self.question.default is not None: diff --git a/qutebrowser/utils/message.py b/qutebrowser/utils/message.py index 32395b8bd..1d321e767 100644 --- a/qutebrowser/utils/message.py +++ b/qutebrowser/utils/message.py @@ -87,7 +87,8 @@ def info(message, *, replace=False): global_bridge.show(usertypes.MessageLevel.info, message, replace) -def _build_question(title, text=None, *, mode, default=None, abort_on=()): +def _build_question(title, text=None, *, mode, default=None, abort_on=(), + url=None): """Common function for ask/ask_async.""" if not isinstance(mode, usertypes.PromptMode): raise TypeError("Mode {} is no PromptMode member!".format(mode)) @@ -96,6 +97,7 @@ def _build_question(title, text=None, *, mode, default=None, abort_on=()): question.text = text question.mode = mode question.default = default + question.url = url for sig in abort_on: sig.connect(question.abort) return question diff --git a/qutebrowser/utils/usertypes.py b/qutebrowser/utils/usertypes.py index da1c2f00b..45e7addfb 100644 --- a/qutebrowser/utils/usertypes.py +++ b/qutebrowser/utils/usertypes.py @@ -266,7 +266,7 @@ class Question(QObject): For user_pwd, a default username as string. title: The question title to show. text: The prompt text to display to the user. - yank_text: The prompt text available to prompt-yank command. + url: Any URL referenced in prompts. answer: The value the user entered (as password for user_pwd). is_aborted: Whether the question was aborted. interrupted: Whether the question was interrupted by another one. @@ -297,7 +297,7 @@ class Question(QObject): self.default = None self.title = None self.text = None - self.yank_text = None + self.url = None self.answer = None self.is_aborted = False self.interrupted = False From ddcc960aa5c166e7999e5d7875f3670cbc803e18 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Thu, 25 Jan 2018 22:01:18 -0500 Subject: [PATCH 4/8] url arg was a string --- qutebrowser/browser/urlmarks.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qutebrowser/browser/urlmarks.py b/qutebrowser/browser/urlmarks.py index 0ef8b9cb6..f372b64b3 100644 --- a/qutebrowser/browser/urlmarks.py +++ b/qutebrowser/browser/urlmarks.py @@ -189,11 +189,10 @@ class QuickmarkManager(UrlMarkManager): self.changed.emit() log.misc.debug("Added quickmark {} for {}".format(name, url)) - urlstr = url.toString(QUrl.RemoveUserInfo) if name in self.marks: message.confirm_async( title="Override existing quickmark?", - yes_action=set_mark, default=True, url=urlstr) + yes_action=set_mark, default=True, url=url) else: set_mark() From fe4dd579f9cfa0283f91c1ca1343b43747cb3ad0 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Fri, 26 Jan 2018 22:06:05 -0500 Subject: [PATCH 5/8] add --sel option to prompt-yank --- doc/help/commands.asciidoc | 9 +++++++-- doc/help/settings.asciidoc | 4 ++-- qutebrowser/config/configdata.yml | 4 ++-- qutebrowser/mainwindow/prompt.py | 16 ++++++++++++---- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index 16473c547..5ce4daf4d 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -1404,7 +1404,7 @@ How many steps to zoom out. |<>|Accept the current prompt. |<>|Shift the focus of the prompt file completion menu to another item. |<>|Immediately open a download. -|<>|Yank URL. +|<>|Yank URL to clipboard or primary selection. |<>|Move back a character. |<>|Delete the character before the cursor. |<>|Remove chars from the cursor to the beginning of the word. @@ -1612,7 +1612,12 @@ If no specific command is given, this will use the system's default application [[prompt-yank]] === prompt-yank -Yank URL. +Syntax: +:prompt-yank [*--sel*]+ + +Yank URL to clipboard or primary selection. + +==== optional arguments +* +*-s*+, +*--sel*+: Use the primary selection instead of the clipboard. [[rl-backward-char]] === rl-backward-char diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index b648a65c4..0455040a2 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -623,11 +623,11 @@ Default: * +pass:[<Ctrl-F>]+: +pass:[rl-forward-char]+ * +pass:[<Ctrl-H>]+: +pass:[rl-backward-delete-char]+ * +pass:[<Ctrl-K>]+: +pass:[rl-kill-line]+ +* +pass:[<Ctrl-Shift-Y>]+: +pass:[prompt-yank --sel]+ * +pass:[<Ctrl-U>]+: +pass:[rl-unix-line-discard]+ * +pass:[<Ctrl-W>]+: +pass:[rl-unix-word-rubout]+ * +pass:[<Ctrl-X>]+: +pass:[prompt-open-download]+ -* +pass:[<Ctrl-Y>]+: +pass:[rl-yank]+ -* +pass:[<Ctrl-y>]+: +pass:[prompt-yank]+ +* +pass:[<Ctrl-Y>]+: +pass:[prompt-yank]+ * +pass:[<Down>]+: +pass:[prompt-item-focus next]+ * +pass:[<Escape>]+: +pass:[leave-mode]+ * +pass:[<Return>]+: +pass:[prompt-accept]+ diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 8e7f9d8a8..d044291ad 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -2349,8 +2349,8 @@ bindings.default: : rl-kill-word : rl-unix-word-rubout : rl-backward-kill-word - : rl-yank - : prompt-yank + : prompt-yank + : prompt-yank --sel : rl-delete-char : rl-backward-delete-char : leave-mode diff --git a/qutebrowser/mainwindow/prompt.py b/qutebrowser/mainwindow/prompt.py index 29afc62a4..aff6701fc 100644 --- a/qutebrowser/mainwindow/prompt.py +++ b/qutebrowser/mainwindow/prompt.py @@ -425,15 +425,23 @@ class PromptContainer(QWidget): @cmdutils.register( instance='prompt-container', scope='window', modes=[usertypes.KeyMode.prompt, usertypes.KeyMode.yesno]) - def prompt_yank(self): - """Yank URL.""" + def prompt_yank(self, sel=False): + """Yank URL to clipboard or primary selection. + + Args: + sel: Use the primary selection instead of the clipboard. + """ question = self._prompt.question if not question.url: message.error('No URL found.') return s = question.url - utils.set_clipboard(s) - message.info("Yanked to clipboard: {}".format(s)) + target = 'primary selection' + if not (sel and utils.supports_selection()): + target = 'clipboard' + sel = False + utils.set_clipboard(s, sel) + message.info("Yanked to {}: {}".format(target, s)) class LineEdit(QLineEdit): From 1a2ab0ffe7a414563e889519ac28f65bd115a9d6 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 28 Jan 2018 10:28:11 -0500 Subject: [PATCH 6/8] add back rl-yank key binding; use alt-y for prompt-yank. --- qutebrowser/browser/qtnetworkdownloads.py | 2 +- qutebrowser/config/configdata.yml | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/qutebrowser/browser/qtnetworkdownloads.py b/qutebrowser/browser/qtnetworkdownloads.py index 6e3dd7b29..6dcc13c6e 100644 --- a/qutebrowser/browser/qtnetworkdownloads.py +++ b/qutebrowser/browser/qtnetworkdownloads.py @@ -20,7 +20,7 @@ """Download manager.""" import io -import os +import os.path import shutil import functools diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index d044291ad..3cba3e6c5 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -2338,6 +2338,8 @@ bindings.default: : prompt-item-focus prev : prompt-item-focus next : prompt-item-focus next + : prompt-yank + : prompt-yank --sel : rl-backward-char : rl-forward-char : rl-backward-word @@ -2349,10 +2351,9 @@ bindings.default: : rl-kill-word : rl-unix-word-rubout : rl-backward-kill-word - : prompt-yank - : prompt-yank --sel : rl-delete-char : rl-backward-delete-char + : rl-yank : leave-mode caret: v: toggle-selection From f16f425cb12071720dadf82e6aca0bb85adf1c74 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 28 Jan 2018 10:41:09 -0500 Subject: [PATCH 7/8] generate the docs --- doc/help/settings.asciidoc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index 0455040a2..164f26f78 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -616,6 +616,8 @@ Default: * +pass:[<Alt-Backspace>]+: +pass:[rl-backward-kill-word]+ * +pass:[<Alt-D>]+: +pass:[rl-kill-word]+ * +pass:[<Alt-F>]+: +pass:[rl-forward-word]+ +* +pass:[<Alt-Shift-Y>]+: +pass:[prompt-yank --sel]+ +* +pass:[<Alt-Y>]+: +pass:[prompt-yank]+ * +pass:[<Ctrl-?>]+: +pass:[rl-delete-char]+ * +pass:[<Ctrl-A>]+: +pass:[rl-beginning-of-line]+ * +pass:[<Ctrl-B>]+: +pass:[rl-backward-char]+ @@ -623,11 +625,10 @@ Default: * +pass:[<Ctrl-F>]+: +pass:[rl-forward-char]+ * +pass:[<Ctrl-H>]+: +pass:[rl-backward-delete-char]+ * +pass:[<Ctrl-K>]+: +pass:[rl-kill-line]+ -* +pass:[<Ctrl-Shift-Y>]+: +pass:[prompt-yank --sel]+ * +pass:[<Ctrl-U>]+: +pass:[rl-unix-line-discard]+ * +pass:[<Ctrl-W>]+: +pass:[rl-unix-word-rubout]+ * +pass:[<Ctrl-X>]+: +pass:[prompt-open-download]+ -* +pass:[<Ctrl-Y>]+: +pass:[prompt-yank]+ +* +pass:[<Ctrl-Y>]+: +pass:[rl-yank]+ * +pass:[<Down>]+: +pass:[prompt-item-focus next]+ * +pass:[<Escape>]+: +pass:[leave-mode]+ * +pass:[<Return>]+: +pass:[prompt-accept]+ From c6ad23f9215f361426b254734ec5c4168fc55a94 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sat, 10 Feb 2018 00:38:27 -0500 Subject: [PATCH 8/8] address all mentionned issues except for file:// - re-encode url using QUrl.RemovePassword | QUrl.FullyEncoded - improve readability for clipboard / primary selection code block --- qutebrowser/browser/downloads.py | 2 +- qutebrowser/browser/shared.py | 12 ++++++------ qutebrowser/browser/webengine/webenginetab.py | 2 +- qutebrowser/browser/webkit/webpage.py | 2 +- qutebrowser/mainwindow/prompt.py | 14 +++++++------- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index d174ebdd2..b90571fa5 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -166,7 +166,7 @@ def get_filename_question(*, suggested_filename, url, parent=None): q.title = "Save file to:" q.text = "Please enter a location for {}".format( html.escape(url.toDisplayString())) - q.url = url.toString(QUrl.RemoveUserInfo) + q.url = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded) q.mode = usertypes.PromptMode.download q.completed.connect(q.deleteLater) q.default = _path_suggestion(suggested_filename) diff --git a/qutebrowser/browser/shared.py b/qutebrowser/browser/shared.py index 43486b8f8..b2baabd36 100644 --- a/qutebrowser/browser/shared.py +++ b/qutebrowser/browser/shared.py @@ -62,7 +62,7 @@ def authentication_required(url, authenticator, abort_on): else: msg = '{} needs authentication'.format( html.escape(url.toDisplayString())) - urlstr = url.toString(QUrl.RemoveUserInfo) + urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded) answer = message.ask(title="Authentication required", text=msg, mode=usertypes.PromptMode.user_pwd, abort_on=abort_on, url=urlstr) @@ -80,7 +80,7 @@ def javascript_confirm(url, js_msg, abort_on): msg = 'From {}:
{}'.format(html.escape(url.toDisplayString()), html.escape(js_msg)) - urlstr = url.toString(QUrl.RemoveUserInfo) + urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded) ans = message.ask('Javascript confirm', msg, mode=usertypes.PromptMode.yesno, abort_on=abort_on, url=urlstr) @@ -97,7 +97,7 @@ def javascript_prompt(url, js_msg, default, abort_on): msg = '{} asks:
{}'.format(html.escape(url.toDisplayString()), html.escape(js_msg)) - urlstr = url.toString(QUrl.RemoveUserInfo) + urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded) answer = message.ask('Javascript prompt', msg, mode=usertypes.PromptMode.text, default=default, @@ -120,7 +120,7 @@ def javascript_alert(url, js_msg, abort_on): msg = 'From {}:
{}'.format(html.escape(url.toDisplayString()), html.escape(js_msg)) - urlstr = url.toString(QUrl.RemoveUserInfo) + urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded) message.ask('Javascript alert', msg, mode=usertypes.PromptMode.alert, abort_on=abort_on, url=urlstr) @@ -169,7 +169,7 @@ def ignore_certificate_errors(url, errors, abort_on): """.strip()) msg = err_template.render(url=url, errors=errors) - urlstr = url.toString(QUrl.RemoveUserInfo) + urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded) ignore = message.ask(title="Certificate errors - continue?", text=msg, mode=usertypes.PromptMode.yesno, default=False, abort_on=abort_on, url=urlstr) @@ -208,7 +208,7 @@ def feature_permission(url, option, msg, yes_action, no_action, abort_on): config_val = config.instance.get(option) if config_val == 'ask': if url.isValid(): - urlstr = url.toString(QUrl.RemoveUserInfo) + urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded) text = "Allow the website at {} to {}?".format( html.escape(url.toDisplayString()), msg) else: diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index c7e6dfef3..1bf9ceb03 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -753,7 +753,7 @@ class WebEngineTab(browsertab.AbstractTab): """Called when a proxy needs authentication.""" msg = "{} requires a username and password.".format( html_utils.escape(proxy_host)) - urlstr = url.toString(QUrl.RemoveUserInfo) + urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded) answer = message.ask( title="Proxy authentication required", text=msg, mode=usertypes.PromptMode.user_pwd, diff --git a/qutebrowser/browser/webkit/webpage.py b/qutebrowser/browser/webkit/webpage.py index b1aaf3a45..abdca68dc 100644 --- a/qutebrowser/browser/webkit/webpage.py +++ b/qutebrowser/browser/webkit/webpage.py @@ -148,7 +148,7 @@ class BrowserPage(QWebPage): text="URL: {}".format( html.escape(url.toDisplayString())), yes_action=functools.partial(QDesktopServices.openUrl, url), - url=urlstr) + url=info.url.toString(QUrl.FullyEncoded)) return True elif (info.domain, info.error) in ignored_errors: log.webview.debug("Ignored error on {}: {} (error domain: {}, " diff --git a/qutebrowser/mainwindow/prompt.py b/qutebrowser/mainwindow/prompt.py index aff6701fc..b502f1f3d 100644 --- a/qutebrowser/mainwindow/prompt.py +++ b/qutebrowser/mainwindow/prompt.py @@ -432,16 +432,16 @@ class PromptContainer(QWidget): sel: Use the primary selection instead of the clipboard. """ question = self._prompt.question - if not question.url: + if question.url is None: message.error('No URL found.') return - s = question.url - target = 'primary selection' - if not (sel and utils.supports_selection()): - target = 'clipboard' + if sel and utils.supports_selection(): + target = 'primary selection' + else: sel = False - utils.set_clipboard(s, sel) - message.info("Yanked to {}: {}".format(target, s)) + target = 'clipboard' + utils.set_clipboard(question.url, sel) + message.info("Yanked to {}: {}".format(target, question.url)) class LineEdit(QLineEdit):