From 0fd64419da4548321773d8ec5265a91947bfd700 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 20 Jun 2014 16:33:01 +0200 Subject: [PATCH] Remove urlutils.{urlstring,qurl}. The idea of treating an URL-string and a QUrl as essentially the same data type got us into all kinds of problems. Now we use QUrl everywhere except at the borders to the user interface. --- qutebrowser/app.py | 46 ++++++++++------ qutebrowser/browser/commands.py | 63 +++++++++++++--------- qutebrowser/browser/downloads.py | 7 ++- qutebrowser/browser/hints.py | 60 ++++++++++----------- qutebrowser/browser/quickmarks.py | 16 +++--- qutebrowser/browser/webpage.py | 3 +- qutebrowser/network/qutescheme.py | 28 ++++------ qutebrowser/test/utils/test_url.py | 37 ------------- qutebrowser/utils/url.py | 81 +++++++++------------------- qutebrowser/utils/webelem.py | 5 +- qutebrowser/widgets/tabbedbrowser.py | 10 ++-- qutebrowser/widgets/webview.py | 28 +++++----- 12 files changed, 165 insertions(+), 219 deletions(-) diff --git a/qutebrowser/app.py b/qutebrowser/app.py index c6ba54e9e..a83063850 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -30,7 +30,7 @@ from base64 import b64encode from PyQt5.QtWidgets import QApplication, QDialog, QMessageBox from PyQt5.QtCore import (pyqtSlot, QTimer, QEventLoop, Qt, QStandardPaths, - qInstallMessageHandler, QObject) + qInstallMessageHandler, QObject, QUrl) import qutebrowser import qutebrowser.commands.utils as cmdutils @@ -42,6 +42,8 @@ import qutebrowser.network.proxy as proxy import qutebrowser.browser.quickmarks as quickmarks import qutebrowser.utils.log as log import qutebrowser.utils.version as version +import qutebrowser.utils.url as urlutils +import qutebrowser.utils.message as message from qutebrowser.network.networkmanager import NetworkManager from qutebrowser.config.config import ConfigManager from qutebrowser.keyinput.modeman import ModeManager @@ -55,7 +57,6 @@ from qutebrowser.config.iniparsers import ReadWriteConfigParser from qutebrowser.config.lineparser import LineConfigParser from qutebrowser.browser.cookies import CookieJar from qutebrowser.browser.downloads import DownloadManager -from qutebrowser.utils.message import MessageBridge from qutebrowser.utils.misc import (get_standard_dir, actute_warning, get_qt_args) from qutebrowser.utils.readline import ReadlineBridge @@ -83,7 +84,7 @@ class Application(QApplication): _timers: List of used QTimers so they don't get GCed. _shutting_down: True if we're currently shutting down. _quit_status: The current quitting status. - _opened_urls: List of opened URLs. + _opened_urls: List of opened URLs, string as passed to the application. _crashdlg: The crash dialog currently open. _crashlogfile: A file handler to the fatal crash logfile. """ @@ -220,7 +221,7 @@ class Application(QApplication): self.setOrganizationName("qutebrowser") self.setApplicationName("qutebrowser") self.setApplicationVersion(qutebrowser.__version__) - self.messagebridge = MessageBridge(self) + self.messagebridge = message.MessageBridge(self) self.rl_bridge = ReadlineBridge() def _handle_segfault(self): @@ -284,19 +285,30 @@ class Application(QApplication): self.processEvents(QEventLoop.ExcludeUserInputEvents | QEventLoop.ExcludeSocketNotifiers) - for e in self.args.command: - if e.startswith(':'): - log.init.debug("Startup cmd {}".format(e)) - self.commandmanager.run_safely_init(e.lstrip(':')) + for cmd in self.args.command: + if cmd.startswith(':'): + log.init.debug("Startup cmd {}".format(cmd)) + self.commandmanager.run_safely_init(cmd.lstrip(':')) else: - log.init.debug("Startup URL {}".format(e)) - self._opened_urls.append(e) - self.mainwindow.tabs.tabopen(e) + log.init.debug("Startup URL {}".format(cmd)) + self._opened_urls.append(cmd) + try: + url = urlutils.fuzzy_url(cmd) + except urlutils.SearchEngineError as e: + message.error("Error in startup argument '{}': {}".format( + cmd, e)) + else: + self.mainwindow.tabs.tabopen(url) if self.mainwindow.tabs.count() == 0: log.init.debug("Opening startpage") - for url in self.config.get('general', 'startpage'): - self.mainwindow.tabs.tabopen(url) + for urlstr in self.config.get('general', 'startpage'): + try: + url = urlutils.fuzzy_url(urlstr) + except urlutils.SearchEngineError as e: + message.error("Error when opening startpage: {}".format(e)) + else: + self.mainwindow.tabs.tabopen(url) def _python_hacks(self): """Get around some PyQt-oddities by evil hacks. @@ -548,9 +560,9 @@ class Application(QApplication): # if pages is None: # pages = [] # for tab in self.mainwindow.tabs.widgets: - # url = tab.url().toString() - # if url: - # pages.append(url) + # urlstr = tab.url().toString() + # if urlstr: + # pages.append(urlstr) # pythonpath = os.pathsep.join(sys.path) # os.environ['PYTHONPATH'] = pythonpath # argv = sys.argv[:] @@ -582,7 +594,7 @@ class Application(QApplication): except Exception as e: # pylint: disable=broad-except out = ': '.join([e.__class__.__name__, str(e)]) qutescheme.pyeval_output = out - self.mainwindow.tabs.cmd.openurl('qute:pyeval') + self.mainwindow.tabs.openurl(QUrl('qute:pyeval'), newtab=True) @pyqtSlot() def shutdown(self): diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 0105c2de0..7a5ef44a5 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -24,7 +24,7 @@ import subprocess from functools import partial from PyQt5.QtWidgets import QApplication -from PyQt5.QtCore import Qt +from PyQt5.QtCore import Qt, QUrl from PyQt5.QtGui import QClipboard from PyQt5.QtPrintSupport import QPrintDialog, QPrintPreviewDialog from PyQt5.QtWebKitWidgets import QWebInspector @@ -32,11 +32,11 @@ from PyQt5.QtWebKitWidgets import QWebInspector import qutebrowser.commands.utils as cmdutils import qutebrowser.config.config as config import qutebrowser.browser.hints as hints -import qutebrowser.utils.url as urlutils import qutebrowser.utils.message as message import qutebrowser.utils.webelem as webelem import qutebrowser.browser.quickmarks as quickmarks import qutebrowser.utils.log as log +import qutebrowser.utils.url as urlutils from qutebrowser.utils.misc import (check_overflow, shell_escape, check_print_compat) from qutebrowser.utils.editor import ExternalEditor @@ -152,14 +152,18 @@ class CommandDispatcher: @cmdutils.register(instance='mainwindow.tabs.cmd', name='open', split=False) - def openurl(self, url, count=None): + def openurl(self, urlstr, count=None): """Open a URL in the current/[count]th tab. Args: - url: The URL to open. + urlstr: The URL to open, as string. count: The tab index to open the URL in, or None. """ tab = self._tabs.cntwidget(count) + try: + url = urlutils.fuzzy_url(urlstr) + except urlutils.SearchEngineError as e: + raise CommandError(e) if tab is None: if count is None: # We want to open a URL in the current tab, but none exists @@ -352,15 +356,15 @@ class CommandDispatcher: Args: sel: True to use primary selection, False to use clipboard """ - url = urlutils.urlstring(self._tabs.currentWidget().url()) + urlstr = self._tabs.currentWidget().url().toString(QUrl.FullyEncoded) if sel: mode = QClipboard.Selection target = "primary selection" else: mode = QClipboard.Clipboard target = "clipboard" - log.misc.debug("Yanking to {}: '{}'".format(target, url)) - QApplication.clipboard().setText(url, mode) + log.misc.debug("Yanking to {}: '{}'".format(target, urlstr)) + QApplication.clipboard().setText(urlstr, mode) message.info("URL yanked to {}".format(target)) @cmdutils.register(instance='mainwindow.tabs.cmd') @@ -425,32 +429,40 @@ class CommandDispatcher: self._tabs.close_tab(tab) @cmdutils.register(instance='mainwindow.tabs.cmd', split=False) - def open_tab(self, url): + def open_tab(self, urlstr): """Open a new tab with a given url.""" + try: + url = urlutils.fuzzy_url(urlstr) + except urlutils.SearchEngineError as e: + raise CommandError(e) self._tabs.tabopen(url, background=False) @cmdutils.register(instance='mainwindow.tabs.cmd', split=False) - def open_tab_bg(self, url): + def open_tab_bg(self, urlstr): """Open a new tab in background.""" + try: + url = urlutils.fuzzy_url(urlstr) + except urlutils.SearchEngineError as e: + raise CommandError(e) self._tabs.tabopen(url, background=True) @cmdutils.register(instance='mainwindow.tabs.cmd', hide=True) def open_tab_cur(self): """Set the statusbar to :tabopen and the current URL.""" - url = urlutils.urlstring(self._tabs.currentWidget().url()) - message.set_cmd_text(':open-tab ' + url) + urlstr = self._tabs.currentWidget().url().toString() + message.set_cmd_text(':open-tab ' + urlstr) @cmdutils.register(instance='mainwindow.tabs.cmd', hide=True) def open_cur(self): """Set the statusbar to :open and the current URL.""" - url = urlutils.urlstring(self._tabs.currentWidget().url()) - message.set_cmd_text(':open ' + url) + urlstr = self._tabs.currentWidget().url().toString() + message.set_cmd_text(':open ' + urlstr) @cmdutils.register(instance='mainwindow.tabs.cmd', hide=True) def open_tab_bg_cur(self): """Set the statusbar to :tabopen-bg and the current URL.""" - url = urlutils.urlstring(self._tabs.currentWidget().url()) - message.set_cmd_text(':open-tab-bg ' + url) + urlstr = self._tabs.currentWidget().url().toString() + message.set_cmd_text(':open-tab-bg ' + urlstr) @cmdutils.register(instance='mainwindow.tabs.cmd') def undo(self): @@ -499,10 +511,14 @@ class CommandDispatcher: tab: True to open in a new tab. """ mode = QClipboard.Selection if sel else QClipboard.Clipboard - url = QApplication.clipboard().text(mode) - if not url: + text = QApplication.clipboard().text(mode) + if not text: raise CommandError("Clipboard is empty.") - log.misc.debug("Clipboard contained: '{}'".format(url)) + log.misc.debug("Clipboard contained: '{}'".format(text)) + try: + url = urlutils.fuzzy_url(text) + except urlutils.SearchEngineError as e: + raise CommandError(e) if tab: self._tabs.tabopen(url) else: @@ -591,8 +607,8 @@ class CommandDispatcher: Args: cmd: The command to execute. """ - url = urlutils.urlstring(self._tabs.currentWidget().url()) - cmd = cmd.replace('{}', shell_escape(url)) + urlstr = self._tabs.currentWidget().url().toString(QUrl.FullyEncoded) + cmd = cmd.replace('{}', shell_escape(urlstr)) log.procs.debug("Executing: {}".format(cmd)) subprocess.Popen(cmd, shell=True) @@ -604,10 +620,10 @@ class CommandDispatcher: @cmdutils.register(instance='mainwindow.tabs.cmd') def run_userscript(self, cmd, *args): """Run an userscript given as argument.""" - url = urlutils.urlstring(self._tabs.currentWidget().url()) + urlstr = self._tabs.currentWidget().url().toString(QUrl.FullyEncoded) runner = UserscriptRunner(self._tabs) runner.got_cmd.connect(self._tabs.got_cmd) - runner.run(cmd, *args, env={'QUTE_URL': url}) + runner.run(cmd, *args, env={'QUTE_URL': urlstr}) self._userscript_runners.append(runner) @cmdutils.register(instance='mainwindow.tabs.cmd') @@ -656,8 +672,7 @@ class CommandDispatcher: @cmdutils.register(instance='mainwindow.tabs.cmd') def download_page(self): """Download the current page.""" - widget = self._tabs.currentWidget() - url = urlutils.urlstring(widget.url()) + url = self._tabs.currentWidget().url() QApplication.instance().downloadmanager.get(url) @cmdutils.register(instance='mainwindow.tabs.cmd', modes=['insert'], diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index 627050ad8..2c5d5f498 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -31,7 +31,6 @@ from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply import qutebrowser.config.config as config import qutebrowser.utils.message as message -import qutebrowser.utils.url as urlutils import qutebrowser.commands.utils as cmdutils from qutebrowser.utils.log import downloads as logger from qutebrowser.utils.log import fix_rfc2622 @@ -360,13 +359,13 @@ class DownloadManager(QObject): filename = 'qutebrowser-download' return os.path.basename(filename) - def get(self, link): + def get(self, url): """Start a download with a link URL. Args: - link: The link URL as a string. + url: The URL to get, as QUrl """ - req = QNetworkRequest(urlutils.qurl(link)) + req = QNetworkRequest(url) reply = QCoreApplication.instance().networkmanager.get(req) self.fetch(reply) diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index 6370bede2..28583f1a1 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -22,14 +22,13 @@ import math from collections import namedtuple -from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QEvent, Qt +from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QEvent, Qt, QUrl from PyQt5.QtGui import QMouseEvent, QClipboard from PyQt5.QtWidgets import QApplication import qutebrowser.config.config as config import qutebrowser.keyinput.modeman as modeman import qutebrowser.utils.message as message -import qutebrowser.utils.url as urlutils import qutebrowser.utils.webelem as webelem from qutebrowser.commands.exceptions import CommandError from qutebrowser.utils.usertypes import enum @@ -294,23 +293,24 @@ class HintManager(QObject): for evt in events: self.mouse_event.emit(evt) - def _yank(self, link): + def _yank(self, url): """Yank an element to the clipboard or primary selection. Args: - link: The URL to open. + url: The URL to open as a QURL. """ sel = self._context.target == Target.yank_primary mode = QClipboard.Selection if sel else QClipboard.Clipboard - QApplication.clipboard().setText(urlutils.urlstring(link), mode) + urlstr = url.toString(QUrl.FullyEncoded) + QApplication.clipboard().setText(urlstr, mode) message.info("URL yanked to {}".format("primary selection" if sel else "clipboard")) - def _preset_cmd_text(self, link): + def _preset_cmd_text(self, url): """Preset a commandline text based on a hint URL. Args: - link: The link to open. + url: The URL to open as a QUrl. """ commands = { Target.cmd: 'open', @@ -318,36 +318,36 @@ class HintManager(QObject): Target.cmd_tab_bg: 'open-tab-bg', } message.set_cmd_text(':{} {}'.format(commands[self._context.target], - urlutils.urlstring(link))) + url.toString(QUrl.FullyEncoded))) - def _download(self, link): + def _download(self, url): """Download a hint URL. Args: - link: The link to download. + url: The URL to download, as a QUrl. """ - QApplication.instance().downloadmanager.get(link) + QApplication.instance().downloadmanager.get(url) - def _resolve_link(self, elem, baseurl=None): - """Resolve a link and check if we want to keep it. + def _resolve_url(self, elem, baseurl=None): + """Resolve a URL and check if we want to keep it. Args: - elem: The QWebElement to get the link of. + elem: The QWebElement to get the URL of. baseurl: The baseurl of the current tab (overrides baseurl from self._context). Return: - A QUrl with the absolute link, or None. + A QUrl with the absolute URL, or None. """ - link = elem.attribute('href') - if not link: + text = elem.attribute('href') + if not text: return None if baseurl is None: baseurl = self._context.baseurl - link = urlutils.qurl(link) - if link.isRelative(): - link = baseurl.resolved(link) - return link + url = QUrl(text) + if url.isRelative(): + url = baseurl.resolved(url) + return url def _find_prevnext(self, frame, prev=False): """Find a prev/next element in frame.""" @@ -399,11 +399,11 @@ class HintManager(QObject): if elem is None: raise CommandError("No {} links found!".format( "prev" if prev else "forward")) - link = self._resolve_link(elem, baseurl) - if link is None: + url = self._resolve_url(elem, baseurl) + if url is None: raise CommandError("No {} links found!".format( "prev" if prev else "forward")) - self.openurl.emit(link, newtab) + self.openurl.emit(url, newtab) def start(self, mainframe, baseurl, group=webelem.Group.all, target=Target.normal): @@ -508,8 +508,8 @@ class HintManager(QObject): Target.tab_bg: self._click, Target.rapid: self._click, } - # Handlers which take a link string - link_handlers = { + # Handlers which take a QUrl + url_handlers = { Target.yank: self._yank, Target.yank_primary: self._yank, Target.cmd: self._preset_cmd_text, @@ -520,11 +520,11 @@ class HintManager(QObject): elem = self._context.elems[keystr].elem if self._context.target in elem_handlers: elem_handlers[self._context.target](elem) - elif self._context.target in link_handlers: - link = self._resolve_link(elem) - if link is None: + elif self._context.target in url_handlers: + url = self._resolve_url(elem) + if url is None: raise CommandError("No suitable link found for this element.") - link_handlers[self._context.target](link) + url_handlers[self._context.target](url) else: raise ValueError("No suitable handler found!") if self._context.target != Target.rapid: diff --git a/qutebrowser/browser/quickmarks.py b/qutebrowser/browser/quickmarks.py index 2368ba1bb..c0b2f98c9 100644 --- a/qutebrowser/browser/quickmarks.py +++ b/qutebrowser/browser/quickmarks.py @@ -22,14 +22,13 @@ from functools import partial from collections import OrderedDict -from PyQt5.QtCore import QStandardPaths +from PyQt5.QtCore import QStandardPaths, QUrl import qutebrowser.utils.message as message import qutebrowser.commands.utils as cmdutils from qutebrowser.utils.usertypes import PromptMode from qutebrowser.config.lineparser import LineConfigParser from qutebrowser.utils.misc import get_standard_dir -from qutebrowser.utils.url import urlstring from qutebrowser.commands.exceptions import CommandError @@ -54,9 +53,14 @@ def save(): def prompt_save(url): - """Prompt for a new quickmark name to be added and add it.""" + """Prompt for a new quickmark name to be added and add it. + + Args: + url: The quickmark url as a QUrl. + """ + urlstr = url.toString(QUrl.FullyEncoded) message.question("Add quickmark:", PromptMode.text, - partial(quickmark_add, url)) + partial(quickmark_add, urlstr)) @cmdutils.register() @@ -64,7 +68,7 @@ def quickmark_add(url, name): """Add a new quickmark. Args: - url: The url to add as quickmark. + url: The url to add as quickmark, as QUrl. name: The name for the new quickmark. """ if not name: @@ -74,7 +78,7 @@ def quickmark_add(url, name): def set_mark(): """Really set the quickmark.""" - marks[name] = urlstring(url) + marks[name] = url if name in marks: message.confirm_action("Override existing quickmark?", set_mark, diff --git a/qutebrowser/browser/webpage.py b/qutebrowser/browser/webpage.py index c5c924ad8..5d61d2fee 100644 --- a/qutebrowser/browser/webpage.py +++ b/qutebrowser/browser/webpage.py @@ -28,7 +28,6 @@ from PyQt5.QtPrintSupport import QPrintDialog from PyQt5.QtWebKitWidgets import QWebPage import qutebrowser.utils.message as message -import qutebrowser.utils.url as urlutils import qutebrowser.config.config as config import qutebrowser.utils.log as log from qutebrowser.utils.misc import read_file, check_print_compat @@ -104,7 +103,7 @@ class BrowserPage(QWebPage): info = sip.cast(opt, QWebPage.ErrorPageExtensionOption) errpage = sip.cast(out, QWebPage.ErrorPageExtensionReturn) errpage.baseUrl = info.url - urlstr = urlutils.urlstring(info.url) + urlstr = info.url.toString() if (info.domain, info.error) in ignored_errors: log.webview.debug("Ignored error on {}: {} (error domain: {}, " "error code: {})".format( diff --git a/qutebrowser/network/qutescheme.py b/qutebrowser/network/qutescheme.py index 136b8f428..0356eaecd 100644 --- a/qutebrowser/network/qutescheme.py +++ b/qutebrowser/network/qutescheme.py @@ -31,7 +31,6 @@ import qutebrowser.utils.log as log import qutebrowser.utils.version as version from qutebrowser.network.schemehandler import (SchemeHandler, SpecialNetworkReply) -from qutebrowser.utils.url import urlstring from qutebrowser.utils.misc import read_file @@ -70,17 +69,6 @@ class QuteSchemeHandler(SchemeHandler): """Scheme handler for qute: URLs.""" - def _transform_url(self, url): - """Transform a special URL to an QuteHandlers method name. - - Args: - url: The URL as string. - - Return: - The method name qute_* - """ - return url.replace('http://', '').replace('qute:', 'qute_') - def createRequest(self, _op, request, _outgoing_data): """Create a new request. @@ -92,10 +80,12 @@ class QuteSchemeHandler(SchemeHandler): Return: A QNetworkReply. """ - log.misc.debug("request: {}".format(request)) - url = urlstring(request.url()) + path = request.url().path() + # An url like "qute:foo" is split as "scheme:path", not "scheme:host". + log.misc.debug("url: {}, path: {}".format(request.url().toString(), + path)) try: - handler = getattr(QuteHandlers, self._transform_url(url)) + handler = getattr(QuteHandlers, path) except AttributeError: data = bytes() else: @@ -108,13 +98,13 @@ class QuteHandlers: """Handlers for qute:... pages.""" @classmethod - def qute_pyeval(cls): + def pyeval(cls): """Handler for qute:pyeval. Return HTML content as bytes.""" text = cgi.escape(pyeval_output) return _get_html('pyeval', '
{}
'.format(text)) @classmethod - def qute_version(cls): + def version(cls): """Handler for qute:version. Return HTML content as bytes.""" text = cgi.escape(version.version()) html = '

Version info

' @@ -125,7 +115,7 @@ class QuteHandlers: return _get_html('Version', html) @classmethod - def qute_log(cls): + def log(cls): """Handler for qute:log. Return HTML content as bytes.""" if log.ram_handler is None: text = "Log output was disabled." @@ -134,6 +124,6 @@ class QuteHandlers: return _get_html('log', '
{}
'.format(text)) @classmethod - def qute_gpl(cls): + def gpl(cls): """Handler for qute:gpl. Return HTML content as bytes.""" return read_file('html/COPYING.html').encode('ASCII') diff --git a/qutebrowser/test/utils/test_url.py b/qutebrowser/test/utils/test_url.py index df73de81f..e1f16183e 100644 --- a/qutebrowser/test/utils/test_url.py +++ b/qutebrowser/test/utils/test_url.py @@ -24,8 +24,6 @@ import unittest from unittest import TestCase -from PyQt5.QtCore import QUrl - import qutebrowser.utils.url as urlutils @@ -64,41 +62,6 @@ class ConfigStub: raise self.NoOptionError -class ConversionTests(TestCase): - - """Test conversions between QUrl and url string. - - Attributes: - URL: The URL to check conversion with. - """ - - URL = 'http://www.qutebrowser.org/' - - def test_qurl2qurl(self): - """Test converting a QUrl to a QUrl.""" - q = urlutils.qurl(QUrl(self.URL)) - self.assertIsInstance(q, QUrl) - self.assertFalse(q.isEmpty()) - - def test_str2qurl(self): - """Test converting a string to a QUrl.""" - q = urlutils.qurl(self.URL) - self.assertIsInstance(q, QUrl) - self.assertFalse(q.isEmpty()) - - def test_str2str(self): - """Test converting a string to a string.""" - s = urlutils.urlstring(self.URL) - self.assertIsInstance(s, str) - self.assertEqual(s, self.URL) - - def test_qurl2str(self): - """Test converting a QUrl to a string.""" - s = urlutils.urlstring(QUrl(self.URL)) - self.assertIsInstance(s, str) - self.assertEqual(s, self.URL) - - class SpecialURLTests(TestCase): """Test is_special_url. diff --git a/qutebrowser/utils/url.py b/qutebrowser/utils/url.py index d6bb03cbb..1dfb14e83 100644 --- a/qutebrowser/utils/url.py +++ b/qutebrowser/utils/url.py @@ -66,38 +66,34 @@ def _get_search_url(txt): return QUrl.fromUserInput(template.format(urllib.parse.quote(term))) -def _is_url_naive(url): +def _is_url_naive(urlstr): """Naive check if given URL is really a URL. Args: - url: The URL to check for. + urlstr: The URL to check for, as string. Return: True if the URL really is a URL, False otherwise. """ - protocols = ('http', 'https') - u = qurl(url) - urlstr = urlstring(url) - if isinstance(url, QUrl): - u = url - else: - u = QUrl.fromUserInput(url) - # We don't use u here because fromUserInput appends http:// automatically. - if any(urlstr.startswith(proto) for proto in protocols): + schemes = ('http', 'https') + url = QUrl.fromUserInput(urlstr) + # We don't use url here because fromUserInput appends http:// + # automatically. + if QUrl(urlstr).scheme() in schemes: return True - elif '.' in u.host(): + elif '.' in url.host(): return True - elif u.host() == 'localhost': + elif url.host() == 'localhost': return True else: return False def _is_url_dns(url): - """Check if a URL (QUrl) is really a URL via DNS. + """Check if a URL is really a URL via DNS. Args: - url: The URL to check for. + url: The URL to check for as QUrl, ideally via QUrl::fromUserInput. Return: True if the URL really is a URL, False otherwise. @@ -110,66 +106,41 @@ def _is_url_dns(url): return not info.error() -def qurl(url): - """Get a QUrl from a URL string. - - Args: - The URL as string or QUrl. - - Return: - The URL as string. - """ - return url if isinstance(url, QUrl) else QUrl(url) - - -def urlstring(url): - """Get an QUrl as string. - - Args: - qurl: URL as string or QUrl. - - Return: - The URL as string - """ - return url.toString() if isinstance(url, QUrl) else url - - -def fuzzy_url(url): +def fuzzy_url(urlstr): """Get a QUrl based on an user input which is URL or search term. Args: - url: URL to load as QUrl or string. + urlstr: URL to load as a string. Return: A target QUrl to a searchpage or the original URL. """ - urlstr = urlstring(url) if is_url(urlstr): # probably an address logger.debug("URL is a fuzzy address") - newurl = QUrl.fromUserInput(urlstr) + url = QUrl.fromUserInput(urlstr) else: # probably a search term logger.debug("URL is a fuzzy search term") try: - newurl = _get_search_url(urlstr) + url = _get_search_url(urlstr) except ValueError: # invalid search engine - newurl = QUrl.fromUserInput(urlstr) + url = QUrl.fromUserInput(urlstr) logger.debug("Converting fuzzy term {} to URL -> {}".format( - urlstr, urlstring(newurl))) - return newurl + urlstr, url.toString())) + return url def is_special_url(url): """Return True if url is an about:... or other special URL.""" special_schemes = ('about', 'qute', 'file') - return qurl(url).scheme() in special_schemes + return QUrl(url).scheme() in special_schemes -def is_url(url): +def is_url(urlstr): """Check if url seems to be a valid URL. Args: - url: The URL as QUrl or string. + urlstr: The URL as string. Return: True if it is a valid URL, False otherwise. @@ -177,8 +148,6 @@ def is_url(url): Raise: ValueError if the autosearch config value is invalid. """ - urlstr = urlstring(url) - autosearch = config.get('general', 'auto-search') logger.debug("Checking if '{}' is a URL (autosearch={}).".format( @@ -192,19 +161,21 @@ def is_url(url): # A URL will never contain a space logger.debug("Contains space -> no URL") return False - elif is_special_url(url): + elif is_special_url(QUrl(urlstr)): # Special URLs are always URLs, even with autosearch=False logger.debug("Is an special URL.") return True - elif os.path.exists(url): + elif os.path.exists(urlstr): # local file return True elif autosearch == 'dns': logger.debug("Checking via DNS") + # We want to use fromUserInput here, as the user might enter "foo.de" + # and that should be treated as URL here. return _is_url_dns(QUrl.fromUserInput(urlstr)) elif autosearch == 'naive': logger.debug("Checking via naive check") - return _is_url_naive(url) + return _is_url_naive(urlstr) else: raise ValueError("Invalid autosearch value") diff --git a/qutebrowser/utils/webelem.py b/qutebrowser/utils/webelem.py index 7c475d7f1..0894aec90 100644 --- a/qutebrowser/utils/webelem.py +++ b/qutebrowser/utils/webelem.py @@ -27,10 +27,9 @@ Module attributes: without "href". """ -from PyQt5.QtCore import QRect +from PyQt5.QtCore import QRect, QUrl from PyQt5.QtWebKit import QWebElement -import qutebrowser.utils.url as urlutils from qutebrowser.utils.usertypes import enum @@ -57,7 +56,7 @@ SELECTORS[Group.editable_focused] = ', '.join( FILTERS = { Group.links: (lambda e: e.hasAttribute('href') and - urlutils.qurl(e.attribute('href')).scheme() != 'javascript'), + QUrl(e.attribute('href')).scheme() != 'javascript'), } diff --git a/qutebrowser/widgets/tabbedbrowser.py b/qutebrowser/widgets/tabbedbrowser.py index fcbb701a0..b185ac50d 100644 --- a/qutebrowser/widgets/tabbedbrowser.py +++ b/qutebrowser/widgets/tabbedbrowser.py @@ -24,7 +24,6 @@ from functools import partial from PyQt5.QtWidgets import QSizePolicy from PyQt5.QtCore import pyqtSignal, pyqtSlot, QSize -import qutebrowser.utils.url as urlutils import qutebrowser.config.config as config import qutebrowser.commands.utils as cmdutils import qutebrowser.keyinput.modeman as modeman @@ -160,7 +159,7 @@ class TabbedBrowser(TabWidget): self._filter.create(self.cur_load_status_changed)) # hintmanager tab.hintmanager.hint_strings_updated.connect(self.hint_strings_updated) - tab.hintmanager.openurl.connect(self.cmd.openurl) + tab.hintmanager.openurl.connect(self.openurl) # downloads tab.page().unsupportedContent.connect(self.start_download) tab.page().start_download.connect(self.start_download) @@ -244,7 +243,7 @@ class TabbedBrowser(TabWidget): """Open a URL, used as a slot. Args: - url: The URL to open. + url: The URL to open as QUrl. newtab: True to open URL in a new tab, False otherwise. """ if newtab: @@ -262,7 +261,7 @@ class TabbedBrowser(TabWidget): """Close a tab with a widget given.""" self.close_tab(widget) - @pyqtSlot(str, bool) + @pyqtSlot('QUrl', bool) def tabopen(self, url=None, background=None): """Open a new tab with a given URL. @@ -270,7 +269,7 @@ class TabbedBrowser(TabWidget): Also connect all the signals we need to _filter_signals. Args: - url: The URL to open. + url: The URL to open as QUrl or None for an empty tab. background: Whether to open the tab in the background. if None, the background-tabs setting decides. @@ -283,7 +282,6 @@ class TabbedBrowser(TabWidget): self._tabs.append(tab) self.addTab(tab, "") if url is not None: - url = urlutils.qurl(url) tab.openurl(url) if background is None: background = config.get('general', 'background-tabs') diff --git a/qutebrowser/widgets/webview.py b/qutebrowser/widgets/webview.py index aac8b777b..8b16f69c9 100644 --- a/qutebrowser/widgets/webview.py +++ b/qutebrowser/widgets/webview.py @@ -21,12 +21,11 @@ import functools -from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt +from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QUrl from PyQt5.QtWidgets import QApplication from PyQt5.QtWebKit import QWebSettings from PyQt5.QtWebKitWidgets import QWebView, QWebPage -import qutebrowser.utils.url as urlutils import qutebrowser.config.config as config import qutebrowser.keyinput.modeman as modeman import qutebrowser.utils.message as message @@ -122,8 +121,7 @@ class WebView(QWebView): # FIXME find some way to hide scrollbars without setScrollBarPolicy def __repr__(self): - return "WebView(url='{}')".format( - elide(urlutils.urlstring(self.url()), 50)) + return "WebView(url='{}')".format(elide(self.url().toString(), 50)) @property def load_status(self): @@ -284,7 +282,7 @@ class WebView(QWebView): """Open a URL in the browser. Args: - url: The URL to load, as string or QUrl. + url: The URL to load as QUrl Return: Return status of self.load @@ -292,14 +290,11 @@ class WebView(QWebView): Emit: titleChanged """ - try: - u = urlutils.fuzzy_url(url) - except urlutils.SearchEngineError as e: - raise CommandError(e) - log.webview.debug("New title: {}".format(urlutils.urlstring(u))) - self.titleChanged.emit(urlutils.urlstring(u)) - self.url_text = urlutils.urlstring(u) - return self.load(u) + urlstr = url.toString() + log.webview.debug("New title: {}".format(urlstr)) + self.titleChanged.emit(urlstr) + self.url_text = urlstr + return self.load(url) def zoom_perc(self, perc, fuzzyval=True): """Zoom to a given zoom percentage. @@ -381,18 +376,19 @@ class WebView(QWebView): @pyqtSlot('QUrl') def on_url_changed(self, url): """Update url_text when URL has changed.""" - self.url_text = urlutils.urlstring(url) + self.url_text = url.toString() @pyqtSlot(str) - def on_link_clicked(self, url): + def on_link_clicked(self, urlstr): """Handle a link. Called from the linkClicked signal. Checks if it should open it in a tab (middle-click or control) or not, and does so. Args: - url: The URL to handle, as string or QUrl. + urlstr: The URL to handle, as string. """ + url = QUrl(urlstr) if self._open_target == Target.tab: self.tabbedbrowser.tabopen(url, False) elif self._open_target == Target.tab_bg: