From 8d15bbdded8eece4c90eed6fe9a08fec02d37e7a Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 24 May 2015 21:00:46 +0200 Subject: [PATCH 01/70] utils.version: Add SIP line on ImportError. --- qutebrowser/utils/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/utils/version.py b/qutebrowser/utils/version.py index 6823685d7..827762af4 100644 --- a/qutebrowser/utils/version.py +++ b/qutebrowser/utils/version.py @@ -130,7 +130,7 @@ def _module_versions(): try: import sipconfig # pylint: disable=import-error,unused-variable except ImportError: - pass + lines.append('SIP: ?') else: try: lines.append('SIP: {}'.format( From 120d2e12b058659075ab11536d96a981682a09fa Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 25 May 2015 01:21:57 +0200 Subject: [PATCH 02/70] Improve QtValueError wording for ensure_not_null. --- qutebrowser/utils/qtutils.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index 939e1ed81..f175dc202 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -131,7 +131,7 @@ def ensure_valid(obj): def ensure_not_null(obj): """Ensure a Qt object with an .isNull() method is not null.""" if obj.isNull(): - raise QtValueError(obj) + raise QtValueError(obj, null=True) def check_qdatastream(stream): @@ -322,12 +322,15 @@ class QtValueError(ValueError): """Exception which gets raised by ensure_valid.""" - def __init__(self, obj): + def __init__(self, obj, null=False): try: self.reason = obj.errorString() except AttributeError: self.reason = None - err = "{} is not valid".format(obj) + if null: + err = "{} is null".format(obj) + else: + err = "{} is not valid".format(obj) if self.reason: err += ": {}".format(self.reason) super().__init__(err) From 0f13d9325b59ff7ed60b564e30532f8bce7b33a2 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 25 May 2015 01:26:52 +0200 Subject: [PATCH 03/70] Don't use parametrization for deprecated keys. This showed up as 2400 tests for what basically is one. --- tests/config/test_config.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/tests/config/test_config.py b/tests/config/test_config.py index 123b2a412..d5fab2ed1 100644 --- a/tests/config/test_config.py +++ b/tests/config/test_config.py @@ -157,14 +157,6 @@ class TestConfigParser: self.cfg.get('general', 'bar') # pylint: disable=bad-config-call -def keyconfig_deprecated_test_cases(): - """Generator yielding test cases (command, rgx) for TestKeyConfigParser.""" - for sect in configdata.KEY_DATA.values(): - for command in sect: - for rgx, _repl in configdata.CHANGED_KEY_COMMANDS: - yield (command, rgx) - - class TestKeyConfigParser: """Test config.parsers.keyconf.KeyConfigParser.""" @@ -185,10 +177,13 @@ class TestKeyConfigParser: with pytest.raises(keyconf.KeyConfigError): kcp._read_command(cmdline_test.cmd) - @pytest.mark.parametrize('command, rgx', keyconfig_deprecated_test_cases()) - def test_default_config_no_deprecated(self, command, rgx): + @pytest.mark.parametrize('rgx', [rgx for rgx, _repl + in configdata.CHANGED_KEY_COMMANDS]) + def test_default_config_no_deprecated(self, rgx): """Make sure the default config contains no deprecated commands.""" - assert rgx.match(command) is None + for sect in configdata.KEY_DATA.values(): + for command in sect: + assert rgx.match(command) is None @pytest.mark.parametrize( 'old, new_expected', From 6d879bbca32c51ba501400826179dac6958a29ba Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 25 May 2015 01:38:17 +0200 Subject: [PATCH 04/70] Exclude resources.py from coverage. --- .coveragerc | 1 + 1 file changed, 1 insertion(+) diff --git a/.coveragerc b/.coveragerc index ff714c43d..16bebb0cc 100644 --- a/.coveragerc +++ b/.coveragerc @@ -3,6 +3,7 @@ branch = true omit = qutebrowser/__main__.py */__init__.py + qutebrowser/resources.py [report] exclude_lines = From a345b02729034e39f2b245592510b17307e4e1df Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 25 May 2015 11:28:50 +0200 Subject: [PATCH 05/70] Fix exception when downloading links without name. We also set a default name to prevent "is a directory" errors. This is a regression introduced in 8f33fcfc52cf598d0aa11a347992c87010d3e37a. Fixes #682. --- CHANGELOG.asciidoc | 1 + qutebrowser/browser/downloads.py | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index c18927953..0af6c0d0f 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -73,6 +73,7 @@ Fixed - Various fixes for deprecated key bindings and auto-migrations. - Workaround for qutebrowser not starting when there are NUL-bytes in the history (because of a currently unknown bug) - Fixed handling of keybindings containing Ctrl/Meta on OS X. +- Fixed crash when downloading an URL without filename (e.g. magnet links) via "Save as...". https://github.com/The-Compiler/qutebrowser/releases/tag/v0.2.1[v0.2.1] ----------------------------------------------------------------------- diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index ab055cbf4..790459f6a 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -686,8 +686,11 @@ class DownloadManager(QAbstractListModel): if fileobj is not None or filename is not None: return self.fetch_request(request, page, fileobj, filename, auto_remove, suggested_fn) - encoding = sys.getfilesystemencoding() - suggested_fn = utils.force_encoding(suggested_fn, encoding) + if suggested_fn is None: + suggested_fn = 'qutebrowser-download' + else: + encoding = sys.getfilesystemencoding() + suggested_fn = utils.force_encoding(suggested_fn, encoding) q = self._prepare_question() q.default = _path_suggestion(suggested_fn) message_bridge = objreg.get('message-bridge', scope='window', From 45dea54e3c2cacbd887ce4e0a006d92afd740e53 Mon Sep 17 00:00:00 2001 From: Tobias Patzl Date: Mon, 25 May 2015 15:23:14 +0200 Subject: [PATCH 06/70] Add setting to disable mousewheel tab switching. See #374. --- doc/help/settings.asciidoc | 12 ++++++++++++ qutebrowser/config/configdata.py | 4 ++++ qutebrowser/mainwindow/tabwidget.py | 11 +++++++++++ 3 files changed, 27 insertions(+) diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index 46539c3b7..d3c571aa3 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -111,6 +111,7 @@ |<>|Spacing between tab edge and indicator. |<>|Whether to open windows instead of tabs. |<>|The format to use for the tab title. The following placeholders are defined: +|<>|Switch between tabs using the mouse wheel. |============== .Quick reference for section ``storage'' @@ -1031,6 +1032,17 @@ The format to use for the tab title. The following placeholders are defined: Default: +pass:[{index}: {title}]+ +[[tabs-mousewheel-tab-switching]] +=== mousewheel-tab-switching +Switch between tabs using the mouse wheel. + +Valid values: + + * +true+ + * +false+ + +Default: +pass:[true]+ + == storage Settings related to cache and storage. diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index cb3a47be7..02b8c6008 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -522,6 +522,10 @@ def data(readonly=False): "* `{index}`: The index of this tab.\n" "* `{id}`: The internal tab ID of this tab."), + ('mousewheel-tab-switching', + SettingValue(typ.Bool(), 'true'), + "Switch between tabs using the mouse wheel."), + readonly=readonly )), diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py index df44ebbba..1ad97370e 100644 --- a/qutebrowser/mainwindow/tabwidget.py +++ b/qutebrowser/mainwindow/tabwidget.py @@ -480,6 +480,17 @@ class TabBar(QTabBar): new_idx = super().insertTab(idx, icon, '') self.set_page_title(new_idx, text) + def wheelEvent(self, event): + """Override wheelEvent to make the action configurable.""" + if config.get('tabs', 'mousewheel-tab-switching'): + super().wheelEvent(event) + else: + tabbed_browser = objreg.get('tabbed-browser', scope='window', + window=self._win_id) + focused_tab = tabbed_browser.currentWidget() + if focused_tab is not None: + focused_tab.wheelEvent(event) + class TabBarStyle(QCommonStyle): From 61519e63839b81ee1532c8021709534f6f49e9f3 Mon Sep 17 00:00:00 2001 From: Tobias Patzl Date: Mon, 25 May 2015 20:21:37 +0200 Subject: [PATCH 07/70] move part of the logic to `TabbedBrowser` --- qutebrowser/mainwindow/tabbedbrowser.py | 9 +++++++++ qutebrowser/mainwindow/tabwidget.py | 14 ++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/qutebrowser/mainwindow/tabbedbrowser.py b/qutebrowser/mainwindow/tabbedbrowser.py index c465c8ca4..7b3477018 100644 --- a/qutebrowser/mainwindow/tabbedbrowser.py +++ b/qutebrowser/mainwindow/tabbedbrowser.py @@ -577,3 +577,12 @@ class TabbedBrowser(tabwidget.TabWidget): """ super().resizeEvent(e) self.resized.emit(self.geometry()) + + def wheelEvent(self, e): + """Override wheelEvent of QWidget to forward it to the focused tab. + + Args: + e: The QWheelEvent + """ + if self._now_focused is not None: + self._now_focused.wheelEvent(e) diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py index 1ad97370e..bbbfdf045 100644 --- a/qutebrowser/mainwindow/tabwidget.py +++ b/qutebrowser/mainwindow/tabwidget.py @@ -480,16 +480,18 @@ class TabBar(QTabBar): new_idx = super().insertTab(idx, icon, '') self.set_page_title(new_idx, text) - def wheelEvent(self, event): - """Override wheelEvent to make the action configurable.""" + def wheelEvent(self, e): + """Override wheelEvent to make the action configurable. + + Args: + e: The QWheelEvent + """ if config.get('tabs', 'mousewheel-tab-switching'): - super().wheelEvent(event) + super().wheelEvent(e) else: tabbed_browser = objreg.get('tabbed-browser', scope='window', window=self._win_id) - focused_tab = tabbed_browser.currentWidget() - if focused_tab is not None: - focused_tab.wheelEvent(event) + tabbed_browser.wheelEvent(e) class TabBarStyle(QCommonStyle): From b858b6ac755ffc6633a24a1a85c7902ce78c1edc Mon Sep 17 00:00:00 2001 From: Tobias Patzl Date: Tue, 26 May 2015 10:24:32 +0200 Subject: [PATCH 08/70] call `e.ignore()` when the event is not handled --- qutebrowser/mainwindow/tabbedbrowser.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qutebrowser/mainwindow/tabbedbrowser.py b/qutebrowser/mainwindow/tabbedbrowser.py index 7b3477018..ba5a5c725 100644 --- a/qutebrowser/mainwindow/tabbedbrowser.py +++ b/qutebrowser/mainwindow/tabbedbrowser.py @@ -586,3 +586,5 @@ class TabbedBrowser(tabwidget.TabWidget): """ if self._now_focused is not None: self._now_focused.wheelEvent(e) + else: + e.ignore() From 6b98c48985fd9ef4c3c6b7095b60bdd69358dd20 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 26 May 2015 10:30:21 +0200 Subject: [PATCH 09/70] Regenerate authors. --- README.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/README.asciidoc b/README.asciidoc index 8742f11cb..ad7a95ff2 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -150,6 +150,7 @@ Contributors, sorted by the number of commits in descending order: * Error 800 * Brian Jackson * sbinix +* Tobias Patzl * Johannes Altmanninger * Samir Benmendil * Regina Hug From e300b2e30d0a275cd88ea4d0d2f462d40c3ef88f Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 26 May 2015 12:10:36 +0200 Subject: [PATCH 10/70] Update changelog. --- CHANGELOG.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 0af6c0d0f..2981578e6 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -32,6 +32,7 @@ Added - New arguments `--basedir` and `--temp-basedir` (intended for debugging) to set a different base directory for all data, which allows multiple invocations. - New argument `--no-err-windows` to suppress all error windows. - New visual/caret mode (bound to `v`) to select text by keyboard. +- New setting `tabs -> mousewheel-tab-switching` to control mousewheel behavior on the tab bar. Changed ~~~~~~~ From 27e82ce6c8a4b535babc4370fd958cd1dcd1cdb0 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 25 May 2015 15:27:29 +0200 Subject: [PATCH 11/70] Improve exception handling in qsavefile_open. Sometimes exceptions were shadowed with new exceptions because of the file flushing. --- qutebrowser/utils/qtutils.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index f175dc202..af2a27a74 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -180,7 +180,7 @@ def deserialize_stream(stream, obj): def savefile_open(filename, binary=False, encoding='utf-8'): """Context manager to easily use a QSaveFile.""" f = QSaveFile(filename) - new_f = None + cancelled = False try: ok = f.open(QIODevice.WriteOnly) if not ok: @@ -192,13 +192,15 @@ def savefile_open(filename, binary=False, encoding='utf-8'): yield new_f except: f.cancelWriting() + cancelled = True raise - finally: + else: if new_f is not None: new_f.flush() + finally: commit_ok = f.commit() - if not commit_ok: - raise OSError(f.errorString()) + if not commit_ok and not cancelled: + raise OSError("Commit failed!") @contextlib.contextmanager From 92abf4bdf877f12d334c1eee1ed9e4540f1215ea Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 26 May 2015 19:25:45 +0200 Subject: [PATCH 12/70] tox: Update pytest-html to 1.3.1. Upstream changelog: 1.3.1: Fix encoding issue in Python 3 1.3: Bump version number to 1.3 Simplify example in README Show extra content in report regardless of test result Support extra content in JSON format --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index cf1d596d6..9166f180c 100644 --- a/tox.ini +++ b/tox.ini @@ -24,7 +24,7 @@ deps = pytest-capturelog==0.7 pytest-qt==1.3.0 pytest-mock==0.5 - pytest-html==1.2 + pytest-html==1.3.1 # We don't use {[testenv:mkvenv]commands} here because that seems to be broken # on Ubuntu Trusty. commands = From e10da78a1a065385157ce6dbc5f6296a102fddc0 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 26 May 2015 08:06:21 +0200 Subject: [PATCH 13/70] urlutils: Remove some more dead code. --- qutebrowser/utils/urlutils.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/qutebrowser/utils/urlutils.py b/qutebrowser/utils/urlutils.py index 3ed82b0db..143e7cfc5 100644 --- a/qutebrowser/utils/urlutils.py +++ b/qutebrowser/utils/urlutils.py @@ -94,6 +94,8 @@ def _is_url_naive(urlstr): True if the URL really is a URL, False otherwise. """ url = qurl_from_user_input(urlstr) + assert url.isValid() + if not utils.raises(ValueError, ipaddress.ip_address, urlstr): # Valid IPv4/IPv6 address return True @@ -104,9 +106,7 @@ def _is_url_naive(urlstr): if not QHostAddress(urlstr).isNull(): return False - if not url.isValid(): - return False - elif '.' in url.host(): + if '.' in url.host(): return True else: return False @@ -122,9 +122,7 @@ def _is_url_dns(urlstr): True if the URL really is a URL, False otherwise. """ url = qurl_from_user_input(urlstr) - if not url.isValid(): - log.url.debug("Invalid URL -> False") - return False + assert url.isValid() if (utils.raises(ValueError, ipaddress.ip_address, urlstr) and not QHostAddress(urlstr).isNull()): @@ -246,16 +244,13 @@ def is_url(urlstr): return False if not qurl_userinput.isValid(): + # This will also catch URLs containing spaces. return False if _has_explicit_scheme(qurl): # URLs with explicit schemes are always URLs log.url.debug("Contains explicit scheme") url = True - elif ' ' in urlstr: - # A URL will never contain a space - log.url.debug("Contains space -> no URL") - url = False elif qurl_userinput.host() in ('localhost', '127.0.0.1', '::1'): log.url.debug("Is localhost.") url = True @@ -274,7 +269,7 @@ def is_url(urlstr): else: raise ValueError("Invalid autosearch value") log.url.debug("url = {}".format(url)) - return url and qurl_userinput.isValid() + return url def qurl_from_user_input(urlstr): From fa69786b0f2f3e338f2ed552c89ecf0075ced20a Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 25 May 2015 20:42:45 +0200 Subject: [PATCH 14/70] PyQIODevice: Raise ValueError when closed. --- qutebrowser/utils/qtutils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index af2a27a74..4525a5c32 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -235,9 +235,9 @@ class PyQIODevice(io.BufferedIOBase): return self._dev.size() def _check_open(self): - """Check if the device is open, raise OSError if not.""" + """Check if the device is open, raise ValueError if not.""" if not self._dev.isOpen(): - raise OSError("IO operation on closed device!") + raise ValueError("IO operation on closed device!") def _check_random(self): """Check if the device supports random access, raise OSError if not.""" From ba9c782824ddf479dd5ed76594c0defa1ae88838 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 25 May 2015 20:43:28 +0200 Subject: [PATCH 15/70] PyQIODevice: First attempt at fixing read(). This was completely broken because one read overload doesn't exist in PyQt and apparently it was never tested... --- qutebrowser/utils/qtutils.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index 4525a5c32..841e94d87 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -311,13 +311,28 @@ class PyQIODevice(io.BufferedIOBase): raise OSError(self._dev.errorString()) return num - def read(self, size): + def read(self, size=-1): self._check_open() - buf = bytes() - num = self._dev.read(buf, size) - if num == -1: - raise OSError(self._dev.errorString()) - return num + self._check_readable() + if size == 0: + # Read no data + return b'' + elif size < 0: + # Read all data + if self._dev.bytesAvailable() > 0: + buf = self._dev.readAll() + if not buf: + raise OSError(self._dev.errorString()) + else: + return b'' + else: + if self._dev.bytesAvailable() > 0: + buf = self._dev.read(size) + if not buf: + raise OSError(self._dev.errorString()) + else: + return b'' + return buf class QtValueError(ValueError): From 35f0b26f4a5b3b17a70f918789f3dd7721d0b99d Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 25 May 2015 20:44:16 +0200 Subject: [PATCH 16/70] PyQIODevice: Remove readinto(). Our implementation was broken, and the BufferedIOBase mixin does a better job at doing this. --- qutebrowser/utils/qtutils.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index 841e94d87..98aee36de 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -300,10 +300,6 @@ class PyQIODevice(io.BufferedIOBase): def writable(self): return self._dev.isWritable() - def readinto(self, b): - self._check_open() - return self._dev.read(b, len(b)) - def write(self, b): self._check_open() num = self._dev.write(b) From b2d763f993d8b164b1ae0e72044a0c8073608492 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 25 May 2015 20:52:51 +0200 Subject: [PATCH 17/70] PyQIODevice: Check if device is readable/writable. --- qutebrowser/utils/qtutils.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index 98aee36de..f4b737162 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -244,6 +244,16 @@ class PyQIODevice(io.BufferedIOBase): if not self.seekable(): raise OSError("Random access not allowed!") + def _check_readable(self): + """Check if the device is readable, raise OSError if not.""" + if not self._dev.isReadable(): + raise OSError("Trying to read unreadable file!") + + def _check_writable(self): + """Check if the device is writable, raise OSError if not.""" + if not self.writable(): + raise OSError("Trying to write to unwritable file!") + def fileno(self): raise io.UnsupportedOperation @@ -285,6 +295,7 @@ class PyQIODevice(io.BufferedIOBase): def readline(self, size=-1): self._check_open() + self._check_readable() if size == -1: size = 0 return self._dev.readLine(size) @@ -302,6 +313,7 @@ class PyQIODevice(io.BufferedIOBase): def write(self, b): self._check_open() + self._check_writable() num = self._dev.write(b) if num == -1 or num < len(b): raise OSError(self._dev.errorString()) From 0788054dd321403195b1b8b32609a6f22204bce3 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 25 May 2015 20:53:44 +0200 Subject: [PATCH 18/70] PyQIODevice: Expose underlying device. --- qutebrowser/utils/qtutils.py | 50 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index f4b737162..f66dfa769 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -223,20 +223,20 @@ class PyQIODevice(io.BufferedIOBase): """Wrapper for a QIODevice which provides a python interface. Attributes: - _dev: The underlying QIODevice. + dev: The underlying QIODevice. """ # pylint: disable=missing-docstring def __init__(self, dev): - self._dev = dev + self.dev = dev def __len__(self): - return self._dev.size() + return self.dev.size() def _check_open(self): """Check if the device is open, raise ValueError if not.""" - if not self._dev.isOpen(): + if not self.dev.isOpen(): raise ValueError("IO operation on closed device!") def _check_random(self): @@ -246,7 +246,7 @@ class PyQIODevice(io.BufferedIOBase): def _check_readable(self): """Check if the device is readable, raise OSError if not.""" - if not self._dev.isReadable(): + if not self.dev.isReadable(): raise OSError("Trying to read unreadable file!") def _check_writable(self): @@ -261,62 +261,62 @@ class PyQIODevice(io.BufferedIOBase): self._check_open() self._check_random() if whence == io.SEEK_SET: - ok = self._dev.seek(offset) + ok = self.dev.seek(offset) elif whence == io.SEEK_CUR: - ok = self._dev.seek(self.tell() + offset) + ok = self.dev.seek(self.tell() + offset) elif whence == io.SEEK_END: - ok = self._dev.seek(len(self) + offset) + ok = self.dev.seek(len(self) + offset) else: raise io.UnsupportedOperation("whence = {} is not " "supported!".format(whence)) if not ok: - raise OSError(self._dev.errorString()) + raise OSError(self.dev.errorString()) def truncate(self, size=None): # pylint: disable=unused-argument raise io.UnsupportedOperation def close(self): - self._dev.close() + self.dev.close() @property def closed(self): - return not self._dev.isOpen() + return not self.dev.isOpen() def flush(self): self._check_open() - self._dev.waitForBytesWritten(-1) + self.dev.waitForBytesWritten(-1) def isatty(self): self._check_open() return False def readable(self): - return self._dev.isReadable() + return self.dev.isReadable() def readline(self, size=-1): self._check_open() self._check_readable() if size == -1: size = 0 - return self._dev.readLine(size) + return self.dev.readLine(size) def seekable(self): - return not self._dev.isSequential() + return not self.dev.isSequential() def tell(self): self._check_open() self._check_random() - return self._dev.pos() + return self.dev.pos() def writable(self): - return self._dev.isWritable() + return self.dev.isWritable() def write(self, b): self._check_open() self._check_writable() - num = self._dev.write(b) + num = self.dev.write(b) if num == -1 or num < len(b): - raise OSError(self._dev.errorString()) + raise OSError(self.dev.errorString()) return num def read(self, size=-1): @@ -327,17 +327,17 @@ class PyQIODevice(io.BufferedIOBase): return b'' elif size < 0: # Read all data - if self._dev.bytesAvailable() > 0: - buf = self._dev.readAll() + if self.dev.bytesAvailable() > 0: + buf = self.dev.readAll() if not buf: - raise OSError(self._dev.errorString()) + raise OSError(self.dev.errorString()) else: return b'' else: - if self._dev.bytesAvailable() > 0: - buf = self._dev.read(size) + if self.dev.bytesAvailable() > 0: + buf = self.dev.read(size) if not buf: - raise OSError(self._dev.errorString()) + raise OSError(self.dev.errorString()) else: return b'' return buf From 48de8b145bcb3bc17cf729c9857de09dbb7e94fb Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 26 May 2015 07:53:19 +0200 Subject: [PATCH 19/70] PyQIODevice: Properly fix read/readLine. --- qutebrowser/utils/qtutils.py | 44 ++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index f66dfa769..7a7050643 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -296,9 +296,25 @@ class PyQIODevice(io.BufferedIOBase): def readline(self, size=-1): self._check_open() self._check_readable() - if size == -1: - size = 0 - return self.dev.readLine(size) + + if size < 0: + qt_size = 0 # no maximum size + elif size == 0: + return QByteArray() + else: + qt_size = size + 1 # Qt also counts the NUL byte + + if self.dev.canReadLine(): + buf = self.dev.readLine(qt_size) + else: + if size < 0: + buf = self.dev.readAll() + else: + buf = self.dev.read(size) + + if buf is None: + raise OSError(self.dev.errorString()) + return buf def seekable(self): return not self.dev.isSequential() @@ -322,24 +338,12 @@ class PyQIODevice(io.BufferedIOBase): def read(self, size=-1): self._check_open() self._check_readable() - if size == 0: - # Read no data - return b'' - elif size < 0: - # Read all data - if self.dev.bytesAvailable() > 0: - buf = self.dev.readAll() - if not buf: - raise OSError(self.dev.errorString()) - else: - return b'' + if size < 0: + buf = self.dev.readAll() else: - if self.dev.bytesAvailable() > 0: - buf = self.dev.read(size) - if not buf: - raise OSError(self.dev.errorString()) - else: - return b'' + buf = self.dev.read(size) + if buf is None: + raise OSError(self.dev.errorString()) return buf From 6a26bc23abbfe81bcb68026a6c10d140cbd98d72 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 26 May 2015 07:52:41 +0200 Subject: [PATCH 20/70] PyQIODevice: Remove unneeded check. --- qutebrowser/utils/qtutils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index 7a7050643..e38025022 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -195,8 +195,7 @@ def savefile_open(filename, binary=False, encoding='utf-8'): cancelled = True raise else: - if new_f is not None: - new_f.flush() + new_f.flush() finally: commit_ok = f.commit() if not commit_ok and not cancelled: From 460308f388fe1d65b5df0964d7491a5981cfd1da Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 26 May 2015 07:52:59 +0200 Subject: [PATCH 21/70] PyQIODevice: Don't use errorString for failed seek. --- qutebrowser/utils/qtutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index e38025022..58772e46a 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -269,7 +269,7 @@ class PyQIODevice(io.BufferedIOBase): raise io.UnsupportedOperation("whence = {} is not " "supported!".format(whence)) if not ok: - raise OSError(self.dev.errorString()) + raise OSError("seek failed!") def truncate(self, size=None): # pylint: disable=unused-argument raise io.UnsupportedOperation From b8dd71a343205f7ee0e1ac82a4e538ef3f2aac00 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 26 May 2015 11:22:54 +0200 Subject: [PATCH 22/70] PyQIODevice: Add .open()/.close(). --- qutebrowser/utils/qtutils.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index 58772e46a..dc88b8c22 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -253,6 +253,22 @@ class PyQIODevice(io.BufferedIOBase): if not self.writable(): raise OSError("Trying to write to unwritable file!") + def open(self, mode): + """Open the underlying device and ensure opening succeeded. + + Raises OSError if opening failed. + + Args: + mode: QIODevice::OpenMode flags. + """ + ok = self.dev.open(mode) + if not ok: + raise OSError(self.dev.errorString()) + + def close(self): + """Close the underlying device.""" + self.dev.close() + def fileno(self): raise io.UnsupportedOperation @@ -274,9 +290,6 @@ class PyQIODevice(io.BufferedIOBase): def truncate(self, size=None): # pylint: disable=unused-argument raise io.UnsupportedOperation - def close(self): - self.dev.close() - @property def closed(self): return not self.dev.isOpen() From 6452c8f883c2531aea8fbb39e33228a58569ab76 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 26 May 2015 11:28:03 +0200 Subject: [PATCH 23/70] PyQIODevice: Add context manager support. --- qutebrowser/utils/qtutils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py index dc88b8c22..6573306ab 100644 --- a/qutebrowser/utils/qtutils.py +++ b/qutebrowser/utils/qtutils.py @@ -260,10 +260,15 @@ class PyQIODevice(io.BufferedIOBase): Args: mode: QIODevice::OpenMode flags. + + Return: + A contextlib.closing() object so this can be used as + contextmanager. """ ok = self.dev.open(mode) if not ok: raise OSError(self.dev.errorString()) + return contextlib.closing(self) def close(self): """Close the underlying device.""" From a969fe021d803a25b4ba788bfcc814af059d0b8d Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 27 May 2015 07:45:09 +0200 Subject: [PATCH 24/70] tox: Install requirements.txt for tests. --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 9166f180c..7c53068e7 100644 --- a/tox.ini +++ b/tox.ini @@ -19,6 +19,7 @@ usedevelop = true setenv = QT_QPA_PLATFORM_PLUGIN_PATH={envdir}/Lib/site-packages/PyQt5/plugins/platforms passenv = DISPLAY XAUTHORITY HOME deps = + -r{toxinidir}/requirements.txt py==1.4.27 pytest==2.7.1 pytest-capturelog==0.7 From 6f3fa9dca65b2fded0640868edcc64962af44cf5 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 27 May 2015 07:49:27 +0200 Subject: [PATCH 25/70] tox: Show more information when testing. --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 7c53068e7..467ba8dfd 100644 --- a/tox.ini +++ b/tox.ini @@ -30,7 +30,7 @@ deps = # on Ubuntu Trusty. commands = {envpython} scripts/link_pyqt.py --tox {envdir} - {envpython} -m py.test --strict {posargs} + {envpython} -m py.test --strict -rfEsw {posargs} [testenv:coverage] passenv = DISPLAY XAUTHORITY HOME @@ -41,7 +41,7 @@ deps = cov-core==1.15.0 commands = {[testenv:mkvenv]commands} - {envpython} -m py.test --strict --cov qutebrowser --cov-report term --cov-report html {posargs} + {envpython} -m py.test --strict -rfEswx -v --cov qutebrowser --cov-report term --cov-report html {posargs} [testenv:misc] commands = From ddf86600d10a802b90e450e03471acfb4233b4ca Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 27 May 2015 07:50:56 +0200 Subject: [PATCH 26/70] tests: Rename Testable* classes. This hides some pytest warnings as it tried to collect those classes. --- tests/misc/test_lineparser.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/misc/test_lineparser.py b/tests/misc/test_lineparser.py index 613ef3d65..17ae8415b 100644 --- a/tests/misc/test_lineparser.py +++ b/tests/misc/test_lineparser.py @@ -72,7 +72,7 @@ class LineParserWrapper: return True -class TestableAppendLineParser(LineParserWrapper, +class AppendLineParserTestable(LineParserWrapper, lineparsermod.AppendLineParser): """Wrapper over AppendLineParser to make it testable.""" @@ -80,14 +80,14 @@ class TestableAppendLineParser(LineParserWrapper, pass -class TestableLineParser(LineParserWrapper, lineparsermod.LineParser): +class LineParserTestable(LineParserWrapper, lineparsermod.LineParser): """Wrapper over LineParser to make it testable.""" pass -class TestableLimitLineParser(LineParserWrapper, +class LimitLineParserTestable(LineParserWrapper, lineparsermod.LimitLineParser): """Wrapper over LimitLineParser to make it testable.""" @@ -137,7 +137,7 @@ class TestAppendLineParser: @pytest.fixture def lineparser(self): """Fixture to get an AppendLineParser for tests.""" - lp = TestableAppendLineParser('this really', 'does not matter') + lp = AppendLineParserTestable('this really', 'does not matter') lp.new_data = self.BASE_DATA lp.save() return lp @@ -178,7 +178,7 @@ class TestAppendLineParser: def test_get_recent_none(self): """Test get_recent with no data.""" - linep = TestableAppendLineParser('this really', 'does not matter') + linep = AppendLineParserTestable('this really', 'does not matter') assert linep.get_recent() == [] def test_get_recent_little(self, lineparser): From 1b48dc8749eb2135ed269e881fc610acb790da52 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 27 May 2015 07:54:25 +0200 Subject: [PATCH 27/70] tox: Also provide sipconfig in link_pyqt.py. --- scripts/link_pyqt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/link_pyqt.py b/scripts/link_pyqt.py index ee1ebf2de..b6621126d 100644 --- a/scripts/link_pyqt.py +++ b/scripts/link_pyqt.py @@ -70,7 +70,7 @@ def link_pyqt(sys_path, venv_path): if not globbed_sip: raise Error("Did not find sip in {}!".format(sys_path)) - files = ['PyQt5'] + files = ['PyQt5', 'sipconfig.py'] files += [os.path.basename(e) for e in globbed_sip] for fn in files: source = os.path.join(sys_path, fn) From 2a269e9cd9b2865b3448f7a57a62c078f6cb22d8 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 27 May 2015 08:10:02 +0200 Subject: [PATCH 28/70] tox: Make sipconfig.py optional in link_pyqt.py. For some reason sipconfig.py doesn't exist at all on Windows... --- scripts/link_pyqt.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scripts/link_pyqt.py b/scripts/link_pyqt.py index b6621126d..7c8a77b58 100644 --- a/scripts/link_pyqt.py +++ b/scripts/link_pyqt.py @@ -70,13 +70,16 @@ def link_pyqt(sys_path, venv_path): if not globbed_sip: raise Error("Did not find sip in {}!".format(sys_path)) - files = ['PyQt5', 'sipconfig.py'] - files += [os.path.basename(e) for e in globbed_sip] - for fn in files: + files = [('PyQt5', True), ('sipconfig.py', False)] + files += [(os.path.basename(e), True) for e in globbed_sip] + for fn, required in files: source = os.path.join(sys_path, fn) dest = os.path.join(venv_path, fn) if not os.path.exists(source): - raise FileNotFoundError(source) + if required: + raise FileNotFoundError(source) + else: + continue if os.path.exists(dest): if os.path.isdir(dest) and not os.path.islink(dest): shutil.rmtree(dest) From 091353a7735eea5b118296612c820f5667c57707 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 27 May 2015 08:30:26 +0200 Subject: [PATCH 29/70] Mention :adblock-update in quickstart. --- doc/quickstart.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/quickstart.asciidoc b/doc/quickstart.asciidoc index ac3be3a9c..e0b22d378 100644 --- a/doc/quickstart.asciidoc +++ b/doc/quickstart.asciidoc @@ -11,6 +11,7 @@ What to do now * View the http://qutebrowser.org/img/cheatsheet-big.png[key binding cheatsheet] to make yourself familiar with the key bindings: + image:http://qutebrowser.org/img/cheatsheet-small.png["qutebrowser key binding cheatsheet",link="http://qutebrowser.org/img/cheatsheet-big.png"] +* Run `:adblock-update` to download adblock lists and activate adblocking. * If you just cloned the repository, you'll need to run `scripts/asciidoc2html.py` to generate the documentation. * Go to the link:qute://settings[settings page] to set up qutebrowser the way you want it. From 534dbfc4c2634d2f43a379a8f5abb8fb9af112a0 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 27 May 2015 08:51:24 +0200 Subject: [PATCH 30/70] tox: Update check-manifest to 0.25. Upstream changelog: Stop dynamic computation of install_requires in setup.py: this doesn't work well in the presence of the pip 7 wheel cache. Use PEP-426 environment markers instead (this means we now require setuptools version 0.7 or newer). --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 467ba8dfd..f39af4ee3 100644 --- a/tox.ini +++ b/tox.ini @@ -97,7 +97,7 @@ commands = [testenv:check-manifest] skip_install = true deps = - check-manifest==0.24 + check-manifest==0.25 commands = {[testenv:mkvenv]commands} {envdir}/bin/check-manifest --ignore 'qutebrowser/git-commit-id,qutebrowser/html/doc,qutebrowser/html/doc/*,*/__pycache__' From c76221c14e15e5339e06e793d98c964a494dbf72 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 29 May 2015 02:07:20 +0200 Subject: [PATCH 31/70] Use a specific 'qutebrowser_editor_' prefix for instead of 'tmp'. Why does this matter? In my vimrc I have this: " When using dwb ; assume markdown, and don't store in viminfo since these are " temporary files autocmd BufRead,BufNewFile /home/martin/.cache/dwb/edit* setlocal ft=markdown viminfo= I would like to do the same with qutebrowser, but this is not possible with a file name like '/tmp/tmpSJsgSG4' --- qutebrowser/misc/editor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qutebrowser/misc/editor.py b/qutebrowser/misc/editor.py index 81323bf5e..fc27b922c 100644 --- a/qutebrowser/misc/editor.py +++ b/qutebrowser/misc/editor.py @@ -122,7 +122,8 @@ class ExternalEditor(QObject): raise ValueError("Already editing a file!") self._text = text try: - self._oshandle, self._filename = tempfile.mkstemp(text=True) + self._oshandle, self._filename = tempfile.mkstemp(text=True, + prefix='qutebrowser_editor_') if text: encoding = config.get('general', 'editor-encoding') with open(self._filename, 'w', encoding=encoding) as f: From d20872d576482d15d632e06c79696b68c45c46fe Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 29 May 2015 14:49:52 +0200 Subject: [PATCH 32/70] Fix feedback from #690 --- misc/userscripts/qutebrowser_viewsource | 2 +- qutebrowser/app.py | 2 +- qutebrowser/misc/editor.py | 4 ++-- qutebrowser/utils/urlutils.py | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/misc/userscripts/qutebrowser_viewsource b/misc/userscripts/qutebrowser_viewsource index 0985297d7..a1e40c67d 100755 --- a/misc/userscripts/qutebrowser_viewsource +++ b/misc/userscripts/qutebrowser_viewsource @@ -27,6 +27,6 @@ path=/tmp/qutebrowser_$(mktemp XXXXXXXX).html curl "$QUTE_URL" > $path -urxvt -e vim "$path" +xterm -e vim "$path" rm "$path" diff --git a/qutebrowser/app.py b/qutebrowser/app.py index 64c277c9f..9b0ab3ba0 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -70,7 +70,7 @@ def run(args): sys.exit(usertypes.Exit.ok) if args.temp_basedir: - args.basedir = tempfile.mkdtemp() + args.basedir = tempfile.mkdtemp(prefix='qutebrowser-prefix-') quitter = Quitter(args) objreg.register('quitter', quitter) diff --git a/qutebrowser/misc/editor.py b/qutebrowser/misc/editor.py index fc27b922c..32e4100ca 100644 --- a/qutebrowser/misc/editor.py +++ b/qutebrowser/misc/editor.py @@ -122,8 +122,8 @@ class ExternalEditor(QObject): raise ValueError("Already editing a file!") self._text = text try: - self._oshandle, self._filename = tempfile.mkstemp(text=True, - prefix='qutebrowser_editor_') + self._oshandle, self._filename = tempfile.mkstemp( + text=True, prefix='qutebrowser-editor-') if text: encoding = config.get('general', 'editor-encoding') with open(self._filename, 'w', encoding=encoding) as f: diff --git a/qutebrowser/utils/urlutils.py b/qutebrowser/utils/urlutils.py index 143e7cfc5..22b84cf2b 100644 --- a/qutebrowser/utils/urlutils.py +++ b/qutebrowser/utils/urlutils.py @@ -166,6 +166,7 @@ def fuzzy_url(urlstr, cwd=None, relative=False, do_search=True): path = None stripped = urlstr.strip() + if path is not None and os.path.exists(path): log.url.debug("URL is a local file") url = QUrl.fromLocalFile(path) @@ -181,6 +182,7 @@ def fuzzy_url(urlstr, cwd=None, relative=False, do_search=True): url = qurl_from_user_input(stripped) log.url.debug("Converting fuzzy term {} to URL -> {}".format( urlstr, url.toDisplayString())) + if do_search and config.get('general', 'auto-search'): qtutils.ensure_valid(url) else: From 48735315f861f3051ee916baf48843625d0d600e Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 29 May 2015 16:52:54 +0200 Subject: [PATCH 33/70] docs: Fix typo. --- CONTRIBUTING.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.asciidoc b/CONTRIBUTING.asciidoc index cf185c3fe..7b0fe6087 100644 --- a/CONTRIBUTING.asciidoc +++ b/CONTRIBUTING.asciidoc @@ -86,7 +86,7 @@ Useful utilities Checkers ~~~~~~~~ -qutbebrowser uses http://tox.readthedocs.org/en/latest/[tox] to run its +qutebrowser uses http://tox.readthedocs.org/en/latest/[tox] to run its unittests and several linters/checkers. Currently, the following tools will be invoked when you run `tox`: From f7b517f3aadfa56eb9de78b7db1919a0a8676b42 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 29 May 2015 17:08:01 +0200 Subject: [PATCH 34/70] Revert some accidental changes >_< --- misc/userscripts/qutebrowser_viewsource | 2 +- qutebrowser/utils/urlutils.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/misc/userscripts/qutebrowser_viewsource b/misc/userscripts/qutebrowser_viewsource index a1e40c67d..0985297d7 100755 --- a/misc/userscripts/qutebrowser_viewsource +++ b/misc/userscripts/qutebrowser_viewsource @@ -27,6 +27,6 @@ path=/tmp/qutebrowser_$(mktemp XXXXXXXX).html curl "$QUTE_URL" > $path -xterm -e vim "$path" +urxvt -e vim "$path" rm "$path" diff --git a/qutebrowser/utils/urlutils.py b/qutebrowser/utils/urlutils.py index 22b84cf2b..143e7cfc5 100644 --- a/qutebrowser/utils/urlutils.py +++ b/qutebrowser/utils/urlutils.py @@ -166,7 +166,6 @@ def fuzzy_url(urlstr, cwd=None, relative=False, do_search=True): path = None stripped = urlstr.strip() - if path is not None and os.path.exists(path): log.url.debug("URL is a local file") url = QUrl.fromLocalFile(path) @@ -182,7 +181,6 @@ def fuzzy_url(urlstr, cwd=None, relative=False, do_search=True): url = qurl_from_user_input(stripped) log.url.debug("Converting fuzzy term {} to URL -> {}".format( urlstr, url.toDisplayString())) - if do_search and config.get('general', 'auto-search'): qtutils.ensure_valid(url) else: From c7dcaff025f98aa72d428ee0c3a7844e0498d001 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 29 May 2015 18:35:15 +0200 Subject: [PATCH 35/70] Add navigate option to scroll_page() So you can scroll down & navigate when you're at the bottom. To bind this to space: scroll-page 0 1 next Not sure if it's a good idea to bind this by default? May surprise some people... See #696 --- qutebrowser/browser/commands.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 0c01260d7..8c29ad317 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -643,14 +643,23 @@ class CommandDispatcher: @cmdutils.register(instance='command-dispatcher', hide=True, scope='window', count='count') - def scroll_page(self, x: {'type': float}, y: {'type': float}, count=1): + def scroll_page(self, x: {'type': float}, y: {'type': float}, + navigate=None, count=1): """Scroll the frame page-wise. Args: x: How many pages to scroll to the right. y: How many pages to scroll down. + navigate: :navigate to the next page on bottom count: multiplier """ + frame = self._current_widget().page().currentFrame() + if (navigate is not None and + frame.scrollPosition().y() >= + frame.scrollBarMaximum(Qt.Vertical)): + self.navigate(navigate) + return + mult_x = count * x mult_y = count * y if mult_y.is_integer(): @@ -663,7 +672,6 @@ class CommandDispatcher: mult_y = 0 if mult_x == 0 and mult_y == 0: return - frame = self._current_widget().page().currentFrame() size = frame.geometry() dx = mult_x * size.width() dy = mult_y * size.height() From c1dadeff6fb8f1d3f68db2e906acf0152be750af Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 29 May 2015 20:48:43 +0200 Subject: [PATCH 36/70] Fix silly mistake... --- qutebrowser/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/app.py b/qutebrowser/app.py index 9b0ab3ba0..d125d1d1a 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -70,7 +70,7 @@ def run(args): sys.exit(usertypes.Exit.ok) if args.temp_basedir: - args.basedir = tempfile.mkdtemp(prefix='qutebrowser-prefix-') + args.basedir = tempfile.mkdtemp(prefix='qutebrowser-basedir-') quitter = Quitter(args) objreg.register('quitter', quitter) From 8c80f99a32363ebc2b139e7c0074e4c165d992b3 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 29 May 2015 21:18:44 +0200 Subject: [PATCH 37/70] Improve navigate option to scroll_page() --- qutebrowser/browser/commands.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 8c29ad317..735deba47 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -643,21 +643,27 @@ class CommandDispatcher: @cmdutils.register(instance='command-dispatcher', hide=True, scope='window', count='count') - def scroll_page(self, x: {'type': float}, y: {'type': float}, - navigate=None, count=1): + def scroll_page(self, x: {'type': float}, y: {'type': float}, *, + top_navigate: {'type': ('prev', 'decrement')}=None, + bottom_navigate: {'type': ('next', 'increment')}=None, + count=1): """Scroll the frame page-wise. Args: x: How many pages to scroll to the right. y: How many pages to scroll down. - navigate: :navigate to the next page on bottom + bottom_navigate: :navigate to the next page on bottom + top_navigate: :navigate to the previous page on top count: multiplier """ frame = self._current_widget().page().currentFrame() - if (navigate is not None and + if (bottom_navigate is not None and frame.scrollPosition().y() >= frame.scrollBarMaximum(Qt.Vertical)): - self.navigate(navigate) + self.navigate(bottom_navigate) + return + elif top_navigate is not None and frame.scrollPosition().y() == 0: + self.navigate(top_navigate) return mult_x = count * x From 0d19d1bcf781b85e9003691fcab642a9e6da4140 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 29 May 2015 23:47:01 +0200 Subject: [PATCH 38/70] Regenerate authors --- README.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/README.asciidoc b/README.asciidoc index ad7a95ff2..aa94eef98 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -147,6 +147,7 @@ Contributors, sorted by the number of commits in descending order: * rikn00 * Patric Schmitz * Martin Zimmermann +* Martin Tournoij * Error 800 * Brian Jackson * sbinix From 9c99c22f1b4edee2d43efe2365beca34a275fbd9 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 29 May 2015 23:49:48 +0200 Subject: [PATCH 39/70] Fix issue #701 --- qutebrowser/browser/commands.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 735deba47..337823122 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -657,6 +657,9 @@ class CommandDispatcher: count: multiplier """ frame = self._current_widget().page().currentFrame() + if not frame.url().isValid() == '': # Issue 701 + return + if (bottom_navigate is not None and frame.scrollPosition().y() >= frame.scrollBarMaximum(Qt.Vertical)): From 70956aaeca3df4bf0c9842fe443202370f683ff8 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 29 May 2015 23:57:57 +0200 Subject: [PATCH 40/70] oops --- qutebrowser/browser/commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 337823122..5318bdc7d 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -657,7 +657,7 @@ class CommandDispatcher: count: multiplier """ frame = self._current_widget().page().currentFrame() - if not frame.url().isValid() == '': # Issue 701 + if not frame.url().isValid(): # Issue 701 return if (bottom_navigate is not None and From 6ca541d359b5d1d3cd088efc65683cce6bbb35cc Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 30 May 2015 10:37:25 -0400 Subject: [PATCH 41/70] Fixed issue #401. --- qutebrowser/browser/commands.py | 6 ++++++ qutebrowser/config/configdata.py | 1 + 2 files changed, 7 insertions(+) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 0c01260d7..9f836d36a 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -985,6 +985,12 @@ class CommandDispatcher: url = objreg.get('quickmark-manager').get(name) self._open(url, tab, bg, window) + @cmdutils.register(instance='command-dispatcher', name='select-follow', scope='window') + def select_follow(self): + """Follow the selected text.""" + widget = self._current_widget() + widget.page().currentFrame().evaluateJavaScript('window.getSelection().anchorNode.parentNode.click()') + @cmdutils.register(instance='command-dispatcher', name='inspector', scope='window') def toggle_inspector(self): diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index 02b8c6008..135e91e81 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -1239,6 +1239,7 @@ KEY_DATA = collections.OrderedDict([ ('stop', ['']), ('print', ['']), ('open qute:settings', ['Ss']), + ('select-follow', ['', '']), ])), ('insert', collections.OrderedDict([ From a56a14fb705bf77f35f0e360fc7b8159672c158a Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 30 May 2015 13:15:53 -0400 Subject: [PATCH 42/70] Added the possibility to open a selected link in a new tab. --- qutebrowser/browser/commands.py | 10 ++++++++-- qutebrowser/config/configdata.py | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 9f836d36a..bc3931a65 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -986,9 +986,15 @@ class CommandDispatcher: self._open(url, tab, bg, window) @cmdutils.register(instance='command-dispatcher', name='select-follow', scope='window') - def select_follow(self): - """Follow the selected text.""" + def select_follow(self, tab=False): + """Follow the selected text. + + Args: + tab: Load the selected link in a new tab. + """ widget = self._current_widget() + if tab: + widget.page().open_target = usertypes.ClickTarget.tab widget.page().currentFrame().evaluateJavaScript('window.getSelection().anchorNode.parentNode.click()') @cmdutils.register(instance='command-dispatcher', name='inspector', diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index 135e91e81..dec02b069 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -1239,7 +1239,8 @@ KEY_DATA = collections.OrderedDict([ ('stop', ['']), ('print', ['']), ('open qute:settings', ['Ss']), - ('select-follow', ['', '']), + ('select-follow', ['']), + ('select-follow -t', ['']), ])), ('insert', collections.OrderedDict([ From e48e063c0fb749d2b693f0c6324b08c8f1b490e6 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 30 May 2015 19:29:37 +0200 Subject: [PATCH 43/70] src2asciidoc.py: Improve exception handling. --- scripts/src2asciidoc.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/src2asciidoc.py b/scripts/src2asciidoc.py index d764b1c7e..31d82f6e8 100755 --- a/scripts/src2asciidoc.py +++ b/scripts/src2asciidoc.py @@ -184,7 +184,7 @@ def _get_command_doc_args(cmd, parser): yield "* +'{}'+: {}".format(name, parser.arg_descs[arg]) except KeyError as e: raise KeyError("No description for arg {} of command " - "'{}'!".format(e, cmd.name)) + "'{}'!".format(e, cmd.name)) from e if cmd.opt_args: yield "" @@ -193,9 +193,9 @@ def _get_command_doc_args(cmd, parser): try: yield '* +*{}*+, +*{}*+: {}'.format(short_flag, long_flag, parser.arg_descs[arg]) - except KeyError: + except KeyError as e: raise KeyError("No description for arg {} of command " - "'{}'!".format(e, cmd.name)) + "'{}'!".format(e, cmd.name)) from e def _get_command_doc_count(cmd, parser): @@ -213,9 +213,9 @@ def _get_command_doc_count(cmd, parser): yield "==== count" try: yield parser.arg_descs[cmd.count_arg] - except KeyError: + except KeyError as e: raise KeyError("No description for count arg {!r} of command " - "{!r}!".format(cmd.count_arg, cmd.name)) + "{!r}!".format(cmd.count_arg, cmd.name)) from e def _get_command_doc_notes(cmd): From b1dd64927806b39dae8fd644755b5d2a2ab0fd72 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 30 May 2015 19:30:08 +0200 Subject: [PATCH 44/70] Replace _ by - in command flag names. See #698. --- qutebrowser/commands/command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/commands/command.py b/qutebrowser/commands/command.py index 269c17e06..998c4a892 100644 --- a/qutebrowser/commands/command.py +++ b/qutebrowser/commands/command.py @@ -287,7 +287,7 @@ class Command: A list of args. """ args = [] - name = param.name.rstrip('_') + name = param.name.rstrip('_').replace('_', '-') shortname = annotation_info.flag or name[0] if len(shortname) != 1: raise ValueError("Flag '{}' of parameter {} (command {}) must be " From 989e3b7291f34ec7f560a1293124aab71ba9aa62 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 30 May 2015 13:56:36 -0400 Subject: [PATCH 45/70] Added a fallback for when JavaScript is disabled. --- qutebrowser/browser/commands.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index bc3931a65..17ef07196 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -25,7 +25,9 @@ import shlex import subprocess import posixpath import functools +from xml.etree import ElementTree +from PyQt5.QtWebKit import QWebSettings from PyQt5.QtWidgets import QApplication, QTabBar from PyQt5.QtCore import Qt, QUrl, QEvent from PyQt5.QtGui import QClipboard, QKeyEvent @@ -985,7 +987,8 @@ class CommandDispatcher: url = objreg.get('quickmark-manager').get(name) self._open(url, tab, bg, window) - @cmdutils.register(instance='command-dispatcher', name='select-follow', scope='window') + @cmdutils.register(instance='command-dispatcher', name='select-follow', + scope='window') def select_follow(self, tab=False): """Follow the selected text. @@ -993,9 +996,19 @@ class CommandDispatcher: tab: Load the selected link in a new tab. """ widget = self._current_widget() - if tab: - widget.page().open_target = usertypes.ClickTarget.tab - widget.page().currentFrame().evaluateJavaScript('window.getSelection().anchorNode.parentNode.click()') + if QWebSettings.globalSettings().testAttribute( + QWebSettings.JavascriptEnabled): + if tab: + widget.page().open_target = usertypes.ClickTarget.tab + widget.page().currentFrame().evaluateJavaScript( + 'window.getSelection().anchorNode.parentNode.click()') + else: + selected_element = ElementTree.fromstring( + '' + widget.selectedHtml() + '').find('a') + if selected_element is not None: + url = selected_element.attrib['href'] + if url: + self._open(QUrl(url), tab) @cmdutils.register(instance='command-dispatcher', name='inspector', scope='window') From 4dc54f881cf87109025366c40a9e17cdb3507551 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 29 May 2015 23:24:13 +0200 Subject: [PATCH 46/70] Give a better error when wrapping on search Previously, it just said "Text not found" when you hit the bottom. --- qutebrowser/browser/webview.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/qutebrowser/browser/webview.py b/qutebrowser/browser/webview.py index a215a1245..51a266949 100644 --- a/qutebrowser/browser/webview.py +++ b/qutebrowser/browser/webview.py @@ -487,12 +487,25 @@ class WebView(QWebView): old_scroll_pos = self.scroll_pos flags = QWebPage.FindFlags(flags) found = self.findText(text, flags) - if not found and not flags & QWebPage.HighlightAllOccurrences and text: - message.error(self.win_id, "Text '{}' not found on " - "page!".format(text), immediately=True) - else: - backward = int(flags) & QWebPage.FindBackward + backward = int(flags) & QWebPage.FindBackward + if not found and not flags & QWebPage.HighlightAllOccurrences and text: + # User disabled wrapping; but findText() just returns False. If we + # have a selection, we know there's a match *somewhere* on the page + if (not flags & QWebPage.FindWrapsAroundDocument and + self.hasSelection()): + if not backward: + message.warning(self.win_id, "Search hit BOTTOM without " + "match for: {}".format(text), + immediately=True) + else: + message.warning(self.win_id, "Search hit TOP without " + "match for: {}".format(text), + immediately=True) + else: + message.error(self.win_id, "Text '{}' not found on " + "page!".format(text), immediately=True) + else: def check_scroll_pos(): """Check if the scroll position got smaller and show info.""" if not backward and self.scroll_pos < old_scroll_pos: From b501677c0e0e1dc519656c9eb552c0400b943cee Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 30 May 2015 22:48:24 +0200 Subject: [PATCH 47/70] Regenerate authors --- README.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.asciidoc b/README.asciidoc index aa94eef98..c651ffc33 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -144,10 +144,10 @@ Contributors, sorted by the number of commits in descending order: * John ShaggyTwoDope Jenkins * Jimmy * Zach-Button +* Martin Tournoij * rikn00 * Patric Schmitz * Martin Zimmermann -* Martin Tournoij * Error 800 * Brian Jackson * sbinix From 3879b8301fdb094330e9d06ba4cf2be9b0b9ef43 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 30 May 2015 22:51:00 +0200 Subject: [PATCH 48/70] Remove unneeded int(). See #706. --- qutebrowser/browser/webview.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/browser/webview.py b/qutebrowser/browser/webview.py index 51a266949..06176064d 100644 --- a/qutebrowser/browser/webview.py +++ b/qutebrowser/browser/webview.py @@ -487,7 +487,7 @@ class WebView(QWebView): old_scroll_pos = self.scroll_pos flags = QWebPage.FindFlags(flags) found = self.findText(text, flags) - backward = int(flags) & QWebPage.FindBackward + backward = flags & QWebPage.FindBackward if not found and not flags & QWebPage.HighlightAllOccurrences and text: # User disabled wrapping; but findText() just returns False. If we From 0be0884a5bb94811fdf9a38a4044bcdd53e96e93 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 30 May 2015 22:46:31 +0200 Subject: [PATCH 49/70] link_pyqt: Only link/copy files if they changed. This reduces the output noise a bit and hopefully makes things a bit faster on Windows. --- scripts/link_pyqt.py | 55 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/scripts/link_pyqt.py b/scripts/link_pyqt.py index 7c8a77b58..dbfeaed99 100644 --- a/scripts/link_pyqt.py +++ b/scripts/link_pyqt.py @@ -28,6 +28,7 @@ import sys import glob import subprocess import platform +import filecmp class Error(Exception): @@ -58,6 +59,22 @@ def get_ignored_files(directory, files): return filtered +def needs_update(source, dest): + """Check if a file to be linked/copied needs to be updated.""" + if os.path.islink(dest): + # No need to delete a link and relink -> skip this + return False + elif os.path.isdir(dest): + diffs = filecmp.dircmp(source, dest) + ignored = get_ignored_files(source, diffs.left_only) + has_new_files = set(ignored) != set(diffs.left_only) + return (has_new_files or diffs.right_only or + diffs.common_funny or diffs.diff_files or + diffs.funny_files) + else: + return not filecmp.cmp(source, dest) + + def link_pyqt(sys_path, venv_path): """Symlink the systemwide PyQt/sip into the venv. @@ -75,26 +92,42 @@ def link_pyqt(sys_path, venv_path): for fn, required in files: source = os.path.join(sys_path, fn) dest = os.path.join(venv_path, fn) + if not os.path.exists(source): if required: raise FileNotFoundError(source) else: continue + if os.path.exists(dest): - if os.path.isdir(dest) and not os.path.islink(dest): - shutil.rmtree(dest) + if needs_update(source, dest): + remove(dest) else: - os.unlink(dest) - if os.name == 'nt': - if os.path.isdir(source): - shutil.copytree(source, dest, ignore=get_ignored_files, - copy_function=verbose_copy) - else: - print('{} -> {}'.format(source, dest)) - shutil.copy(source, dest) + continue + + copy_or_link(source, dest) + + +def copy_or_link(source, dest): + """Copy or symlink source to dest.""" + if os.name == 'nt': + if os.path.isdir(source): + shutil.copytree(source, dest, ignore=get_ignored_files, + copy_function=verbose_copy) else: print('{} -> {}'.format(source, dest)) - os.symlink(source, dest) + shutil.copy(source, dest) + else: + print('{} -> {}'.format(source, dest)) + os.symlink(source, dest) + + +def remove(filename): + """Remove a given filename, regardless of whether it's a file or dir.""" + if os.path.isdir(filename): + shutil.rmtree(filename) + else: + os.unlink(filename) def get_python_lib(executable, venv=False): From b1f8a70c02c5af72abff64d00b0a1715d24f378e Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 30 May 2015 18:03:39 -0400 Subject: [PATCH 50/70] Added try/except for parse error. --- qutebrowser/browser/commands.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 17ef07196..7a4345176 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1003,12 +1003,15 @@ class CommandDispatcher: widget.page().currentFrame().evaluateJavaScript( 'window.getSelection().anchorNode.parentNode.click()') else: - selected_element = ElementTree.fromstring( - '' + widget.selectedHtml() + '').find('a') - if selected_element is not None: - url = selected_element.attrib['href'] - if url: - self._open(QUrl(url), tab) + try: + selected_element = ElementTree.fromstring( + '' + widget.selectedHtml() + '').find('a') + if selected_element is not None: + url = selected_element.attrib['href'] + if url: + self._open(QUrl(url), tab) + except ElementTree.ParseError: + pass @cmdutils.register(instance='command-dispatcher', name='inspector', scope='window') From 81345eb17ee6bd3e80dc7ed16c0159a9ee70961a Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 May 2015 00:11:33 +0200 Subject: [PATCH 51/70] Hide some QXcbWindow warnings. --- qutebrowser/utils/log.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/qutebrowser/utils/log.py b/qutebrowser/utils/log.py index 92bdef222..d156c6be1 100644 --- a/qutebrowser/utils/log.py +++ b/qutebrowser/utils/log.py @@ -269,8 +269,6 @@ def qt_message_handler(msg_type, context, msg): # https://bugreports.qt-project.org/browse/QTBUG-30298 "QNetworkReplyImplPrivate::error: Internal problem, this method must " "only be called once.", - # Not much information about this, but it seems harmless - 'QXcbWindow: Unhandled client message: "_GTK_LOAD_ICONTHEMES"', # Sometimes indicates missing text, but most of the time harmless "load glyph failed ", # Harmless, see https://bugreports.qt-project.org/browse/QTBUG-42479 @@ -282,7 +280,11 @@ def qt_message_handler(msg_type, context, msg): # Hopefully harmless '"Method "GetAll" with signature "s" on interface ' '"org.freedesktop.DBus.Properties" doesn\'t exist', - 'WOFF support requires QtWebKit to be built with zlib support.' + 'WOFF support requires QtWebKit to be built with zlib support.', + # Weird Enlightment/GTK X extensions + 'QXcbWindow: Unhandled client message: "_E_', + 'QXcbWindow: Unhandled client message: "_ECORE_', + 'QXcbWindow: Unhandled client message: "_GTK_', ) if any(msg.strip().startswith(pattern) for pattern in suppressed_msgs): level = logging.DEBUG From 11b258568d7d29a722ae9b57cefbcce2add11db8 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 May 2015 15:02:09 +0200 Subject: [PATCH 52/70] Improve docstring. --- qutebrowser/browser/commands.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 5318bdc7d..8f54ed76b 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -652,8 +652,10 @@ class CommandDispatcher: Args: x: How many pages to scroll to the right. y: How many pages to scroll down. - bottom_navigate: :navigate to the next page on bottom - top_navigate: :navigate to the previous page on top + bottom_navigate: :navigate action (next, increment) to run when + scrolling down at the bottom of the page. + top_navigate: :navigate action (prev, decrement) to run when + scrolling up at the top of the page. count: multiplier """ frame = self._current_widget().page().currentFrame() From cdde1d7dfcb8a07b6d289d932269437f53a4435a Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 May 2015 15:10:12 +0200 Subject: [PATCH 53/70] command: Add support for custom metavar for docs. --- qutebrowser/commands/command.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/qutebrowser/commands/command.py b/qutebrowser/commands/command.py index 998c4a892..d55597d9d 100644 --- a/qutebrowser/commands/command.py +++ b/qutebrowser/commands/command.py @@ -61,7 +61,8 @@ class Command: """ AnnotationInfo = collections.namedtuple('AnnotationInfo', - ['kwargs', 'type', 'flag', 'hide']) + ['kwargs', 'type', 'flag', 'hide', + 'metavar']) def __init__(self, *, handler, name, instance=None, maxsplit=None, hide=False, completion=None, modes=None, not_modes=None, @@ -257,10 +258,10 @@ class Command: pass if isinstance(typ, tuple): - pass + kwargs['metavar'] = annotation_info.metavar or param.name elif utils.is_enum(typ): kwargs['choices'] = [e.name.replace('_', '-') for e in typ] - kwargs['metavar'] = param.name + kwargs['metavar'] = annotation_info.metavar or param.name elif typ is bool: kwargs['action'] = 'store_true' elif typ is not None: @@ -322,11 +323,12 @@ class Command: flag: The short name/flag if overridden. name: The long name if overridden. """ - info = {'kwargs': {}, 'type': None, 'flag': None, 'hide': False} + info = {'kwargs': {}, 'type': None, 'flag': None, 'hide': False, + 'metavar': None} if param.annotation is not inspect.Parameter.empty: log.commands.vdebug("Parsing annotation {}".format( param.annotation)) - for field in ('type', 'flag', 'name', 'hide'): + for field in ('type', 'flag', 'name', 'hide', 'metavar'): if field in param.annotation: info[field] = param.annotation[field] if 'nargs' in param.annotation: From 6b550defaee70d7817b4d58c2a864486856bfe3e Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 May 2015 15:10:35 +0200 Subject: [PATCH 54/70] scroll-page: Add custom metavar for navigate-*. --- qutebrowser/browser/commands.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 8f54ed76b..664cd752f 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -644,8 +644,10 @@ class CommandDispatcher: @cmdutils.register(instance='command-dispatcher', hide=True, scope='window', count='count') def scroll_page(self, x: {'type': float}, y: {'type': float}, *, - top_navigate: {'type': ('prev', 'decrement')}=None, - bottom_navigate: {'type': ('next', 'increment')}=None, + top_navigate: {'type': ('prev', 'decrement'), + 'metavar': 'ACTION'}=None, + bottom_navigate: {'type': ('next', 'increment'), + 'metavar': 'ACTION'}=None, count=1): """Scroll the frame page-wise. From 1814b672d7e6e2504a24eab0df3f091abec18a1e Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 May 2015 15:11:04 +0200 Subject: [PATCH 55/70] Regenerate docs. --- README.asciidoc | 2 +- doc/help/commands.asciidoc | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.asciidoc b/README.asciidoc index c651ffc33..437ab8734 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -141,10 +141,10 @@ Contributors, sorted by the number of commits in descending order: * Artur Shaik * ZDarian * Peter Vilim +* Martin Tournoij * John ShaggyTwoDope Jenkins * Jimmy * Zach-Button -* Martin Tournoij * rikn00 * Patric Schmitz * Martin Zimmermann diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index c33bccaaf..fa835f53a 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -1009,7 +1009,7 @@ multiplier [[scroll-page]] === scroll-page -Syntax: +:scroll-page 'x' 'y'+ +Syntax: +:scroll-page [*--top-navigate* 'ACTION'] [*--bottom-navigate* 'ACTION'] 'x' 'y'+ Scroll the frame page-wise. @@ -1017,6 +1017,12 @@ Scroll the frame page-wise. * +'x'+: How many pages to scroll to the right. * +'y'+: How many pages to scroll down. +==== optional arguments +* +*-t*+, +*--top-navigate*+: :navigate action (prev, decrement) to run when scrolling up at the top of the page. + +* +*-b*+, +*--bottom-navigate*+: :navigate action (next, increment) to run when scrolling down at the bottom of the page. + + ==== count multiplier From 54c1cd7c05e5780460a117c83a9e8c9e77e71e7b Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 May 2015 15:11:37 +0200 Subject: [PATCH 56/70] Add link to issue. --- 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 664cd752f..2c008fd9e 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -661,7 +661,8 @@ class CommandDispatcher: count: multiplier """ frame = self._current_widget().page().currentFrame() - if not frame.url().isValid(): # Issue 701 + if not frame.url().isValid(): + # See https://github.com/The-Compiler/qutebrowser/issues/701 return if (bottom_navigate is not None and From 4ff9d585ea77d5438fa398e9269afb4ead623e8e Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 31 May 2015 11:56:27 -0400 Subject: [PATCH 57/70] Fixed to use qualified import. --- qutebrowser/browser/commands.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 7a4345176..deafedb75 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -25,7 +25,7 @@ import shlex import subprocess import posixpath import functools -from xml.etree import ElementTree +import xml.etree.ElementTree from PyQt5.QtWebKit import QWebSettings from PyQt5.QtWidgets import QApplication, QTabBar @@ -1004,13 +1004,13 @@ class CommandDispatcher: 'window.getSelection().anchorNode.parentNode.click()') else: try: - selected_element = ElementTree.fromstring( + selected_element = xml.etree.ElementTree.fromstring( '' + widget.selectedHtml() + '').find('a') if selected_element is not None: url = selected_element.attrib['href'] if url: self._open(QUrl(url), tab) - except ElementTree.ParseError: + except xml.etree.ElementTree.ParseError: pass @cmdutils.register(instance='command-dispatcher', name='inspector', From c5c145320cf48804a8636037d2c2c52da0b8780c Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 31 May 2015 12:02:15 -0400 Subject: [PATCH 58/70] Fixed exception handling in select_follow command. --- qutebrowser/browser/commands.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index deafedb75..d2738560e 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1006,12 +1006,13 @@ class CommandDispatcher: try: selected_element = xml.etree.ElementTree.fromstring( '' + widget.selectedHtml() + '').find('a') - if selected_element is not None: - url = selected_element.attrib['href'] - if url: - self._open(QUrl(url), tab) except xml.etree.ElementTree.ParseError: - pass + raise cmdexc.CommandError('Parse error') + + if selected_element is not None: + url = selected_element.attrib['href'] + if url: + self._open(QUrl(url), tab) @cmdutils.register(instance='command-dispatcher', name='inspector', scope='window') From 87e988816777dcaad807d732d438aab63f08bb11 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 31 May 2015 12:07:08 -0400 Subject: [PATCH 59/70] Added exception handling for href attribute. --- qutebrowser/browser/commands.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index d2738560e..748fe7d3a 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1007,12 +1007,14 @@ class CommandDispatcher: selected_element = xml.etree.ElementTree.fromstring( '' + widget.selectedHtml() + '').find('a') except xml.etree.ElementTree.ParseError: - raise cmdexc.CommandError('Parse error') + raise cmdexc.CommandError('Parse error!') if selected_element is not None: - url = selected_element.attrib['href'] - if url: - self._open(QUrl(url), tab) + try: + url = selected_element.attrib['href'] + except KeyError: + raise cmdexc.CommandError('Anchor elment without href!') + self._open(QUrl(url), tab) @cmdutils.register(instance='command-dispatcher', name='inspector', scope='window') From 1cd64481de2db6f381204beecc3ca8eab01f976c Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 31 May 2015 12:13:37 -0400 Subject: [PATCH 60/70] Fixed for relative url. --- 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 748fe7d3a..ff7a02aad 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1014,7 +1014,8 @@ class CommandDispatcher: url = selected_element.attrib['href'] except KeyError: raise cmdexc.CommandError('Anchor elment without href!') - self._open(QUrl(url), tab) + url = self._current_url().resolved(QUrl(url)) + self._open(url, tab) @cmdutils.register(instance='command-dispatcher', name='inspector', scope='window') From d0eda3336cd9665623a14e0729f19bb86f9840e8 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 31 May 2015 12:18:27 -0400 Subject: [PATCH 61/70] Added a page variable. --- qutebrowser/browser/commands.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index ff7a02aad..36ef67b74 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -996,11 +996,12 @@ class CommandDispatcher: tab: Load the selected link in a new tab. """ widget = self._current_widget() + page = widget.page() if QWebSettings.globalSettings().testAttribute( QWebSettings.JavascriptEnabled): if tab: - widget.page().open_target = usertypes.ClickTarget.tab - widget.page().currentFrame().evaluateJavaScript( + page.open_target = usertypes.ClickTarget.tab + page.currentFrame().evaluateJavaScript( 'window.getSelection().anchorNode.parentNode.click()') else: try: From c0b6aef7748a2aff2f64cf4c7b6b8ac83e434ea1 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 31 May 2015 12:50:28 -0400 Subject: [PATCH 62/70] Fixed command name. --- qutebrowser/browser/commands.py | 4 ++-- qutebrowser/config/configdata.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 36ef67b74..18164cf31 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -987,9 +987,9 @@ class CommandDispatcher: url = objreg.get('quickmark-manager').get(name) self._open(url, tab, bg, window) - @cmdutils.register(instance='command-dispatcher', name='select-follow', + @cmdutils.register(instance='command-dispatcher', hide=True, scope='window') - def select_follow(self, tab=False): + def follow_selected(self, tab=False): """Follow the selected text. Args: diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index dec02b069..1480ddb2e 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -1239,8 +1239,8 @@ KEY_DATA = collections.OrderedDict([ ('stop', ['']), ('print', ['']), ('open qute:settings', ['Ss']), - ('select-follow', ['']), - ('select-follow -t', ['']), + ('follow-selected', ['']), + ('follow-selected -t', ['']), ])), ('insert', collections.OrderedDict([ From 27cbe618f0c8f4b6e74e0abd5ddc3b857239a550 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 31 May 2015 12:53:14 -0400 Subject: [PATCH 63/70] Added hasSelection check before trying to click on a selected link. --- qutebrowser/browser/commands.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 18164cf31..a221ab44e 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -997,6 +997,8 @@ class CommandDispatcher: """ widget = self._current_widget() page = widget.page() + if not page.hasSelection(): + return if QWebSettings.globalSettings().testAttribute( QWebSettings.JavascriptEnabled): if tab: From 3d0721afea3747287e33c6a5351c8fc3b6a441e5 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 31 May 2015 12:56:08 -0400 Subject: [PATCH 64/70] Fixed error messages. --- 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 a221ab44e..0f09baddf 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1010,13 +1010,13 @@ class CommandDispatcher: selected_element = xml.etree.ElementTree.fromstring( '' + widget.selectedHtml() + '').find('a') except xml.etree.ElementTree.ParseError: - raise cmdexc.CommandError('Parse error!') + raise cmdexc.CommandError('Could not parse selected element!') if selected_element is not None: try: url = selected_element.attrib['href'] except KeyError: - raise cmdexc.CommandError('Anchor elment without href!') + raise cmdexc.CommandError('Anchor element without href!') url = self._current_url().resolved(QUrl(url)) self._open(url, tab) From 172d0c3ca222f116ad58ad88b161b8cbef77174f Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 May 2015 21:16:53 +0200 Subject: [PATCH 65/70] Regenerate docs. --- README.asciidoc | 1 + doc/help/commands.asciidoc | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/README.asciidoc b/README.asciidoc index 437ab8734..a1d4c2128 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -139,6 +139,7 @@ Contributors, sorted by the number of commits in descending order: * Joel Torstensson * Claude * Artur Shaik +* Antoni Boucher * ZDarian * Peter Vilim * Martin Tournoij diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index fa835f53a..6cc2ee9db 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -692,6 +692,7 @@ How many steps to zoom out. |<>|Drop selection and keep selection mode enabled. |<>|Enter a key mode. |<>|Follow the currently selected hint. +|<>|Follow the selected text. |<>|Leave the mode we're currently in. |<>|Show an error message in the statusbar. |<>|Show an info message in the statusbar. @@ -774,6 +775,15 @@ Enter a key mode. === follow-hint Follow the currently selected hint. +[[follow-selected]] +=== follow-selected +Syntax: +:follow-selected [*--tab*]+ + +Follow the selected text. + +==== optional arguments +* +*-t*+, +*--tab*+: Load the selected link in a new tab. + [[leave-mode]] === leave-mode Leave the mode we're currently in. From 122f0a7edc3b805ded089548d389e6667b7e75a2 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 May 2015 21:25:16 +0200 Subject: [PATCH 66/70] Update changelog --- CHANGELOG.asciidoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 2981578e6..8c994280f 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -33,6 +33,9 @@ Added - New argument `--no-err-windows` to suppress all error windows. - New visual/caret mode (bound to `v`) to select text by keyboard. - New setting `tabs -> mousewheel-tab-switching` to control mousewheel behavior on the tab bar. +- New arguments `--top-navigate` and `--bottom-navigate` (`-t`/`-b`) for `:scroll-page` to specify a navigation action (e.g. automatically go to the next page when arriving at the bottom). +- New flag `-d`/`--detach` for `:spawn` to detach the spawned process so it's not closed when qutebrowser is. +- New (hidden) command `:follow-selected` (bound to `Enter`/`Ctrl-Enter` by default) to follow the link which is currently selected (e.g. after searching via `/`). Changed ~~~~~~~ From 4204a8de9a19fefb8098422a291dcbe6495e6580 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Sun, 31 May 2015 21:32:16 +0200 Subject: [PATCH 67/70] Add ui.modal-js-dialog to restore the default JS dialogs --- doc/help/settings.asciidoc | 1 + qutebrowser/browser/webpage.py | 6 ++++++ qutebrowser/config/configdata.py | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index d3c571aa3..4886d9dcd 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -45,6 +45,7 @@ |<>|Whether to hide the statusbar unless a message is shown. |<>|The format to use for the window title. The following placeholders are defined: |<>|Whether to hide the mouse cursor. +|<>|Use standard JavaScript modal dialog for alert() and confirm() |============== .Quick reference for section ``network'' diff --git a/qutebrowser/browser/webpage.py b/qutebrowser/browser/webpage.py index 005a6e300..fd6e7a7c9 100644 --- a/qutebrowser/browser/webpage.py +++ b/qutebrowser/browser/webpage.py @@ -481,6 +481,9 @@ class BrowserPage(QWebPage): def javaScriptAlert(self, _frame, msg): """Override javaScriptAlert to use the statusbar.""" log.js.debug("alert: {}".format(msg)) + if config.get('ui', 'modal-js-dialog'): + return super().javaScriptAlert(_frame, msg) + if (self._is_shutting_down or config.get('content', 'ignore-javascript-alert')): return @@ -489,6 +492,9 @@ class BrowserPage(QWebPage): def javaScriptConfirm(self, _frame, msg): """Override javaScriptConfirm to use the statusbar.""" log.js.debug("confirm: {}".format(msg)) + if config.get('ui', 'modal-js-dialog'): + return super().javaScriptConfirm(_frame, msg) + if self._is_shutting_down: return False ans = self._ask("[js confirm] {}".format(msg), diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index 02b8c6008..f2c68c708 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -305,6 +305,10 @@ def data(readonly=False): SettingValue(typ.Bool(), 'false'), "Whether to hide the mouse cursor."), + ('modal-js-dialog', + SettingValue(typ.Bool(), 'false'), + "Use standard JavaScript modal dialog for alert() and confirm()"), + readonly=readonly )), From e7619477cd341fdefaf22af29095b2fa9cef7de3 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 May 2015 21:40:19 +0200 Subject: [PATCH 68/70] Rename _frame argument to frame. _foo is used to denote unused arguments, so renaming this as it's now used. --- qutebrowser/browser/webpage.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qutebrowser/browser/webpage.py b/qutebrowser/browser/webpage.py index fd6e7a7c9..8e430efcb 100644 --- a/qutebrowser/browser/webpage.py +++ b/qutebrowser/browser/webpage.py @@ -478,22 +478,22 @@ class BrowserPage(QWebPage): return super().extension(ext, opt, out) return handler(opt, out) - def javaScriptAlert(self, _frame, msg): + def javaScriptAlert(self, frame, msg): """Override javaScriptAlert to use the statusbar.""" log.js.debug("alert: {}".format(msg)) if config.get('ui', 'modal-js-dialog'): - return super().javaScriptAlert(_frame, msg) + return super().javaScriptAlert(frame, msg) if (self._is_shutting_down or config.get('content', 'ignore-javascript-alert')): return self._ask("[js alert] {}".format(msg), usertypes.PromptMode.alert) - def javaScriptConfirm(self, _frame, msg): + def javaScriptConfirm(self, frame, msg): """Override javaScriptConfirm to use the statusbar.""" log.js.debug("confirm: {}".format(msg)) if config.get('ui', 'modal-js-dialog'): - return super().javaScriptConfirm(_frame, msg) + return super().javaScriptConfirm(frame, msg) if self._is_shutting_down: return False From f52f3db1f21a55509d06b17677dfff2d5b2ad379 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 May 2015 21:41:32 +0200 Subject: [PATCH 69/70] Regenerate docs. --- README.asciidoc | 2 +- doc/help/settings.asciidoc | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/README.asciidoc b/README.asciidoc index a1d4c2128..63d803d8f 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -141,8 +141,8 @@ Contributors, sorted by the number of commits in descending order: * Artur Shaik * Antoni Boucher * ZDarian -* Peter Vilim * Martin Tournoij +* Peter Vilim * John ShaggyTwoDope Jenkins * Jimmy * Zach-Button diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index 4886d9dcd..073ad2d63 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -45,7 +45,7 @@ |<>|Whether to hide the statusbar unless a message is shown. |<>|The format to use for the window title. The following placeholders are defined: |<>|Whether to hide the mouse cursor. -|<>|Use standard JavaScript modal dialog for alert() and confirm() +|<>|Use standard JavaScript modal dialog for alert() and confirm() |============== .Quick reference for section ``network'' @@ -595,6 +595,17 @@ Valid values: Default: +pass:[false]+ +[[ui-modal-js-dialog]] +=== modal-js-dialog +Use standard JavaScript modal dialog for alert() and confirm() + +Valid values: + + * +true+ + * +false+ + +Default: +pass:[false]+ + == network Settings related to the network. From a14685be3de0609de196bdb47856a22a7da4097e Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 31 May 2015 21:42:25 +0200 Subject: [PATCH 70/70] Update changelog. --- CHANGELOG.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 8c994280f..96e6482ea 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -36,6 +36,7 @@ Added - New arguments `--top-navigate` and `--bottom-navigate` (`-t`/`-b`) for `:scroll-page` to specify a navigation action (e.g. automatically go to the next page when arriving at the bottom). - New flag `-d`/`--detach` for `:spawn` to detach the spawned process so it's not closed when qutebrowser is. - New (hidden) command `:follow-selected` (bound to `Enter`/`Ctrl-Enter` by default) to follow the link which is currently selected (e.g. after searching via `/`). +- New setting `ui -> modal-js-dialog` to use the standard modal dialogs for javascript questions instead of using the statusbar. Changed ~~~~~~~