From 9d0dfd5726faa81613144bbe0d07c6b025ba9ece Mon Sep 17 00:00:00 2001 From: Luca Benci Date: Sat, 7 Oct 2017 15:18:57 +0200 Subject: [PATCH 01/99] Always run best-matching command --- qutebrowser/commands/runners.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/commands/runners.py b/qutebrowser/commands/runners.py index 9d480cc5d..21ec41e58 100644 --- a/qutebrowser/commands/runners.py +++ b/qutebrowser/commands/runners.py @@ -218,7 +218,7 @@ class CommandParser: for valid_command in cmdutils.cmd_dict: if valid_command.find(cmdstr) == 0: matches.append(valid_command) - if len(matches) == 1: + if len(matches) >= 1: cmdstr = matches[0] return cmdstr From 71048a1b55fe3383f98f54237558e665b91be52b Mon Sep 17 00:00:00 2001 From: Luca Benci Date: Sat, 7 Oct 2017 15:42:42 +0200 Subject: [PATCH 02/99] Add (and use) completion.use_best_match config --- qutebrowser/commands/runners.py | 4 +++- qutebrowser/config/configdata.yml | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/qutebrowser/commands/runners.py b/qutebrowser/commands/runners.py index 21ec41e58..d6a12e2c7 100644 --- a/qutebrowser/commands/runners.py +++ b/qutebrowser/commands/runners.py @@ -218,7 +218,9 @@ class CommandParser: for valid_command in cmdutils.cmd_dict: if valid_command.find(cmdstr) == 0: matches.append(valid_command) - if len(matches) >= 1: + if len(matches) == 1: + cmdstr = matches[0] + elif len(matches) > 1 and config.val.completion.use_best_match: cmdstr = matches[0] return cmdstr diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 56b58f8e1..acee49f40 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -656,6 +656,11 @@ completion.web_history_max_items: 0: no history / -1: unlimited +completion.use_best_match: + type: Bool + default: true + desc: Whether to execute the best-matching command on a partial match. + ## downloads downloads.location.directory: From 0578349e290e8292f4fbd3ba2890edb7a6ce91da Mon Sep 17 00:00:00 2001 From: Luca Benci Date: Mon, 9 Oct 2017 11:06:25 +0200 Subject: [PATCH 03/99] Default completion.use_best_match to false --- qutebrowser/config/configdata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index acee49f40..e3c6c6e7a 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -658,7 +658,7 @@ completion.web_history_max_items: completion.use_best_match: type: Bool - default: true + default: false desc: Whether to execute the best-matching command on a partial match. ## downloads From 019d66a4c626d9a8ee8a5e3a026eb680347598a0 Mon Sep 17 00:00:00 2001 From: Joakim Reinert Date: Wed, 27 Sep 2017 13:39:33 +0200 Subject: [PATCH 04/99] add adjustable delay for completion updates --- qutebrowser/completion/completer.py | 4 +++- qutebrowser/config/configdata.yml | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/qutebrowser/completion/completer.py b/qutebrowser/completion/completer.py index efd6b3490..23c77b59a 100644 --- a/qutebrowser/completion/completer.py +++ b/qutebrowser/completion/completer.py @@ -196,6 +196,8 @@ class Completer(QObject): For performance reasons we don't want to block here, instead we do this in the background. + + We delay the update only if we've already input some text. """ if (self._cmd.cursorPosition() == self._last_cursor_pos and self._cmd.text() == self._last_text): @@ -203,7 +205,7 @@ class Completer(QObject): "changes.") else: log.completion.debug("Scheduling completion update.") - self._timer.start() + self._timer.start(config.val.completion.delay if self._last_text else 0) self._last_cursor_pos = self._cmd.cursorPosition() self._last_text = self._cmd.text() diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index f500a2f0f..71ab4c8b0 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -656,6 +656,13 @@ completion.web_history_max_items: 0: no history / -1: unlimited +completion.delay: + default: 0 + type: + name: Int + minval: 0 + desc: Delay in ms before updating completions after typing a character + ## downloads downloads.location.directory: From 0226025308819df0381887e42ec14287d9e7c65b Mon Sep 17 00:00:00 2001 From: Joakim Reinert Date: Wed, 27 Sep 2017 13:41:06 +0200 Subject: [PATCH 05/99] add adjustable amount of chars required to update completions --- qutebrowser/completion/completer.py | 11 +++++++++-- qutebrowser/config/configdata.yml | 7 +++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/qutebrowser/completion/completer.py b/qutebrowser/completion/completer.py index 23c77b59a..aa7f170a9 100644 --- a/qutebrowser/completion/completer.py +++ b/qutebrowser/completion/completer.py @@ -197,9 +197,16 @@ class Completer(QObject): For performance reasons we don't want to block here, instead we do this in the background. - We delay the update only if we've already input some text. + We delay the update only if we've already input some text and ignore + updates if the text is shorter than completion.min_chars (unless we're + hitting backspace in which case updates won't be ignored). """ - if (self._cmd.cursorPosition() == self._last_cursor_pos and + cmd, _sep, rest = self._cmd.text().partition(' ') + if (0 < len(rest) < config.val.completion.min_chars and + self._cmd.cursorPosition() > self._last_cursor_pos): + log.completion.debug("Ignoring update because the length of " + "the text is less than completion.min_chars.") + elif (self._cmd.cursorPosition() == self._last_cursor_pos and self._cmd.text() == self._last_text): log.completion.debug("Ignoring update because there were no " "changes.") diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 71ab4c8b0..23349de29 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -663,6 +663,13 @@ completion.delay: minval: 0 desc: Delay in ms before updating completions after typing a character +completion.min_chars: + default: 1 + type: + name: Int + minval: 1 + desc: Minimum amount of characters needed to update completions + ## downloads downloads.location.directory: From 5078080bb00f9a8d40ace9810b18eeb751cd7fad Mon Sep 17 00:00:00 2001 From: Luca Benci Date: Tue, 10 Oct 2017 22:02:25 +0200 Subject: [PATCH 06/99] Add (not fully working) tests for use_best_match --- tests/unit/config/test_configcommands.py | 31 +++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tests/unit/config/test_configcommands.py b/tests/unit/config/test_configcommands.py index 21ec040f7..ed69e7c32 100644 --- a/tests/unit/config/test_configcommands.py +++ b/tests/unit/config/test_configcommands.py @@ -25,7 +25,7 @@ import pytest from PyQt5.QtCore import QUrl, QProcess from qutebrowser.config import configcommands -from qutebrowser.commands import cmdexc +from qutebrowser.commands import cmdexc, runners from qutebrowser.utils import usertypes from qutebrowser.misc import objects @@ -532,3 +532,32 @@ class TestBind: """ with pytest.raises(cmdexc.CommandError, match=expected): commands.unbind(key, mode=mode) + + +class TestCompletions: + + """Tests for completions.use_best_match.""" + + def test_dont_use_best_match(self, config_stub, monkeypatch): + """Test multiple completion options with use_best_match set to false. + + Should raise NoSuchCommandError + """ + config_stub.val.completion.use_best_match = False + monkeypatch.setattr('qutebrowser.config', config_stub) + parser = runners.CommandParser(partial_match=True) + + with pytest.raises(cmdexc.NoSuchCommandError): + result = parser.parse('do') + + def test_use_best_match(self, config_stub, monkeypatch): + """Test multiple completion options with use_best_match set to true. + + The resulting command should be the best match + """ + config_stub.val.completion.use_best_match = True + monkeypatch.setattr('qutebrowser.config', config_stub) + parser = runners.CommandParser(partial_match=True) + + result = parser.parse('do') + assert result.cmd.name == 'download' From 787e3db3d50aa5d42227f708477a01526b015416 Mon Sep 17 00:00:00 2001 From: Luca Benci Date: Tue, 10 Oct 2017 22:51:40 +0200 Subject: [PATCH 07/99] Move tests to test_runners.py --- tests/unit/commands/test_runners.py | 29 ++++++++++++++++++++++ tests/unit/config/test_configcommands.py | 31 +----------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/tests/unit/commands/test_runners.py b/tests/unit/commands/test_runners.py index 75558b390..daa8541e8 100644 --- a/tests/unit/commands/test_runners.py +++ b/tests/unit/commands/test_runners.py @@ -74,3 +74,32 @@ class TestCommandParser: parser = runners.CommandParser(partial_match=True) result = parser.parse('message-i') assert result.cmd.name == 'message-info' + + +class TestCompletions: + + """Tests for completions.use_best_match.""" + + def test_dont_use_best_match(self, config_stub, monkeypatch): + """Test multiple completion options with use_best_match set to false. + + Should raise NoSuchCommandError + """ + config_stub.val.completion.use_best_match = False + monkeypatch.setattr('qutebrowser.config', config_stub) + parser = runners.CommandParser(partial_match=True) + + with pytest.raises(cmdexc.NoSuchCommandError): + result = parser.parse('do') + + def test_use_best_match(self, config_stub, monkeypatch): + """Test multiple completion options with use_best_match set to true. + + The resulting command should be the best match + """ + config_stub.val.completion.use_best_match = True + monkeypatch.setattr('qutebrowser.config', config_stub) + parser = runners.CommandParser(partial_match=True) + + result = parser.parse('do') + assert result.cmd.name == 'download' diff --git a/tests/unit/config/test_configcommands.py b/tests/unit/config/test_configcommands.py index ed69e7c32..21ec040f7 100644 --- a/tests/unit/config/test_configcommands.py +++ b/tests/unit/config/test_configcommands.py @@ -25,7 +25,7 @@ import pytest from PyQt5.QtCore import QUrl, QProcess from qutebrowser.config import configcommands -from qutebrowser.commands import cmdexc, runners +from qutebrowser.commands import cmdexc from qutebrowser.utils import usertypes from qutebrowser.misc import objects @@ -532,32 +532,3 @@ class TestBind: """ with pytest.raises(cmdexc.CommandError, match=expected): commands.unbind(key, mode=mode) - - -class TestCompletions: - - """Tests for completions.use_best_match.""" - - def test_dont_use_best_match(self, config_stub, monkeypatch): - """Test multiple completion options with use_best_match set to false. - - Should raise NoSuchCommandError - """ - config_stub.val.completion.use_best_match = False - monkeypatch.setattr('qutebrowser.config', config_stub) - parser = runners.CommandParser(partial_match=True) - - with pytest.raises(cmdexc.NoSuchCommandError): - result = parser.parse('do') - - def test_use_best_match(self, config_stub, monkeypatch): - """Test multiple completion options with use_best_match set to true. - - The resulting command should be the best match - """ - config_stub.val.completion.use_best_match = True - monkeypatch.setattr('qutebrowser.config', config_stub) - parser = runners.CommandParser(partial_match=True) - - result = parser.parse('do') - assert result.cmd.name == 'download' From 052c527e4c8cafc576691fa49496d4397dca5a6a Mon Sep 17 00:00:00 2001 From: Luca Benci Date: Tue, 10 Oct 2017 22:52:57 +0200 Subject: [PATCH 08/99] Avoid explicit config monkeypatching --- tests/unit/commands/test_runners.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/unit/commands/test_runners.py b/tests/unit/commands/test_runners.py index daa8541e8..4497cb843 100644 --- a/tests/unit/commands/test_runners.py +++ b/tests/unit/commands/test_runners.py @@ -80,25 +80,23 @@ class TestCompletions: """Tests for completions.use_best_match.""" - def test_dont_use_best_match(self, config_stub, monkeypatch): + def test_dont_use_best_match(self, config_stub): """Test multiple completion options with use_best_match set to false. Should raise NoSuchCommandError """ config_stub.val.completion.use_best_match = False - monkeypatch.setattr('qutebrowser.config', config_stub) parser = runners.CommandParser(partial_match=True) with pytest.raises(cmdexc.NoSuchCommandError): result = parser.parse('do') - def test_use_best_match(self, config_stub, monkeypatch): + def test_use_best_match(self, config_stub): """Test multiple completion options with use_best_match set to true. The resulting command should be the best match """ config_stub.val.completion.use_best_match = True - monkeypatch.setattr('qutebrowser.config', config_stub) parser = runners.CommandParser(partial_match=True) result = parser.parse('do') From c8d41a4f879f2acfc5304d94285f3517c784ebe4 Mon Sep 17 00:00:00 2001 From: Luca Benci Date: Tue, 10 Oct 2017 22:54:49 +0200 Subject: [PATCH 09/99] Make tests pass --- tests/unit/commands/test_runners.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/commands/test_runners.py b/tests/unit/commands/test_runners.py index 4497cb843..fad96c558 100644 --- a/tests/unit/commands/test_runners.py +++ b/tests/unit/commands/test_runners.py @@ -100,4 +100,4 @@ class TestCompletions: parser = runners.CommandParser(partial_match=True) result = parser.parse('do') - assert result.cmd.name == 'download' + assert result.cmd.name == 'download-cancel' From b7061dc7db4cd4e9d44fc21aedf3a41487e4cbcf Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Wed, 4 Oct 2017 04:33:23 +1100 Subject: [PATCH 10/99] Separate logic for resolving buffers from index --- qutebrowser/browser/commands.py | 74 +++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 7a8825720..7a3bbe159 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1009,40 +1009,27 @@ class CommandDispatcher: raise cmdexc.CommandError(e) self._open(url, tab, bg, window) - @cmdutils.register(instance='command-dispatcher', scope='window') - @cmdutils.argument('index', completion=miscmodels.buffer) - @cmdutils.argument('count', count=True) - def buffer(self, index=None, count=None): - """Select tab by index or url/title best match. - - Focuses window if necessary when index is given. If both index and - count are given, use count. + def _resolve_buffer_index(self, index): + """Resolves a buffer index to the tabbedbrowser and tab. Args: - index: The [win_id/]index of the tab to focus. Or a substring + index: The [win_id/]index of the tab to be selected. Or a substring in which case the closest match will be focused. - count: The tab index to focus, starting with 1. """ - if count is not None: - index_parts = [count] - elif index is None: - raise cmdexc.CommandError("buffer: Either a count or the argument " - "index must be specified.") - else: - index_parts = index.split('/', 1) + index_parts = index.split('/', 1) - try: - for part in index_parts: - int(part) - except ValueError: - model = miscmodels.buffer() - model.set_pattern(index) - if model.count() > 0: - index = model.data(model.first_item()) - index_parts = index.split('/', 1) - else: - raise cmdexc.CommandError( - "No matching tab for: {}".format(index)) + try: + for part in index_parts: + int(part) + except ValueError: + model = miscmodels.buffer() + model.set_pattern(index) + if model.count() > 0: + index = model.data(model.first_item()) + index_parts = index.split('/', 1) + else: + raise cmdexc.CommandError( + "No matching tab for: {}".format(index)) if len(index_parts) == 2: win_id = int(index_parts[0]) @@ -1066,10 +1053,35 @@ class CommandDispatcher: raise cmdexc.CommandError( "There's no tab with index {}!".format(idx)) - window = objreg.window_registry[win_id] + return (tabbed_browser, tabbed_browser.widget(idx-1)) + + @cmdutils.register(instance='command-dispatcher', scope='window') + @cmdutils.argument('index', completion=miscmodels.buffer) + @cmdutils.argument('count', count=True) + def buffer(self, index=None, count=None): + """Select tab by index or url/title best match. + + Focuses window if necessary when index is given. If both index and + count are given, use count. + + Args: + index: The [win_id/]index of the tab to focus. Or a substring + in which case the closest match will be focused. + count: The tab index to focus, starting with 1. + """ + if count is None and index is None: + raise cmdexc.CommandError("buffer: Either a count or the argument " + "index must be specified.") + + if count is not None: + index = str(count) + + tabbed_browser, tab = self._resolve_buffer_index(index) + + window = tabbed_browser.window() window.activateWindow() window.raise_() - tabbed_browser.setCurrentIndex(idx-1) + tabbed_browser.setCurrentWidget(tab) @cmdutils.register(instance='command-dispatcher', scope='window') @cmdutils.argument('index', choices=['last']) From 67437a0d5d78736e279927b195f27ceed23230a2 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Wed, 4 Oct 2017 05:05:00 +1100 Subject: [PATCH 11/99] Add :tab-give and :tab-take commands and tests --- doc/help/commands.asciidoc | 21 +++++++++ qutebrowser/browser/commands.py | 33 ++++++++++++++ qutebrowser/completion/models/miscmodels.py | 19 ++++++++ tests/end2end/features/tabs.feature | 50 +++++++++++++++++++++ 4 files changed, 123 insertions(+) diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index 137bf3ef8..e166e51eb 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -85,11 +85,13 @@ It is possible to run or bind multiple commands by separating them with `;;`. |<>|Close the current/[count]th tab. |<>|Detach the current tab to its own window. |<>|Select the tab given as argument/[count]. +|<>|Give the current tab to another window. |<>|Move the current tab according to the argument and [count]. |<>|Switch to the next tab, or switch [count] tabs forward. |<>|Close all tabs except for the current one. |<>|Pin/Unpin the current/[count]th tab. |<>|Switch to the previous tab, or switch [count] tabs back. +|<>|Take a tab from another window. |<>|Unbind a keychain. |<>|Re-open a closed tab. |<>|Show version information. @@ -967,6 +969,15 @@ If neither count nor index are given, it behaves like tab-next. If both are give ==== count The tab index to focus, starting with 1. +[[tab-give]] +=== tab-give +Syntax: +:tab-give 'win-id'+ + +Give the current tab to another window. + +==== positional arguments +* +'win-id'+: The window ID of the window to give the current tab to. + [[tab-move]] === tab-move Syntax: +:tab-move ['index']+ @@ -1019,6 +1030,16 @@ Switch to the previous tab, or switch [count] tabs back. ==== count How many tabs to switch back. +[[tab-take]] +=== tab-take +Syntax: +:tab-take 'index'+ + +Take a tab from another window. + +==== positional arguments +* +'index'+: The [win_id/]index of the tab to take. Or a substring in which case the closest match will be taken. + + [[unbind]] === unbind Syntax: +:unbind [*--mode* 'mode'] 'key'+ diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 7a3bbe159..b7ed82af9 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -523,6 +523,39 @@ class CommandDispatcher: cur_widget = self._current_widget() self._tabbed_browser.close_tab(cur_widget, add_undo=False) + @cmdutils.register(instance='command-dispatcher', scope='window') + @cmdutils.argument('index', completion=miscmodels.buffer) + def tab_take(self, index): + """Take a tab from another window. + + Args: + index: The [win_id/]index of the tab to take. Or a substring + in which case the closest match will be taken. + """ + tabbed_browser, tab = self._resolve_buffer_index(index) + + if tabbed_browser is self._tabbed_browser: + raise cmdexc.CommandError("Can't take a tab from the same window") + + self._open(tab.url(), tab=True) + tabbed_browser.close_tab(tab, add_undo=False) + + @cmdutils.register(instance='command-dispatcher', scope='window') + @cmdutils.argument('win_id', completion=miscmodels.window) + def tab_give(self, win_id: int): + """Give the current tab to another window. + + Args: + win_id: The window ID of the window to give the current tab to. + """ + if win_id == self._win_id: + raise cmdexc.CommandError("Can't give a tab to the same window") + + tabbed_browser = objreg.get('tabbed-browser', scope='window', + window=win_id) + tabbed_browser.tabopen(self._current_url()) + self._tabbed_browser.close_tab(self._current_widget(), add_undo=False) + def _back_forward(self, tab, bg, window, count, forward): """Helper function for :back/:forward.""" history = self._current_widget().history diff --git a/qutebrowser/completion/models/miscmodels.py b/qutebrowser/completion/models/miscmodels.py index 3244c7bf3..9b7783e4f 100644 --- a/qutebrowser/completion/models/miscmodels.py +++ b/qutebrowser/completion/models/miscmodels.py @@ -122,3 +122,22 @@ def buffer(*, info=None): # pylint: disable=unused-argument model.add_category(cat) return model + + +def window(*, info=None): # pylint: disable=unused-argument + """A model to complete on all open windows.""" + model = completionmodel.CompletionModel(column_widths=(6, 30, 64)) + + windows = [] + + for win_id in objreg.window_registry: + tabbed_browser = objreg.get('tabbed-browser', scope='window', + window=win_id) + tab_titles = (tab.title() for tab in tabbed_browser.widgets()) + windows.append(("{}".format(win_id), + objreg.window_registry[win_id].windowTitle(), + ", ".join(tab_titles))) + + model.add_category(listcategory.ListCategory("Windows", windows)) + + return model diff --git a/tests/end2end/features/tabs.feature b/tests/end2end/features/tabs.feature index b510a4f66..ba20f9a75 100644 --- a/tests/end2end/features/tabs.feature +++ b/tests/end2end/features/tabs.feature @@ -1010,6 +1010,56 @@ Feature: Tab management And I run :buffer "1/2/3" Then the error "No matching tab for: 1/2/3" should be shown + # :tab-take + + @xfail_norun + Scenario: Take a tab from another window + Given I have a fresh instance + When I open data/numbers/1.txt + And I open data/numbers/2.txt in a new window + And I run :tab-take 0/1 + Then the session should look like: + windows: + - tabs: + - history: + - url: about:blank + - tabs: + - history: + - url: http://localhost:*/data/numbers/2.txt + - history: + - url: http://localhost:*/data/numbers/1.txt + + Scenario: Take a tab from the same window + Given I have a fresh instance + When I open data/numbers/1.txt + And I run :tab-take 0/1 + Then the error "Can't take a tab from the same window" should be shown + + # :tab-give + + @xfail_norun + Scenario: Give a tab to another window + Given I have a fresh instance + When I open data/numbers/1.txt + And I open data/numbers/2.txt in a new window + And I run :tab-give 0 + Then the session should look like: + windows: + - tabs: + - history: + - url: http://localhost:*/data/numbers/1.txt + - history: + - url: http://localhost:*/data/numbers/2.txt + - tabs: + - history: + - url: about:blank + + Scenario: Give a tab to the same window + Given I have a fresh instance + When I open data/numbers/1.txt + And I run :tab-give 0 + Then the error "Can't give a tab to the same window" should be shown + # Other Scenario: Using :tab-next after closing last tab (#1448) From 29f66dcd9591016585602566af46cbbbb63efb2b Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Wed, 4 Oct 2017 13:35:40 +1100 Subject: [PATCH 12/99] Merge :tab-detach with :tab-give --- doc/help/commands.asciidoc | 13 ++++----- qutebrowser/browser/commands.py | 28 +++++++++--------- tests/end2end/features/invoke.feature | 4 +-- tests/end2end/features/tabs.feature | 42 +++++++++++++-------------- 4 files changed, 41 insertions(+), 46 deletions(-) diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index e166e51eb..fed4e88d4 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -83,9 +83,8 @@ It is possible to run or bind multiple commands by separating them with `;;`. |<>|Stop loading in the current/[count]th tab. |<>|Duplicate the current tab. |<>|Close the current/[count]th tab. -|<>|Detach the current tab to its own window. |<>|Select the tab given as argument/[count]. -|<>|Give the current tab to another window. +|<>|Give the current tab to a new or existing window if win_id given. |<>|Move the current tab according to the argument and [count]. |<>|Switch to the next tab, or switch [count] tabs forward. |<>|Close all tabs except for the current one. @@ -948,10 +947,6 @@ Close the current/[count]th tab. ==== count The tab index to close -[[tab-detach]] -=== tab-detach -Detach the current tab to its own window. - [[tab-focus]] === tab-focus Syntax: +:tab-focus ['index']+ @@ -971,9 +966,11 @@ The tab index to focus, starting with 1. [[tab-give]] === tab-give -Syntax: +:tab-give 'win-id'+ +Syntax: +:tab-give ['win-id']+ -Give the current tab to another window. +Give the current tab to a new or existing window if win_id given. + +If no win_id is given, the tab will get detached into a new window. ==== positional arguments * +'win-id'+: The window ID of the window to give the current tab to. diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index b7ed82af9..a3eed85df 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -513,16 +513,6 @@ class CommandDispatcher: new_tabbed_browser.set_tab_pinned(newtab, curtab.data.pinned) return newtab - @cmdutils.register(instance='command-dispatcher', scope='window') - def tab_detach(self): - """Detach the current tab to its own window.""" - if self._count() < 2: - raise cmdexc.CommandError("Cannot detach one tab.") - url = self._current_url() - self._open(url, window=True) - cur_widget = self._current_widget() - self._tabbed_browser.close_tab(cur_widget, add_undo=False) - @cmdutils.register(instance='command-dispatcher', scope='window') @cmdutils.argument('index', completion=miscmodels.buffer) def tab_take(self, index): @@ -542,8 +532,10 @@ class CommandDispatcher: @cmdutils.register(instance='command-dispatcher', scope='window') @cmdutils.argument('win_id', completion=miscmodels.window) - def tab_give(self, win_id: int): - """Give the current tab to another window. + def tab_give(self, win_id: int = None): + """Give the current tab to a new or existing window if win_id given. + + If no win_id is given, the tab will get detached into a new window. Args: win_id: The window ID of the window to give the current tab to. @@ -551,8 +543,16 @@ class CommandDispatcher: if win_id == self._win_id: raise cmdexc.CommandError("Can't give a tab to the same window") - tabbed_browser = objreg.get('tabbed-browser', scope='window', - window=win_id) + if win_id is not None: + tabbed_browser = objreg.get('tabbed-browser', scope='window', + window=win_id) + else: + if self._count() < 2: + raise cmdexc.CommandError("Cannot detach from a window with " + "only one tab") + + tabbed_browser = self._new_tabbed_browser( + private=self._tabbed_browser.private) tabbed_browser.tabopen(self._current_url()) self._tabbed_browser.close_tab(self._current_widget(), add_undo=False) diff --git a/tests/end2end/features/invoke.feature b/tests/end2end/features/invoke.feature index d343db593..9be38659e 100644 --- a/tests/end2end/features/invoke.feature +++ b/tests/end2end/features/invoke.feature @@ -74,12 +74,12 @@ Feature: Invoking a new process # issue #1060 - Scenario: Using target_window = first-opened after tab-detach + Scenario: Using target_window = first-opened after tab-give When I set new_instance_open_target to tab And I set new_instance_open_target_window to first-opened And I open data/title.html And I open data/search.html in a new tab - And I run :tab-detach + And I run :tab-give And I wait until data/search.html is loaded And I open data/hello.txt as a URL Then the session should look like: diff --git a/tests/end2end/features/tabs.feature b/tests/end2end/features/tabs.feature index ba20f9a75..4c35547dc 100644 --- a/tests/end2end/features/tabs.feature +++ b/tests/end2end/features/tabs.feature @@ -638,28 +638,6 @@ Feature: Tab management And I run :tab-clone Then no crash should happen - # :tab-detach - - Scenario: Detaching a tab - When I open data/numbers/1.txt - And I open data/numbers/2.txt in a new tab - And I run :tab-detach - And I wait until data/numbers/2.txt is loaded - Then the session should look like: - windows: - - tabs: - - history: - - url: about:blank - - url: http://localhost:*/data/numbers/1.txt - - tabs: - - history: - - url: http://localhost:*/data/numbers/2.txt - - Scenario: Detach tab from window with only one tab - When I open data/hello.txt - And I run :tab-detach - Then the error "Cannot detach one tab." should be shown - # :undo Scenario: Undo without any closed tabs @@ -1060,6 +1038,26 @@ Feature: Tab management And I run :tab-give 0 Then the error "Can't give a tab to the same window" should be shown + Scenario: Give a tab to a new window + When I open data/numbers/1.txt + And I open data/numbers/2.txt in a new tab + And I run :tab-give + And I wait until data/numbers/2.txt is loaded + Then the session should look like: + windows: + - tabs: + - history: + - url: about:blank + - url: http://localhost:*/data/numbers/1.txt + - tabs: + - history: + - url: http://localhost:*/data/numbers/2.txt + + Scenario: Give a tab from window with only one tab + When I open data/hello.txt + And I run :tab-give + Then the error "Cannot detach from a window with only one tab" should be shown + # Other Scenario: Using :tab-next after closing last tab (#1448) From 249e497d368759d38a8751d0ceb6490c8db22667 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Wed, 11 Oct 2017 17:14:18 +1100 Subject: [PATCH 13/99] Add test for window completion --- tests/helpers/fixtures.py | 3 +++ tests/helpers/stubs.py | 3 +++ tests/unit/completion/test_models.py | 24 ++++++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/tests/helpers/fixtures.py b/tests/helpers/fixtures.py index 09307711f..3434760ec 100644 --- a/tests/helpers/fixtures.py +++ b/tests/helpers/fixtures.py @@ -60,6 +60,9 @@ class WinRegistryHelper: registry = attr.ib() + def windowTitle(self): + return 'window title - qutebrowser' + def __init__(self): self._ids = [] diff --git a/tests/helpers/stubs.py b/tests/helpers/stubs.py index 15d2ce8a0..0a6df9b35 100644 --- a/tests/helpers/stubs.py +++ b/tests/helpers/stubs.py @@ -520,6 +520,9 @@ class TabbedBrowserStub(QObject): def count(self): return len(self.tabs) + def widgets(self): + return self.tabs + def widget(self, i): return self.tabs[i] diff --git a/tests/unit/completion/test_models.py b/tests/unit/completion/test_models.py index 30241b1b3..80b3234a9 100644 --- a/tests/unit/completion/test_models.py +++ b/tests/unit/completion/test_models.py @@ -528,6 +528,30 @@ def test_tab_completion_delete(qtmodeltester, fake_web_tab, app_stub, QUrl('https://duckduckgo.com')] +def test_window_completion(qtmodeltester, fake_web_tab, tabbed_browser_stubs): + tabbed_browser_stubs[0].tabs = [ + fake_web_tab(QUrl('https://github.com'), 'GitHub', 0), + fake_web_tab(QUrl('https://wikipedia.org'), 'Wikipedia', 1), + fake_web_tab(QUrl('https://duckduckgo.com'), 'DuckDuckGo', 2) + ] + tabbed_browser_stubs[1].tabs = [ + fake_web_tab(QUrl('https://wiki.archlinux.org'), 'ArchWiki', 0) + ] + + model = miscmodels.window() + model.set_pattern('') + qtmodeltester.data_display_may_return_none = True + qtmodeltester.check(model) + + _check_completions(model, { + 'Windows': [ + ('0', 'window title - qutebrowser', + 'GitHub, Wikipedia, DuckDuckGo'), + ('1', 'window title - qutebrowser', 'ArchWiki') + ] + }) + + def test_setting_option_completion(qtmodeltester, config_stub, configdata_stub, info): model = configmodel.option(info=info) From 7c584e7b6c6a1514ecd28bc7962d63c74bab74e7 Mon Sep 17 00:00:00 2001 From: Joakim Reinert Date: Mon, 9 Oct 2017 16:23:45 +0200 Subject: [PATCH 14/99] add optional interval argument to start function of Timer stubs Fixes failing tests for completer --- tests/helpers/stubs.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/helpers/stubs.py b/tests/helpers/stubs.py index 15d2ce8a0..d86d6c1d7 100644 --- a/tests/helpers/stubs.py +++ b/tests/helpers/stubs.py @@ -377,7 +377,9 @@ class FakeTimer(QObject): def isSingleShot(self): return self._singleshot - def start(self): + def start(self, interval=None): + if interval: + self._interval = interval self._started = True def stop(self): @@ -396,7 +398,7 @@ class InstaTimer(QObject): timeout = pyqtSignal() - def start(self): + def start(self, interval=None): self.timeout.emit() def setSingleShot(self, yes): From efef588c30102edc9673a01442fe8198c7858576 Mon Sep 17 00:00:00 2001 From: Joakim Reinert Date: Thu, 12 Oct 2017 14:43:22 +0200 Subject: [PATCH 15/99] fix lints in completer --- qutebrowser/completion/completer.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/qutebrowser/completion/completer.py b/qutebrowser/completion/completer.py index aa7f170a9..eaf74f959 100644 --- a/qutebrowser/completion/completer.py +++ b/qutebrowser/completion/completer.py @@ -201,8 +201,9 @@ class Completer(QObject): updates if the text is shorter than completion.min_chars (unless we're hitting backspace in which case updates won't be ignored). """ - cmd, _sep, rest = self._cmd.text().partition(' ') - if (0 < len(rest) < config.val.completion.min_chars and + _cmd, _sep, rest = self._cmd.text().partition(' ') + input_length = len(rest) + if (0 < input_length < config.val.completion.min_chars and self._cmd.cursorPosition() > self._last_cursor_pos): log.completion.debug("Ignoring update because the length of " "the text is less than completion.min_chars.") @@ -212,7 +213,8 @@ class Completer(QObject): "changes.") else: log.completion.debug("Scheduling completion update.") - self._timer.start(config.val.completion.delay if self._last_text else 0) + start_delay = config.val.completion.delay if self._last_text else 0 + self._timer.start(start_delay) self._last_cursor_pos = self._cmd.cursorPosition() self._last_text = self._cmd.text() From 69ced4e033dd9aac21e8a7ff7be9d13fbcee864a Mon Sep 17 00:00:00 2001 From: Ryan Roden-Corrent Date: Thu, 12 Oct 2017 11:51:03 -0400 Subject: [PATCH 16/99] Note how to ignore pylint in configuring doc. The doc explains how to ignore flake8 errors, but the `c` and `config` variables may also make pylint unhappy --- doc/help/configuring.asciidoc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/help/configuring.asciidoc b/doc/help/configuring.asciidoc index 9c350cbaf..f4996e16c 100644 --- a/doc/help/configuring.asciidoc +++ b/doc/help/configuring.asciidoc @@ -349,12 +349,13 @@ bind_chained('', 'clear-keychain', 'search') Avoiding flake8 errors ^^^^^^^^^^^^^^^^^^^^^^ -If you use an editor with flake8 integration which complains about `c` and `config` being undefined, you can use: +If you use an editor with flake8 and pylint integration which complains about +`c` and `config` being undefined or invalid, you can use: [source,python] ---- -c = c # noqa: F821 -config = config # noqa: F821 +c = c # noqa: F821 pylint: disable=invalid-name,undefined-variable +config = config # noqa: F821 pylint: disable=invalid-name,undefined-variable ---- For type annotation support (note that those imports aren't guaranteed to be From 0e527d2584ce26bcde565a6bea63585a0e05f073 Mon Sep 17 00:00:00 2001 From: Bryan Gilbert Date: Thu, 12 Oct 2017 12:11:00 -0400 Subject: [PATCH 17/99] Consistently space + center favicons when using vertical tabs --- qutebrowser/mainwindow/tabwidget.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py index c5566f877..f97188930 100644 --- a/qutebrowser/mainwindow/tabwidget.py +++ b/qutebrowser/mainwindow/tabwidget.py @@ -652,7 +652,7 @@ class TabBarStyle(QCommonStyle): icon_state = (QIcon.On if opt.state & QStyle.State_Selected else QIcon.Off) icon = opt.icon.pixmap(opt.iconSize, icon_mode, icon_state) - p.drawPixmap(layouts.icon.x(), layouts.icon.y(), icon) + p.drawItemPixmap(layouts.icon, Qt.AlignCenter, icon) def drawControl(self, element, opt, p, widget=None): """Override drawControl to draw odd tabs in a different color. @@ -819,8 +819,7 @@ class TabBarStyle(QCommonStyle): else QIcon.Off) # reserve space for favicon when tab bar is vertical (issue #1968) position = config.val.tabs.position - if (opt.icon.isNull() and - position in [QTabWidget.East, QTabWidget.West] and + if (position in [QTabWidget.East, QTabWidget.West] and config.val.tabs.favicons.show): tab_icon_size = icon_size else: @@ -828,6 +827,7 @@ class TabBarStyle(QCommonStyle): tab_icon_size = QSize( min(actual_size.width(), icon_size.width()), min(actual_size.height(), icon_size.height())) + icon_top = text_rect.center().y() + 1 - tab_icon_size.height() / 2 icon_rect = QRect(QPoint(text_rect.left(), icon_top), tab_icon_size) icon_rect = self._style.visualRect(opt.direction, opt.rect, icon_rect) From dde50c23bc8f387508e7d3fed6e7c84e3d226e1e Mon Sep 17 00:00:00 2001 From: Ryan Roden-Corrent Date: Fri, 13 Oct 2017 07:44:26 -0400 Subject: [PATCH 18/99] Fix up pylint notes in configuring.asciidoc. - Use short form of pylint disable - Update the following code block as well - Add pylint ignore for missing-module-docstring --- doc/help/configuring.asciidoc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/doc/help/configuring.asciidoc b/doc/help/configuring.asciidoc index f4996e16c..39a72201b 100644 --- a/doc/help/configuring.asciidoc +++ b/doc/help/configuring.asciidoc @@ -349,13 +349,15 @@ bind_chained('', 'clear-keychain', 'search') Avoiding flake8 errors ^^^^^^^^^^^^^^^^^^^^^^ -If you use an editor with flake8 and pylint integration which complains about -`c` and `config` being undefined or invalid, you can use: +If you use an editor with flake8 and pylint integration, it may have some +complaints about invalid names, undefined variables, or missing docstrings. +You can silence those with: [source,python] ---- -c = c # noqa: F821 pylint: disable=invalid-name,undefined-variable -config = config # noqa: F821 pylint: disable=invalid-name,undefined-variable +# pylint: disable=C0111 +c = c # noqa: F821 pylint: disable=E0602,C0103 +config = config # noqa: F821 pylint: disable=E0602,C0103 ---- For type annotation support (note that those imports aren't guaranteed to be @@ -363,8 +365,9 @@ stable across qutebrowser versions): [source,python] ---- +# pylint: disable=C0111 from qutebrowser.config.configfiles import ConfigAPI # noqa: F401 from qutebrowser.config.config import ConfigContainer # noqa: F401 -config = config # type: ConfigAPI # noqa: F821 -c = c # type: ConfigContainer # noqa: F821 +config = config # type: ConfigAPI # noqa: F821 pylint: disable=E0602,C0103 +c = c # type: ConfigContainer # noqa: F821 pylint: disable=E0602,C0103 ---- From ee3d7463f607126667ac8fe6d5a1248cab3e7967 Mon Sep 17 00:00:00 2001 From: Jay Kamat Date: Fri, 13 Oct 2017 21:33:03 -0400 Subject: [PATCH 19/99] Change qute:version git commit to display hash Replaces output of git-describe Closes #3095 --- qutebrowser/utils/version.py | 11 ++++++++--- tests/unit/utils/test_version.py | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/qutebrowser/utils/version.py b/qutebrowser/utils/version.py index 0f1b2233d..9cb770710 100644 --- a/qutebrowser/utils/version.py +++ b/qutebrowser/utils/version.py @@ -148,13 +148,18 @@ def _git_str_subprocess(gitpath): if not os.path.isdir(os.path.join(gitpath, ".git")): return None try: - cid = subprocess.check_output( - ['git', 'describe', '--tags', '--dirty', '--always'], + commit_hash = subprocess.check_output( + ['git', + 'describe', + '--match=NeVeRmAtCh', + '--always', + '--abbrev=40', + '--dirty'], cwd=gitpath).decode('UTF-8').strip() date = subprocess.check_output( ['git', 'show', '-s', '--format=%ci', 'HEAD'], cwd=gitpath).decode('UTF-8').strip() - return '{} ({})'.format(cid, date) + return '{} ({})'.format(commit_hash, date) except (subprocess.CalledProcessError, OSError): return None diff --git a/tests/unit/utils/test_version.py b/tests/unit/utils/test_version.py index 489806f8c..cfd8c06a6 100644 --- a/tests/unit/utils/test_version.py +++ b/tests/unit/utils/test_version.py @@ -356,7 +356,9 @@ class TestGitStrSubprocess: def test_real_git(self, git_repo): """Test with a real git repository.""" ret = version._git_str_subprocess(str(git_repo)) - assert ret == 'foobar (1970-01-01 01:00:00 +0100)' + assert ret == \ + '6e4b65a529c0ab78fb370c1527d5809f7436b8f3 ' \ + + '(1970-01-01 01:00:00 +0100)' def test_missing_dir(self, tmpdir): """Test with a directory which doesn't exist.""" From 4d2ca878ead78979af7de83dcf3b44a077bc6272 Mon Sep 17 00:00:00 2001 From: sMailund Date: Sat, 14 Oct 2017 10:26:55 +0200 Subject: [PATCH 20/99] add color configuration to passthrough mode --- qutebrowser/config/configdata.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 7e7f024f3..1acac8641 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -524,7 +524,6 @@ content.netrc_file: content.notifications: default: ask type: BoolAsk - backend: QtWebKit desc: Allow websites to show notifications. content.pdfjs: @@ -1504,6 +1503,16 @@ colors.completion.match.fg: type: QssColor desc: Foreground color of the matched text in the completion. +colors.statusbar.passthrough.fg: + default: white + type: QssColor + desc: Foreground color of the statusbar in passthrough mode. + +colors.statusbar.passthrough.bg: + default: darkblue + type: QssColor + desc: Background color of the statusbar in passthrough mode. + colors.completion.scrollbar.fg: default: white type: QssColor From 57c4285dbc9d2ba6e8a7e690a899dc77974bdf58 Mon Sep 17 00:00:00 2001 From: sMailund Date: Sat, 14 Oct 2017 10:29:34 +0200 Subject: [PATCH 21/99] configure colorflags for passthrough mode --- qutebrowser/mainwindow/statusbar/bar.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/qutebrowser/mainwindow/statusbar/bar.py b/qutebrowser/mainwindow/statusbar/bar.py index e8aacc935..e7a6256a2 100644 --- a/qutebrowser/mainwindow/statusbar/bar.py +++ b/qutebrowser/mainwindow/statusbar/bar.py @@ -43,6 +43,7 @@ class ColorFlags: command: If we're currently in command mode. mode: The current caret mode (CaretMode.off/.on/.selection). private: Whether this window is in private browsing mode. + passthrough: If we're currently in passthrough-mode """ CaretMode = usertypes.enum('CaretMode', ['off', 'on', 'selection']) @@ -51,6 +52,7 @@ class ColorFlags: command = attr.ib(False) caret = attr.ib(CaretMode.off) private = attr.ib(False) + passthrough = attr.ib(False) def to_stringlist(self): """Get a string list of set flags used in the stylesheet. @@ -66,6 +68,8 @@ class ColorFlags: strings.append('command') if self.private: strings.append('private') + if self.passthrough: + strings.append('passthrough') if self.private and self.command: strings.append('private-command') @@ -88,6 +92,7 @@ def _generate_stylesheet(): ('prompt', 'prompts'), ('insert', 'statusbar.insert'), ('command', 'statusbar.command'), + ('passthrough', 'statusbar.passthrough'), ('private-command', 'statusbar.command.private'), ] stylesheet = """ From 14005e368493963078631344668e218b082be025 Mon Sep 17 00:00:00 2001 From: sMailund Date: Sat, 14 Oct 2017 10:30:44 +0200 Subject: [PATCH 22/99] trigger color change on passthrough mode --- qutebrowser/mainwindow/statusbar/bar.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/qutebrowser/mainwindow/statusbar/bar.py b/qutebrowser/mainwindow/statusbar/bar.py index e7a6256a2..ec01fe89b 100644 --- a/qutebrowser/mainwindow/statusbar/bar.py +++ b/qutebrowser/mainwindow/statusbar/bar.py @@ -249,6 +249,9 @@ class StatusBar(QWidget): if mode == usertypes.KeyMode.insert: log.statusbar.debug("Setting insert flag to {}".format(val)) self._color_flags.insert = val + if mode == usertypes.KeyMode.passthrough: + log.statusbar.debug("Setting passthrough flag to {}".format(val)) + self._color_flags.passthrough = val if mode == usertypes.KeyMode.command: log.statusbar.debug("Setting command flag to {}".format(val)) self._color_flags.command = val @@ -312,7 +315,8 @@ class StatusBar(QWidget): usertypes.KeyMode.command, usertypes.KeyMode.caret, usertypes.KeyMode.prompt, - usertypes.KeyMode.yesno]: + usertypes.KeyMode.yesno, + usertypes.KeyMode.passthrough]: self.set_mode_active(mode, True) @pyqtSlot(usertypes.KeyMode, usertypes.KeyMode) @@ -329,7 +333,8 @@ class StatusBar(QWidget): usertypes.KeyMode.command, usertypes.KeyMode.caret, usertypes.KeyMode.prompt, - usertypes.KeyMode.yesno]: + usertypes.KeyMode.yesno, + usertypes.KeyMode.passthrough]: self.set_mode_active(old_mode, False) @pyqtSlot(browsertab.AbstractTab) From f5cccfb0977bdb2f3957a28b1f4ee91c921f4100 Mon Sep 17 00:00:00 2001 From: sMailund Date: Sat, 14 Oct 2017 10:43:34 +0200 Subject: [PATCH 23/99] re-add erroneously removed line --- qutebrowser/config/configdata.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 1acac8641..0ac82837b 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -524,6 +524,7 @@ content.netrc_file: content.notifications: default: ask type: BoolAsk + backend: QtWebKit desc: Allow websites to show notifications. content.pdfjs: From ffab9e263f6903315ef76261c006c39f37a9a84d Mon Sep 17 00:00:00 2001 From: Kimat Boven Date: Fri, 13 Oct 2017 22:44:02 +0200 Subject: [PATCH 24/99] it was not possible to show the current_url in tab or window title note that I couldn't use {url} as field for the FormatString --- doc/help/settings.asciidoc | 2 ++ qutebrowser/config/configdata.yml | 5 +++++ qutebrowser/mainwindow/tabwidget.py | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index 1973418ad..55f8af99a 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -2792,6 +2792,7 @@ The following placeholders are defined: * `{host}`: The host of the current web page. * `{backend}`: Either ''webkit'' or ''webengine'' * `{private}` : Indicates when private mode is enabled. +* `{current_url}` : The url of the current web page. Type: <> @@ -2928,6 +2929,7 @@ The following placeholders are defined: * `{host}`: The host of the current web page. * `{backend}`: Either ''webkit'' or ''webengine'' * `{private}` : Indicates when private mode is enabled. +* `{current_url}` : The url of the current web page. Type: <> diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 7e7f024f3..3cfc1ced5 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -1224,6 +1224,7 @@ tabs.title.format: - scroll_pos - host - private + - current_url none_ok: true desc: | The format to use for the tab title. @@ -1239,6 +1240,7 @@ tabs.title.format: * `{host}`: The host of the current web page. * `{backend}`: Either ''webkit'' or ''webengine'' * `{private}` : Indicates when private mode is enabled. + * `{current_url}` : The url of the current web page. tabs.title.format_pinned: default: '{index}' @@ -1254,6 +1256,7 @@ tabs.title.format_pinned: - scroll_pos - host - private + - current_url none_ok: true desc: The format to use for the tab title for pinned tabs. The same placeholders like for `tabs.title.format` are defined. @@ -1371,6 +1374,7 @@ window.title_format: - host - backend - private + - current_url default: '{perc}{title}{title_sep}qutebrowser' desc: | The format to use for the window title. @@ -1385,6 +1389,7 @@ window.title_format: * `{host}`: The host of the current web page. * `{backend}`: Either ''webkit'' or ''webengine'' * `{private}` : Indicates when private mode is enabled. + * `{current_url}` : The url of the current web page. ## zoom diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py index c5566f877..a8bc45cc0 100644 --- a/qutebrowser/mainwindow/tabwidget.py +++ b/qutebrowser/mainwindow/tabwidget.py @@ -164,6 +164,11 @@ class TabWidget(QTabWidget): except qtutils.QtValueError: fields['host'] = '' + try: + fields['current_url'] = self.tab_url(idx).url() + except qtutils.QtValueError: + fields['current_url'] = '' + y = tab.scroller.pos_perc()[1] if y is None: scroll_pos = '???' From 8ca0c87b1ffb0e7b3cf3906f1490b4b3a7123ed8 Mon Sep 17 00:00:00 2001 From: Kimat Boven Date: Sat, 14 Oct 2017 20:03:58 +0200 Subject: [PATCH 25/99] FakeUrl had no url --- tests/helpers/stubs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/helpers/stubs.py b/tests/helpers/stubs.py index 15d2ce8a0..1313649bc 100644 --- a/tests/helpers/stubs.py +++ b/tests/helpers/stubs.py @@ -131,10 +131,11 @@ class FakeUrl: """QUrl stub which provides .path(), isValid() and host().""" - def __init__(self, path=None, valid=True, host=None): + def __init__(self, path=None, valid=True, host=None, url=None): self.path = mock.Mock(return_value=path) self.isValid = mock.Mock(returl_value=valid) self.host = mock.Mock(returl_value=host) + self.url = mock.Mock(return_value=url) class FakeNetworkReply: From 4ff44eff7bb789cdde9db254f24feb92a8250c66 Mon Sep 17 00:00:00 2001 From: Jay Kamat Date: Sat, 14 Oct 2017 11:32:23 -0400 Subject: [PATCH 26/99] Clean up logic for finding git hash Also add implementation for release scripts as well --- qutebrowser/utils/version.py | 8 ++------ scripts/setupcommon.py | 7 ++++--- tests/unit/utils/test_version.py | 4 +--- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/qutebrowser/utils/version.py b/qutebrowser/utils/version.py index 9cb770710..4c31aa60d 100644 --- a/qutebrowser/utils/version.py +++ b/qutebrowser/utils/version.py @@ -148,13 +148,9 @@ def _git_str_subprocess(gitpath): if not os.path.isdir(os.path.join(gitpath, ".git")): return None try: + # https://stackoverflow.com/questions/21017300/21017394#21017394 commit_hash = subprocess.check_output( - ['git', - 'describe', - '--match=NeVeRmAtCh', - '--always', - '--abbrev=40', - '--dirty'], + ['git', 'describe', '--match=NeVeRmAtCh', '--always', '--dirty'], cwd=gitpath).decode('UTF-8').strip() date = subprocess.check_output( ['git', 'show', '-s', '--format=%ci', 'HEAD'], diff --git a/scripts/setupcommon.py b/scripts/setupcommon.py index a2e4dfca9..1f85b225f 100644 --- a/scripts/setupcommon.py +++ b/scripts/setupcommon.py @@ -50,13 +50,14 @@ def _git_str(): if not os.path.isdir(os.path.join(BASEDIR, ".git")): return None try: - cid = subprocess.check_output( - ['git', 'describe', '--tags', '--dirty', '--always'], + # https://stackoverflow.com/questions/21017300/21017394#21017394 + commit_hash = subprocess.check_output( + ['git', 'describe', '--match=NeVeRmAtCh', '--always', '--dirty'], cwd=BASEDIR).decode('UTF-8').strip() date = subprocess.check_output( ['git', 'show', '-s', '--format=%ci', 'HEAD'], cwd=BASEDIR).decode('UTF-8').strip() - return '{} ({})'.format(cid, date) + return '{} ({})'.format(commit_hash, date) except (subprocess.CalledProcessError, OSError): return None diff --git a/tests/unit/utils/test_version.py b/tests/unit/utils/test_version.py index cfd8c06a6..9db7603e3 100644 --- a/tests/unit/utils/test_version.py +++ b/tests/unit/utils/test_version.py @@ -356,9 +356,7 @@ class TestGitStrSubprocess: def test_real_git(self, git_repo): """Test with a real git repository.""" ret = version._git_str_subprocess(str(git_repo)) - assert ret == \ - '6e4b65a529c0ab78fb370c1527d5809f7436b8f3 ' \ - + '(1970-01-01 01:00:00 +0100)' + assert ret == '6e4b65a (1970-01-01 01:00:00 +0100)' def test_missing_dir(self, tmpdir): """Test with a directory which doesn't exist.""" From 71f48a1e30a8cba319b8218b213bf73675c3ad6c Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 15 Oct 2017 00:21:35 +0200 Subject: [PATCH 27/99] Move statusbar colors together in configdata.yml --- qutebrowser/config/configdata.yml | 40 +++++++++++++++---------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 941135d22..2a8c4c32b 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -1469,16 +1469,6 @@ colors.completion.category.border.bottom: type: QssColor desc: Bottom border color of the completion widget category headers. -colors.statusbar.insert.fg: - default: white - type: QssColor - desc: Foreground color of the statusbar in insert mode. - -colors.statusbar.insert.bg: - default: darkgreen - type: QssColor - desc: Background color of the statusbar in insert mode. - colors.completion.item.selected.fg: default: black type: QtColor @@ -1504,16 +1494,6 @@ colors.completion.match.fg: type: QssColor desc: Foreground color of the matched text in the completion. -colors.statusbar.passthrough.fg: - default: white - type: QssColor - desc: Foreground color of the statusbar in passthrough mode. - -colors.statusbar.passthrough.bg: - default: darkblue - type: QssColor - desc: Background color of the statusbar in passthrough mode. - colors.completion.scrollbar.fg: default: white type: QssColor @@ -1678,6 +1658,26 @@ colors.statusbar.normal.bg: type: QssColor desc: Background color of the statusbar. +colors.statusbar.insert.fg: + default: white + type: QssColor + desc: Foreground color of the statusbar in insert mode. + +colors.statusbar.insert.bg: + default: darkgreen + type: QssColor + desc: Background color of the statusbar in insert mode. + +colors.statusbar.passthrough.fg: + default: white + type: QssColor + desc: Foreground color of the statusbar in passthrough mode. + +colors.statusbar.passthrough.bg: + default: darkblue + type: QssColor + desc: Background color of the statusbar in passthrough mode. + colors.statusbar.private.fg: default: white type: QssColor From e3a305a81455299078b5c094b16e23125228501b Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 15 Oct 2017 00:21:56 +0200 Subject: [PATCH 28/99] Regenerate docs --- doc/help/settings.asciidoc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index 1973418ad..9bf058c96 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -70,6 +70,8 @@ |<>|Foreground color of the statusbar in insert mode. |<>|Background color of the statusbar. |<>|Foreground color of the statusbar. +|<>|Background color of the statusbar in passthrough mode. +|<>|Foreground color of the statusbar in passthrough mode. |<>|Background color of the statusbar in private browsing mode. |<>|Foreground color of the statusbar in private browsing mode. |<>|Background color of the progress bar. @@ -1093,6 +1095,22 @@ Type: <> Default: +pass:[white]+ +[[colors.statusbar.passthrough.bg]] +=== colors.statusbar.passthrough.bg +Background color of the statusbar in passthrough mode. + +Type: <> + +Default: +pass:[darkblue]+ + +[[colors.statusbar.passthrough.fg]] +=== colors.statusbar.passthrough.fg +Foreground color of the statusbar in passthrough mode. + +Type: <> + +Default: +pass:[white]+ + [[colors.statusbar.private.bg]] === colors.statusbar.private.bg Background color of the statusbar in private browsing mode. From f4796b5ec61663453953e5482de74f6b21f78858 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 15 Oct 2017 00:22:19 +0200 Subject: [PATCH 29/99] Add missing period --- qutebrowser/mainwindow/statusbar/bar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/mainwindow/statusbar/bar.py b/qutebrowser/mainwindow/statusbar/bar.py index ec01fe89b..da18deae8 100644 --- a/qutebrowser/mainwindow/statusbar/bar.py +++ b/qutebrowser/mainwindow/statusbar/bar.py @@ -43,7 +43,7 @@ class ColorFlags: command: If we're currently in command mode. mode: The current caret mode (CaretMode.off/.on/.selection). private: Whether this window is in private browsing mode. - passthrough: If we're currently in passthrough-mode + passthrough: If we're currently in passthrough-mode. """ CaretMode = usertypes.enum('CaretMode', ['off', 'on', 'selection']) From 2eba2cc8f5abf5bbefbbf526d150e326018b4faa Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 15 Oct 2017 00:26:26 +0200 Subject: [PATCH 30/99] Skip another history test on AppVeyor --- tests/end2end/features/history.feature | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/end2end/features/history.feature b/tests/end2end/features/history.feature index ca5adbb97..69af64941 100644 --- a/tests/end2end/features/history.feature +++ b/tests/end2end/features/history.feature @@ -99,6 +99,8 @@ Feature: Page history Then the page should contain the plaintext "3.txt" Then the page should contain the plaintext "4.txt" + # Hangs a lot on AppVeyor + @posix Scenario: Listing history with qute:history redirect When I open data/numbers/3.txt And I open data/numbers/4.txt From af3c9a2b9ecb2cee519ed58b80230e44e875c16f Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 15 Oct 2017 00:29:45 +0200 Subject: [PATCH 31/99] Update changelog --- doc/changelog.asciidoc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 00281d562..931dd8fd3 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -15,10 +15,19 @@ breaking changes (such as renamed commands) can happen in minor releases. // `Fixed` for any bug fixes. // `Security` to invite users to upgrade in case of vulnerabilities. +v1.1.0 (unreleased) +------------------- + +Added +~~~~~ + +- New `{current_url}` field for `window.title_format` and `tabs.title.format`. +- New `colors.statusbar.passthrough.fg`/`.bg` settings. + v1.0.2 (unreleased) ------------------- -Fixes +Fixed ~~~~~ - Fixed workaround for black screens with Nvidia cards @@ -27,7 +36,7 @@ Fixes v1.0.1 ------ -Fixes +Fixed ~~~~~ - Fixed starting after customizing `fonts.tabs` or `fonts.debug_console`. From 392ea8825bb31e6888557df4c9ee18af5e4b7329 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 15 Oct 2017 12:21:14 +0200 Subject: [PATCH 32/99] Clarify completion keybinding changes See #3125 [ci skip] --- doc/changelog.asciidoc | 3 +++ doc/help/configuring.asciidoc | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 931dd8fd3..5a48959bd 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -74,6 +74,9 @@ Major changes the entire browsing history. The default for `completion.web_history_max_items` got changed to `-1` (unlimited). If the completion is too slow on your machine, try setting it to a few 1000 items. +- Up/Down now navigates through the command history instead of selecting + completion items. Either use Tab to cycle through the completion, or + https://github.com/qutebrowser/qutebrowser/blob/master/doc/help/configuring.asciidoc#migrating-older-configurations[restore the old behavior]. Added ~~~~~ diff --git a/doc/help/configuring.asciidoc b/doc/help/configuring.asciidoc index 39a72201b..997e47246 100644 --- a/doc/help/configuring.asciidoc +++ b/doc/help/configuring.asciidoc @@ -18,8 +18,9 @@ the old defaults. Other changes in default settings: - `` and `` in the completion now navigate through command history - instead of selecting completion items. You can get back the old behavior by - doing: + instead of selecting completion items. Use ``/`` to cycle + through the completion instead. + You can get back the old behavior by doing: + ---- :bind -f -m command completion-item-focus prev From e90a5f509e1745f33095882d30570924e8512e5b Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 15 Oct 2017 12:25:57 +0200 Subject: [PATCH 33/99] Improve install docs [ci skip] --- doc/install.asciidoc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/install.asciidoc b/doc/install.asciidoc index de6e9f2f2..15e3ac93e 100644 --- a/doc/install.asciidoc +++ b/doc/install.asciidoc @@ -221,6 +221,10 @@ https://lists.schokokeks.org/mailman/listinfo.cgi/qutebrowser-announce[qutebrows mailinglist] to get notified on new releases). You can install a newer version without uninstalling the older one. +The binary release ships with a QtWebEngine built without proprietary codec +support. To get support for e.g. h264/h265 videos, you'll need to build +QtWebEngine from source yourself with support for that enabled. + https://chocolatey.org/packages/qutebrowser[Chocolatey package] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -261,6 +265,10 @@ Note that you'll need to upgrade to new versions manually (subscribe to the https://lists.schokokeks.org/mailman/listinfo.cgi/qutebrowser-announce[qutebrowser-announce mailinglist] to get notified on new releases). +The binary release ships with a QtWebEngine built without proprietary codec +support. To get support for e.g. h264/h265 videos, you'll need to build +QtWebEngine from source yourself with support for that enabled. + This binary is also available through the https://caskroom.github.io/[Homebrew Cask] package manager: @@ -355,6 +363,18 @@ also typically means you'll be using an older release of QtWebEngine. On Windows, run `tox -e 'mkvenv-win' instead, however make sure that ONLY Python3 is in your PATH before running tox. +Building the docs +~~~~~~~~~~~~~~~~~ + +To build the documentation, install `asciidoc` (note that LaTeX which comes as +optional/recommended dependency with some distributions is not required). + +Then, run: + +---- +$ python3 scripts/asciidoc2html.py +---- + Creating a wrapper script ~~~~~~~~~~~~~~~~~~~~~~~~~ From fa4a66f7b38ed038e11f74011c796e2577b3f005 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 15 Oct 2017 21:09:37 +0200 Subject: [PATCH 34/99] Add SQLITE_READONLY to environmental errors --- doc/changelog.asciidoc | 1 + qutebrowser/misc/sql.py | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 5a48959bd..7eecf3b82 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -32,6 +32,7 @@ Fixed - Fixed workaround for black screens with Nvidia cards - Mark the content.notifications setting as QtWebKit only correctly +- Handle a filesystem going read-only gracefully v1.0.1 ------ diff --git a/qutebrowser/misc/sql.py b/qutebrowser/misc/sql.py index 5b0d3361d..e04c3f6e3 100644 --- a/qutebrowser/misc/sql.py +++ b/qutebrowser/misc/sql.py @@ -65,13 +65,12 @@ class SqliteError(SqlError): log.sql.debug("error code: {}".format(error.nativeErrorCode())) # https://sqlite.org/rescode.html + # https://github.com/qutebrowser/qutebrowser/issues/2930 + # https://github.com/qutebrowser/qutebrowser/issues/3004 environmental_errors = [ - # SQLITE_LOCKED, - # https://github.com/qutebrowser/qutebrowser/issues/2930 - '9', - # SQLITE_FULL, - # https://github.com/qutebrowser/qutebrowser/issues/3004 - '13', + '8', # SQLITE_READONLY + '9', # SQLITE_LOCKED, + '13', # SQLITE_FULL, ] self.environmental = error.nativeErrorCode() in environmental_errors From e003b116704a12b01c65af442af6060df5d9c0a4 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 15 Oct 2017 22:30:17 +0200 Subject: [PATCH 35/99] Fix overflow handling for QtWebKit scrolling If we do "m * val / 100", the value gets bigger, so we need to check for an overflow afterwards. --- qutebrowser/browser/webkit/webkittab.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/qutebrowser/browser/webkit/webkittab.py b/qutebrowser/browser/webkit/webkittab.py index 43a38ea61..43bec3456 100644 --- a/qutebrowser/browser/webkit/webkittab.py +++ b/qutebrowser/browser/webkit/webkittab.py @@ -422,12 +422,13 @@ class WebKitScroller(browsertab.AbstractScroller): else: for val, orientation in [(x, Qt.Horizontal), (y, Qt.Vertical)]: if val is not None: - val = qtutils.check_overflow(val, 'int', fatal=False) frame = self._widget.page().mainFrame() - m = frame.scrollBarMaximum(orientation) - if m == 0: + maximum = frame.scrollBarMaximum(orientation) + if maximum == 0: continue - frame.setScrollBarValue(orientation, int(m * val / 100)) + pos = int(maximum * val / 100) + pos = qtutils.check_overflow(pos, 'int', fatal=False) + frame.setScrollBarValue(orientation, pos) def _key_press(self, key, count=1, getter_name=None, direction=None): frame = self._widget.page().mainFrame() From 2a65cadb67ec8ec1792e5e6f90b770ae82e6b221 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 16 Oct 2017 06:18:09 +0200 Subject: [PATCH 36/99] Fix setting monospace fonts with None values Fixes #3130 --- qutebrowser/config/configinit.py | 4 +++- tests/unit/config/test_configinit.py | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/qutebrowser/config/configinit.py b/qutebrowser/config/configinit.py index c76efba00..027aedb04 100644 --- a/qutebrowser/config/configinit.py +++ b/qutebrowser/config/configinit.py @@ -104,7 +104,9 @@ def _update_monospace_fonts(): continue elif not isinstance(opt.typ, configtypes.Font): continue - elif not config.instance.get_obj(name).endswith(' monospace'): + + value = config.instance.get_obj(name) + if value is None or not value.endswith(' monospace'): continue config.instance.changed.emit(name) diff --git a/tests/unit/config/test_configinit.py b/tests/unit/config/test_configinit.py index 820b03a38..1501b794d 100644 --- a/tests/unit/config/test_configinit.py +++ b/tests/unit/config/test_configinit.py @@ -258,6 +258,15 @@ class TestEarlyInit: # Font subclass, but doesn't end with "monospace" assert 'fonts.web.family.standard' not in changed_options + def test_setting_monospace_fonts_family(self, init_patch, args): + """Make sure setting fonts.monospace after a family works. + + See https://github.com/qutebrowser/qutebrowser/issues/3130 + """ + configinit.early_init(args) + config.instance.set_str('fonts.web.family.standard', '') + config.instance.set_str('fonts.monospace', 'Terminus') + def test_force_software_rendering(self, monkeypatch, config_stub): """Setting force_software_rendering should set the environment var.""" envvar = 'QT_XCB_FORCE_SOFTWARE_OPENGL' From 09868c1e7fb091ae51bdb6c242f692f3095f23ef Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 16 Oct 2017 08:17:45 +0200 Subject: [PATCH 37/99] Update docs --- doc/changelog.asciidoc | 2 ++ doc/help/settings.asciidoc | 18 ++++++++++++++++++ qutebrowser/config/configdata.yml | 4 ++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 7eecf3b82..cccc7bb22 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -23,6 +23,8 @@ Added - New `{current_url}` field for `window.title_format` and `tabs.title.format`. - New `colors.statusbar.passthrough.fg`/`.bg` settings. +- New `completion.delay` and `completion.min_chars` settings to update the + completion less often. v1.0.2 (unreleased) ------------------- diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index f9a5aaeb0..7678583b7 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -96,7 +96,9 @@ |<>|Foreground color of selected odd tabs. |<>|Background color for webpages if unset (or empty to use the theme's color) |<>|How many commands to save in the command history. +|<>|Delay in ms before updating completions after typing a character. |<>|The height of the completion, in px or as percentage of the window. +|<>|Minimum amount of characters needed to update completions. |<>|Move on to the next part when there's only one possible completion left. |<>|Padding of scrollbar handle in the completion window (in px). |<>|Width of the scrollbar in the completion window (in px). @@ -1311,6 +1313,14 @@ Type: <> Default: +pass:[100]+ +[[completion.delay]] +=== completion.delay +Delay in ms before updating completions after typing a character. + +Type: <> + +Default: +pass:[0]+ + [[completion.height]] === completion.height The height of the completion, in px or as percentage of the window. @@ -1319,6 +1329,14 @@ Type: <> Default: +pass:[50%]+ +[[completion.min_chars]] +=== completion.min_chars +Minimum amount of characters needed to update completions. + +Type: <> + +Default: +pass:[1]+ + [[completion.quick]] === completion.quick Move on to the next part when there's only one possible completion left. diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 700dd4ddd..44c405a2f 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -683,14 +683,14 @@ completion.delay: type: name: Int minval: 0 - desc: Delay in ms before updating completions after typing a character + desc: Delay in ms before updating completions after typing a character. completion.min_chars: default: 1 type: name: Int minval: 1 - desc: Minimum amount of characters needed to update completions + desc: Minimum amount of characters needed to update completions. ## downloads From caeab959a52369968767e377f3795bd41a11c2cf Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 16 Oct 2017 08:32:11 +0200 Subject: [PATCH 38/99] Update changelog --- doc/changelog.asciidoc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index cccc7bb22..14a9379e7 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -26,6 +26,11 @@ Added - New `completion.delay` and `completion.min_chars` settings to update the completion less often. +Fixed +~~~~~ + +- More consistent sizing for favicons with vertical tabs. + v1.0.2 (unreleased) ------------------- From 5307b97ca587696981f61b863fa951780f76f776 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 16 Oct 2017 09:24:31 +0200 Subject: [PATCH 39/99] Improve checkpyver error message --- qutebrowser/misc/checkpyver.py | 2 +- tests/unit/misc/test_checkpyver.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/qutebrowser/misc/checkpyver.py b/qutebrowser/misc/checkpyver.py index fc3dde673..d4ea13bcd 100644 --- a/qutebrowser/misc/checkpyver.py +++ b/qutebrowser/misc/checkpyver.py @@ -49,7 +49,7 @@ def check_python_version(): # pylint: disable=bad-builtin version_str = '.'.join(map(str, sys.version_info[:3])) text = ("At least Python 3.5 is required to run qutebrowser, but " + - version_str + " is installed!\n") + "it's running with " + version_str + ".\n") if Tk and '--no-err-windows' not in sys.argv: # pragma: no cover root = Tk() root.withdraw() diff --git a/tests/unit/misc/test_checkpyver.py b/tests/unit/misc/test_checkpyver.py index a25e1d187..8864a63a6 100644 --- a/tests/unit/misc/test_checkpyver.py +++ b/tests/unit/misc/test_checkpyver.py @@ -28,8 +28,8 @@ import pytest from qutebrowser.misc import checkpyver -TEXT = (r"At least Python 3.5 is required to run qutebrowser, but " - r"\d+\.\d+\.\d+ is installed!\n") +TEXT = (r"At least Python 3.5 is required to run qutebrowser, but it's running " + r"with \d+\.\d+\.\d+.\n") @pytest.mark.not_frozen From 7adab9ec78ad2ee531870c086a06a472e1bb33b3 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 16 Oct 2017 09:58:44 +0200 Subject: [PATCH 40/99] Fix long line --- tests/unit/misc/test_checkpyver.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/misc/test_checkpyver.py b/tests/unit/misc/test_checkpyver.py index 8864a63a6..c5fa83a48 100644 --- a/tests/unit/misc/test_checkpyver.py +++ b/tests/unit/misc/test_checkpyver.py @@ -28,8 +28,8 @@ import pytest from qutebrowser.misc import checkpyver -TEXT = (r"At least Python 3.5 is required to run qutebrowser, but it's running " - r"with \d+\.\d+\.\d+.\n") +TEXT = (r"At least Python 3.5 is required to run qutebrowser, but it's " + r"running with \d+\.\d+\.\d+.\n") @pytest.mark.not_frozen From e766fe14fcde6769f50e02f822b0d788266acc3f Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 16 Oct 2017 12:27:13 +0200 Subject: [PATCH 41/99] Fix HTML escaping in completion --- doc/changelog.asciidoc | 1 + qutebrowser/completion/completiondelegate.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 14a9379e7..3e2aeeb12 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -40,6 +40,7 @@ Fixed - Fixed workaround for black screens with Nvidia cards - Mark the content.notifications setting as QtWebKit only correctly - Handle a filesystem going read-only gracefully +- Fix wrong rendering of keys like `` in the completion v1.0.1 ------ diff --git a/qutebrowser/completion/completiondelegate.py b/qutebrowser/completion/completiondelegate.py index 8248b3745..6688a2dfa 100644 --- a/qutebrowser/completion/completiondelegate.py +++ b/qutebrowser/completion/completiondelegate.py @@ -202,7 +202,8 @@ class CompletionItemDelegate(QStyledItemDelegate): if index.column() in columns_to_filter and pattern: repl = r'\g<0>' text = re.sub(re.escape(pattern).replace(r'\ ', r'|'), - repl, self._opt.text, flags=re.IGNORECASE) + repl, html.escape(self._opt.text), + flags=re.IGNORECASE) self._doc.setHtml(text) else: self._doc.setPlainText(self._opt.text) From e89fda189ae5fa3ead1e9d37fb593bf507bfd6dd Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 16 Oct 2017 13:44:51 +0200 Subject: [PATCH 42/99] Fix tab sizing when we get a QPainter and not a QStylePainter I'm not sure yet how that happens, but I got a crash report for that. See #3099 --- qutebrowser/mainwindow/tabwidget.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py index b0786a3b7..56cb922f8 100644 --- a/qutebrowser/mainwindow/tabwidget.py +++ b/qutebrowser/mainwindow/tabwidget.py @@ -657,7 +657,7 @@ class TabBarStyle(QCommonStyle): icon_state = (QIcon.On if opt.state & QStyle.State_Selected else QIcon.Off) icon = opt.icon.pixmap(opt.iconSize, icon_mode, icon_state) - p.drawItemPixmap(layouts.icon, Qt.AlignCenter, icon) + self._style.drawItemPixmap(p, layouts.icon, Qt.AlignCenter, icon) def drawControl(self, element, opt, p, widget=None): """Override drawControl to draw odd tabs in a different color. From dd70019d4ccd4e7b4b3a51820fe2253f700a41b7 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Mon, 16 Oct 2017 16:53:13 +0200 Subject: [PATCH 43/99] Update setuptools from 36.5.0 to 36.6.0 --- misc/requirements/requirements-pip.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/requirements/requirements-pip.txt b/misc/requirements/requirements-pip.txt index b8d75bcc1..b643e0667 100644 --- a/misc/requirements/requirements-pip.txt +++ b/misc/requirements/requirements-pip.txt @@ -3,6 +3,6 @@ appdirs==1.4.3 packaging==16.8 pyparsing==2.2.0 -setuptools==36.5.0 +setuptools==36.6.0 six==1.11.0 wheel==0.30.0 From eec129807e0a8f0cbff8aac1b37d0020b2d44f76 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Mon, 16 Oct 2017 16:53:15 +0200 Subject: [PATCH 44/99] Update hypothesis from 3.32.0 to 3.33.0 --- misc/requirements/requirements-tests.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/requirements/requirements-tests.txt b/misc/requirements/requirements-tests.txt index 9cd025e4e..1bacf0cfc 100644 --- a/misc/requirements/requirements-tests.txt +++ b/misc/requirements/requirements-tests.txt @@ -11,7 +11,7 @@ fields==5.0.0 Flask==0.12.2 glob2==0.6 hunter==2.0.1 -hypothesis==3.32.0 +hypothesis==3.33.0 itsdangerous==0.24 # Jinja2==2.9.6 Mako==1.0.7 From 039edd8d85b8830c4bcc1ea03b41353d0952e756 Mon Sep 17 00:00:00 2001 From: suve Date: Mon, 16 Oct 2017 21:32:53 +0200 Subject: [PATCH 45/99] Add a basic appdata.xml file --- misc/qutebrowser.appdata.xml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 misc/qutebrowser.appdata.xml diff --git a/misc/qutebrowser.appdata.xml b/misc/qutebrowser.appdata.xml new file mode 100644 index 000000000..7a3260226 --- /dev/null +++ b/misc/qutebrowser.appdata.xml @@ -0,0 +1,33 @@ + + + + qutebrowser.desktop + CC-BY-SA-3.0 + GPL-3.0 + qutebrowser + A keyboard-driven web browser + +

+ qutebrowser is a keyboard-focused browser with a minimal GUI. + It was inspired by other browsers/addons like dwb and Vimperator/Pentadactyl, + and is based on Python and PyQt5. +

+
+ + + https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/main.png + + + https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/downloads.png + + + https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/completion.png + + + https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/hints.png + + + https://www.qutebrowser.org/ +
+ + From 1d5d6acdeacd330936676e3fad7b9fb304b5ed67 Mon Sep 17 00:00:00 2001 From: suve Date: Mon, 16 Oct 2017 21:34:08 +0200 Subject: [PATCH 46/99] Add info to appdata.xml --- misc/qutebrowser.appdata.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/misc/qutebrowser.appdata.xml b/misc/qutebrowser.appdata.xml index 7a3260226..5aaa013bb 100644 --- a/misc/qutebrowser.appdata.xml +++ b/misc/qutebrowser.appdata.xml @@ -13,6 +13,7 @@ and is based on Python and PyQt5.

+ qutebrowser.desktop https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/main.png From a76fdfe205229d124c6fab8af9c89a71fcd43d7d Mon Sep 17 00:00:00 2001 From: suve Date: Mon, 16 Oct 2017 21:55:24 +0200 Subject: [PATCH 47/99] Add more URLs to appdata file --- misc/qutebrowser.appdata.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/misc/qutebrowser.appdata.xml b/misc/qutebrowser.appdata.xml index 5aaa013bb..a70f55112 100644 --- a/misc/qutebrowser.appdata.xml +++ b/misc/qutebrowser.appdata.xml @@ -28,7 +28,9 @@ https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/hints.png - https://www.qutebrowser.org/ + https://www.qutebrowser.org + https://github.com/qutebrowser/qutebrowser/issues/ + https://github.com/qutebrowser/qutebrowser#donating From 3084e7be029195b50a57e6a8fccdd6087451078e Mon Sep 17 00:00:00 2001 From: suve Date: Mon, 16 Oct 2017 21:57:10 +0200 Subject: [PATCH 48/99] Add to appdata.xml file --- misc/qutebrowser.appdata.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/misc/qutebrowser.appdata.xml b/misc/qutebrowser.appdata.xml index a70f55112..f52db9e9a 100644 --- a/misc/qutebrowser.appdata.xml +++ b/misc/qutebrowser.appdata.xml @@ -13,6 +13,10 @@ and is based on Python and PyQt5.

+ + Network + WebBrowser + qutebrowser.desktop From 18776456f3e9d78581ba44af5d241cd4f1771183 Mon Sep 17 00:00:00 2001 From: suve Date: Mon, 16 Oct 2017 21:58:24 +0200 Subject: [PATCH 49/99] Add to appdata.xml file --- misc/qutebrowser.appdata.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/misc/qutebrowser.appdata.xml b/misc/qutebrowser.appdata.xml index f52db9e9a..3f9923cc8 100644 --- a/misc/qutebrowser.appdata.xml +++ b/misc/qutebrowser.appdata.xml @@ -17,6 +17,9 @@ Network WebBrowser
+ + qutebrowser + qutebrowser.desktop From 30f7f7b03c8555954ebbabf0d559b1f41442386b Mon Sep 17 00:00:00 2001 From: suve Date: Mon, 16 Oct 2017 22:05:07 +0200 Subject: [PATCH 50/99] Change in appdata.xml to match the {tld}.{vendor}.{product} scheme --- misc/qutebrowser.appdata.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/qutebrowser.appdata.xml b/misc/qutebrowser.appdata.xml index 3f9923cc8..e72850100 100644 --- a/misc/qutebrowser.appdata.xml +++ b/misc/qutebrowser.appdata.xml @@ -1,7 +1,7 @@ - qutebrowser.desktop + org.qutebrowser.qutebrowser.desktop CC-BY-SA-3.0 GPL-3.0 qutebrowser From 914d72a2160c575ef8085cdf5f250c738ea5127f Mon Sep 17 00:00:00 2001 From: suve Date: Mon, 16 Oct 2017 22:26:46 +0200 Subject: [PATCH 51/99] Remove the .desktop suffix from in appdata.xml This used to be required by the standard, but is no longer the case. --- misc/qutebrowser.appdata.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/qutebrowser.appdata.xml b/misc/qutebrowser.appdata.xml index e72850100..8684beecc 100644 --- a/misc/qutebrowser.appdata.xml +++ b/misc/qutebrowser.appdata.xml @@ -1,7 +1,7 @@ - org.qutebrowser.qutebrowser.desktop + org.qutebrowser.qutebrowser CC-BY-SA-3.0 GPL-3.0 qutebrowser From 2ad7bafcdffaede36b26de47651483f964aaf82d Mon Sep 17 00:00:00 2001 From: suve Date: Mon, 16 Oct 2017 22:30:51 +0200 Subject: [PATCH 52/99] Add "faq" and "help" links in appdata.xml file --- misc/qutebrowser.appdata.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/misc/qutebrowser.appdata.xml b/misc/qutebrowser.appdata.xml index 8684beecc..ba333702f 100644 --- a/misc/qutebrowser.appdata.xml +++ b/misc/qutebrowser.appdata.xml @@ -36,6 +36,8 @@ https://www.qutebrowser.org + https://qutebrowser.org/doc/faq.html + https://qutebrowser.org/doc/help/ https://github.com/qutebrowser/qutebrowser/issues/ https://github.com/qutebrowser/qutebrowser#donating From 8acd014d39acce2643f206bd8cbeda816f9c0c81 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 16 Oct 2017 15:54:18 +0200 Subject: [PATCH 53/99] Ignore new Qt 5.10 debug build messages --- tests/end2end/fixtures/quteprocess.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/end2end/fixtures/quteprocess.py b/tests/end2end/fixtures/quteprocess.py index 8a976ba96..4f5f3a572 100644 --- a/tests/end2end/fixtures/quteprocess.py +++ b/tests/end2end/fixtures/quteprocess.py @@ -105,6 +105,12 @@ def is_ignored_lowlevel_message(message): elif (message.startswith('QNetworkProxyFactory: factory 0x') and message.endswith(' has returned an empty result set')): return True + elif message == ' Error: No such file or directory': + # Qt 5.10 with debug Chromium + # [1016/155149.941048:WARNING:stack_trace_posix.cc(625)] Failed to open + # file: /home/florian/#14687139 (deleted) + # Error: No such file or directory + return True return False @@ -170,6 +176,12 @@ def is_ignored_chromium_message(line): # WebFrame LEAKED 1 TIMES 'WebFrame LEAKED 1 TIMES', + # Qt 5.10 with debug Chromium + # [1016/155149.941048:WARNING:stack_trace_posix.cc(625)] Failed to open + # file: /home/florian/#14687139 (deleted) + # Error: No such file or directory + 'Failed to open file: * (deleted)', + # macOS on Travis # [5140:5379:0911/063441.239771:ERROR:mach_port_broker.mm(175)] # Unknown process 5176 is sending Mach IPC messages! From 544c508fac0e955ef66b19e9a8d08c8451370890 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 06:22:40 +0200 Subject: [PATCH 54/99] Add standardpaths_tester.py --- scripts/dev/standardpaths_tester.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 scripts/dev/standardpaths_tester.py diff --git a/scripts/dev/standardpaths_tester.py b/scripts/dev/standardpaths_tester.py new file mode 100644 index 000000000..e9bdd6e4c --- /dev/null +++ b/scripts/dev/standardpaths_tester.py @@ -0,0 +1,18 @@ +import os +import sys + +from PyQt5.QtCore import (QT_VERSION_STR, PYQT_VERSION_STR, qVersion, + QStandardPaths) + +print("Python {}".format(sys.version)) +print("os.name: {}".format(os.name)) +print("sys.platform: {}".format(sys.platform)) +print() + +print("Qt {}, compiled {}".format(qVersion(), QT_VERSION_STR)) +print("PyQt {}".format(PYQT_VERSION_STR)) +print() + +for name, obj in vars(QStandardPaths).items(): + if isinstance(obj, QStandardPaths.StandardLocation): + print("{:25} {}".format(name, QStandardPaths.writableLocation(obj))) From d8384ced0a958e9841dfbb7f7b0d75f1f8c92f19 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 06:26:42 +0200 Subject: [PATCH 55/99] Show better error message when trying to toggle with :set --- doc/changelog.asciidoc | 5 +++++ qutebrowser/config/configcommands.py | 4 ++++ tests/unit/config/test_configcommands.py | 14 ++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 3e2aeeb12..f0af67b97 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -42,6 +42,11 @@ Fixed - Handle a filesystem going read-only gracefully - Fix wrong rendering of keys like `` in the completion +Changed +~~~~~~~ + +- Nicer error messages and other minor improvements + v1.0.1 ------ diff --git a/qutebrowser/config/configcommands.py b/qutebrowser/config/configcommands.py index 5848c9680..340175f23 100644 --- a/qutebrowser/config/configcommands.py +++ b/qutebrowser/config/configcommands.py @@ -75,6 +75,10 @@ class ConfigCommands: tabbed_browser.openurl(QUrl('qute://settings'), newtab=False) return + if option.endswith('!'): + raise cmdexc.CommandError("Toggling values was moved to the " + ":config-cycle command") + if option.endswith('?') and option != '?': self._print_value(option[:-1]) return diff --git a/tests/unit/config/test_configcommands.py b/tests/unit/config/test_configcommands.py index 1841e6260..c33bb54d4 100644 --- a/tests/unit/config/test_configcommands.py +++ b/tests/unit/config/test_configcommands.py @@ -133,9 +133,9 @@ class TestSet: "QtWebEngine backend!"): commands.set(0, 'content.cookies.accept', 'all') - @pytest.mark.parametrize('option', ['?', '!', 'url.auto_search']) + @pytest.mark.parametrize('option', ['?', 'url.auto_search']) def test_empty(self, commands, option): - """Run ':set ?' / ':set !' / ':set url.auto_search'. + """Run ':set ?' / ':set url.auto_search'. Should show an error. See https://github.com/qutebrowser/qutebrowser/issues/1109 @@ -145,6 +145,16 @@ class TestSet: "value"): commands.set(win_id=0, option=option) + def test_toggle(self, commands): + """Try toggling a value. + + Should show an nicer error. + """ + with pytest.raises(cmdexc.CommandError, + match="Toggling values was moved to the " + ":config-cycle command"): + commands.set(win_id=0, option='javascript.enabled!') + def test_invalid(self, commands): """Run ':set foo?'. From 1a7612e559560e8b1a1fb95ebaf9151a3643e9c4 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 06:28:22 +0200 Subject: [PATCH 56/99] Bump up yaml timeout a bit --- qutebrowser/utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py index d8e63af1a..018a0f18a 100644 --- a/qutebrowser/utils/utils.py +++ b/qutebrowser/utils/utils.py @@ -882,7 +882,7 @@ def yaml_load(f): end = datetime.datetime.now() delta = (end - start).total_seconds() - deadline = 3 if 'CI' in os.environ else 1 + deadline = 3 if 'CI' in os.environ else 2 if delta > deadline: # pragma: no cover log.misc.warning( "YAML load took unusually long, please report this at " From db874d8bbab6c027451480e157b7f7bc572d2419 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 06:34:08 +0200 Subject: [PATCH 57/99] Show apps with/without QApplication in standardpaths_tester --- scripts/dev/standardpaths_tester.py | 48 ++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/scripts/dev/standardpaths_tester.py b/scripts/dev/standardpaths_tester.py index e9bdd6e4c..dd7117b32 100644 --- a/scripts/dev/standardpaths_tester.py +++ b/scripts/dev/standardpaths_tester.py @@ -2,17 +2,43 @@ import os import sys from PyQt5.QtCore import (QT_VERSION_STR, PYQT_VERSION_STR, qVersion, - QStandardPaths) + QStandardPaths, QCoreApplication) -print("Python {}".format(sys.version)) -print("os.name: {}".format(os.name)) -print("sys.platform: {}".format(sys.platform)) -print() -print("Qt {}, compiled {}".format(qVersion(), QT_VERSION_STR)) -print("PyQt {}".format(PYQT_VERSION_STR)) -print() +def print_header(): + print("Python {}".format(sys.version)) + print("os.name: {}".format(os.name)) + print("sys.platform: {}".format(sys.platform)) + print() -for name, obj in vars(QStandardPaths).items(): - if isinstance(obj, QStandardPaths.StandardLocation): - print("{:25} {}".format(name, QStandardPaths.writableLocation(obj))) + print("Qt {}, compiled {}".format(qVersion(), QT_VERSION_STR)) + print("PyQt {}".format(PYQT_VERSION_STR)) + print() + + +def print_paths(): + for name, obj in vars(QStandardPaths).items(): + if isinstance(obj, QStandardPaths.StandardLocation): + print("{:25} {}".format(name, QStandardPaths.writableLocation(obj))) + + +def main(): + print_header() + + print("No QApplication") + print("===============") + print() + print_paths() + + app = QCoreApplication(sys.argv) + app.setApplicationName("qapp_name") + + print() + print("With QApplication") + print("=================") + print() + print_paths() + + +if __name__ == '__main__': + main() From 6bc35a18422ae62a0b38269064f64d93f796c36c Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 07:39:09 +0200 Subject: [PATCH 58/99] Remove blank lines --- misc/qutebrowser.appdata.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/misc/qutebrowser.appdata.xml b/misc/qutebrowser.appdata.xml index ba333702f..bac4539ab 100644 --- a/misc/qutebrowser.appdata.xml +++ b/misc/qutebrowser.appdata.xml @@ -41,5 +41,3 @@ https://github.com/qutebrowser/qutebrowser/issues/ https://github.com/qutebrowser/qutebrowser#donating - - From 14a63b8a82961ddcba3ad326e27fdd0767a1dca1 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 07:39:44 +0200 Subject: [PATCH 59/99] Include appdata file in MANIFEST --- MANIFEST.in | 1 + 1 file changed, 1 insertion(+) diff --git a/MANIFEST.in b/MANIFEST.in index a3ae1ee28..f09e9c0ef 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -13,6 +13,7 @@ include qutebrowser/utils/testfile include qutebrowser/git-commit-id include LICENSE doc/* README.asciidoc include misc/qutebrowser.desktop +include misc/qutebrowser.appdata.xml include requirements.txt include tox.ini include qutebrowser.py From 373ad28d2eb85861c46a255fb78cf03ac14af74e Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 07:41:15 +0200 Subject: [PATCH 60/99] Release v1.0.2 (cherry picked from commit 55a88ceea674fdfaf5577c255bc704e41e3353a3) --- doc/changelog.asciidoc | 10 ++++++---- qutebrowser/__init__.py | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index f0af67b97..757b149d0 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -31,15 +31,17 @@ Fixed - More consistent sizing for favicons with vertical tabs. -v1.0.2 (unreleased) -------------------- +v1.0.2 +------ Fixed ~~~~~ -- Fixed workaround for black screens with Nvidia cards -- Mark the content.notifications setting as QtWebKit only correctly +- Fix workaround for black screens or crashes with Nvidia cards - Handle a filesystem going read-only gracefully +- Fix crash when setting `fonts.monospace` +- Fix list options not being modifyable via `.append()` in `config.py` +- Mark the content.notifications setting as QtWebKit only correctly - Fix wrong rendering of keys like `` in the completion Changed diff --git a/qutebrowser/__init__.py b/qutebrowser/__init__.py index 0061e755b..a0da19248 100644 --- a/qutebrowser/__init__.py +++ b/qutebrowser/__init__.py @@ -26,7 +26,7 @@ __copyright__ = "Copyright 2014-2017 Florian Bruhin (The Compiler)" __license__ = "GPL" __maintainer__ = __author__ __email__ = "mail@qutebrowser.org" -__version_info__ = (1, 0, 1) +__version_info__ = (1, 0, 2) __version__ = '.'.join(str(e) for e in __version_info__) __description__ = "A keyboard-driven, vim-like browser based on PyQt5." From a8eae03ee944ae8f5e0476e17c4ef7f276c596ec Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 07:52:43 +0200 Subject: [PATCH 61/99] Update release checklist --- doc/contributing.asciidoc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/contributing.asciidoc b/doc/contributing.asciidoc index 2069263fd..2dda2f817 100644 --- a/doc/contributing.asciidoc +++ b/doc/contributing.asciidoc @@ -681,7 +681,6 @@ qutebrowser release * Adjust `__version_info__` in `qutebrowser/__init__.py`. * Update changelog (remove *(unreleased)*). -* Run tests again. * Commit. * Create annotated git tag (`git tag -s "v1.$x.$y" -m "Release v1.$x.$y"`). @@ -691,9 +690,9 @@ qutebrowser release * Mark the milestone at https://github.com/qutebrowser/qutebrowser/milestones as closed. -* Linux: Run `python3 scripts/dev/build_release.py --upload v1.$x.$y`. -* Windows: Run `C:\Python36-32\python scripts\dev\build_release.py --asciidoc C:\Python27\python C:\asciidoc-8.6.9\asciidoc.py --upload v1.X.Y` (replace X/Y by hand). -* macOS: Run `python3 scripts/dev/build_release.py --upload v1.X.Y` (replace X/Y by hand). +* Linux: Run `git checkout v1.$x.$y && python3 scripts/dev/build_release.py --upload v1.$x.$y`. +* Windows: Run `git checkout v1.X.Y; C:\Python36-32\python scripts\dev\build_release.py --asciidoc C:\Python27\python C:\asciidoc-8.6.9\asciidoc.py --upload v1.X.Y` (replace X/Y by hand). +* macOS: Run `git checkout v1.X.Y && python3 scripts/dev/build_release.py --upload v1.X.Y` (replace X/Y by hand). * On server: Run `python3 scripts/dev/download_release.py v1.X.Y` (replace X/Y by hand). * Update `qutebrowser-git` PKGBUILD if dependencies/install changed. * Announce to qutebrowser and qutebrowser-announce mailinglist. From 8d169597ae79fb492edcb4a7c7b79e417cab0cdc Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 09:06:52 +0200 Subject: [PATCH 62/99] Fix lint for standardpaths_tester --- scripts/dev/standardpaths_tester.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/scripts/dev/standardpaths_tester.py b/scripts/dev/standardpaths_tester.py index dd7117b32..a53b0320a 100644 --- a/scripts/dev/standardpaths_tester.py +++ b/scripts/dev/standardpaths_tester.py @@ -1,3 +1,25 @@ +#!/usr/bin/env python3 +# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: + +# Copyright 2017 Florian Bruhin (The Compiler) +# +# This file is part of qutebrowser. +# +# qutebrowser is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# qutebrowser is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with qutebrowser. If not, see . + +"""Show various QStandardPath paths.""" + import os import sys @@ -6,6 +28,7 @@ from PyQt5.QtCore import (QT_VERSION_STR, PYQT_VERSION_STR, qVersion, def print_header(): + """Show system information.""" print("Python {}".format(sys.version)) print("os.name: {}".format(os.name)) print("sys.platform: {}".format(sys.platform)) @@ -19,7 +42,8 @@ def print_header(): def print_paths(): for name, obj in vars(QStandardPaths).items(): if isinstance(obj, QStandardPaths.StandardLocation): - print("{:25} {}".format(name, QStandardPaths.writableLocation(obj))) + location = QStandardPaths.writableLocation(obj) + print("{:25} {}".format(name, location)) def main(): From 2c867889016445f2e78f52582929f80d12825f39 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 09:14:02 +0200 Subject: [PATCH 63/99] Update changelog --- doc/changelog.asciidoc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 757b149d0..db84d803e 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -25,12 +25,20 @@ Added - New `colors.statusbar.passthrough.fg`/`.bg` settings. - New `completion.delay` and `completion.min_chars` settings to update the completion less often. +- New `:tab-give` and `:tab-take` commands, to give tabs to another window, or + take them from another window. Fixed ~~~~~ - More consistent sizing for favicons with vertical tabs. +Removed +~~~~~~~ + +- `:tab-detach` has been removed, as `:tab-give` without argument can be used + instead. + v1.0.2 ------ From ced4713fda1619bb6131e0dd9a02b227d18efc60 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 09:14:59 +0200 Subject: [PATCH 64/99] Reverse if/else --- 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 a3eed85df..2e8ed2ade 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -543,16 +543,17 @@ class CommandDispatcher: if win_id == self._win_id: raise cmdexc.CommandError("Can't give a tab to the same window") - if win_id is not None: - tabbed_browser = objreg.get('tabbed-browser', scope='window', - window=win_id) - else: + if win_id is None: if self._count() < 2: raise cmdexc.CommandError("Cannot detach from a window with " "only one tab") tabbed_browser = self._new_tabbed_browser( - private=self._tabbed_browser.private) + private=self._tabbed_browser.private) + else: + tabbed_browser = objreg.get('tabbed-browser', scope='window', + window=win_id) + tabbed_browser.tabopen(self._current_url()) self._tabbed_browser.close_tab(self._current_widget(), add_undo=False) From f84af0a6fb1a8afaf5edf2b77ffa3172cd4756e2 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 09:33:20 +0200 Subject: [PATCH 65/99] Fix docstring --- 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 2e8ed2ade..0575d01d2 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1044,7 +1044,7 @@ class CommandDispatcher: self._open(url, tab, bg, window) def _resolve_buffer_index(self, index): - """Resolves a buffer index to the tabbedbrowser and tab. + """Resolve a buffer index to the tabbedbrowser and tab. Args: index: The [win_id/]index of the tab to be selected. Or a substring From f1ddf58260936ecdcb2932997d5ac8955ebc6ee8 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 10:28:28 +0200 Subject: [PATCH 66/99] Add a deprecated :tab-detach --- doc/changelog.asciidoc | 6 +++--- qutebrowser/browser/commands.py | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index db84d803e..bd29784fe 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -33,10 +33,10 @@ Fixed - More consistent sizing for favicons with vertical tabs. -Removed -~~~~~~~ +Deprecated +~~~~~~~~~~ -- `:tab-detach` has been removed, as `:tab-give` without argument can be used +- `:tab-detach` has been deprecated, as `:tab-give` without argument can be used instead. v1.0.2 diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 0575d01d2..2983bbd02 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -557,6 +557,12 @@ class CommandDispatcher: tabbed_browser.tabopen(self._current_url()) self._tabbed_browser.close_tab(self._current_widget(), add_undo=False) + @cmdutils.register(instance='command-dispatcher', hide=True, scope='window', + deprecated='Use :tab-give instead!') + def tab_detach(self): + """Deprecated way to detach a tab.""" + self.tab_give() + def _back_forward(self, tab, bg, window, count, forward): """Helper function for :back/:forward.""" history = self._current_widget().history From 458a45c172a87c5917f097d33306e0e24451cc40 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 10:31:45 +0200 Subject: [PATCH 67/99] Remove old deprecated commands --- doc/changelog.asciidoc | 6 ++++ qutebrowser/browser/commands.py | 45 -------------------------- qutebrowser/mainwindow/prompt.py | 14 -------- tests/end2end/features/prompts.feature | 16 --------- 4 files changed, 6 insertions(+), 75 deletions(-) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index bd29784fe..1d30a6d9e 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -39,6 +39,12 @@ Deprecated - `:tab-detach` has been deprecated, as `:tab-give` without argument can be used instead. +Removed +~~~~~~~ + +- The long-deprecated `:prompt-yes`, `:prompt-no`, `:paste-primary` and `:paste` + commands have been removed. + v1.0.2 ------ diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 2983bbd02..801ff290d 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1012,43 +1012,6 @@ class CommandDispatcher: else: raise cmdexc.CommandError("Last tab") - @cmdutils.register(instance='command-dispatcher', scope='window', - deprecated="Use :open {clipboard}") - def paste(self, sel=False, tab=False, bg=False, window=False): - """Open a page from the clipboard. - - If the pasted text contains newlines, each line gets opened in its own - tab. - - Args: - sel: Use the primary selection instead of the clipboard. - tab: Open in a new tab. - bg: Open in a background tab. - window: Open in new window. - """ - force_search = False - if not utils.supports_selection(): - sel = False - try: - text = utils.get_clipboard(selection=sel) - except utils.ClipboardError as e: - raise cmdexc.CommandError(e) - text_urls = [u for u in text.split('\n') if u.strip()] - if (len(text_urls) > 1 and not urlutils.is_url(text_urls[0]) and - urlutils.get_path_if_valid( - text_urls[0], check_exists=True) is None): - force_search = True - text_urls = [text] - for i, text_url in enumerate(text_urls): - if not window and i > 0: - tab = False - bg = True - try: - url = urlutils.fuzzy_url(text_url, force_search=force_search) - except urlutils.InvalidUrlError as e: - raise cmdexc.CommandError(e) - self._open(url, tab, bg, window) - def _resolve_buffer_index(self, index): """Resolve a buffer index to the tabbedbrowser and tab. @@ -1676,14 +1639,6 @@ class CommandDispatcher: except webelem.Error as e: raise cmdexc.CommandError(str(e)) - @cmdutils.register(instance='command-dispatcher', - deprecated="Use :insert-text {primary}", - modes=[KeyMode.insert], hide=True, scope='window', - backend=usertypes.Backend.QtWebKit) - def paste_primary(self): - """Paste the primary selection at cursor position.""" - self.insert_text(utils.get_clipboard(selection=True, fallback=True)) - @cmdutils.register(instance='command-dispatcher', maxsplit=0, scope='window') def insert_text(self, text): diff --git a/qutebrowser/mainwindow/prompt.py b/qutebrowser/mainwindow/prompt.py index 1f4c47c78..d00e57174 100644 --- a/qutebrowser/mainwindow/prompt.py +++ b/qutebrowser/mainwindow/prompt.py @@ -388,20 +388,6 @@ class PromptContainer(QWidget): message.global_bridge.prompt_done.emit(self._prompt.KEY_MODE) question.done() - @cmdutils.register(instance='prompt-container', hide=True, scope='window', - modes=[usertypes.KeyMode.yesno], - deprecated='Use :prompt-accept yes instead!') - def prompt_yes(self): - """Answer yes to a yes/no prompt.""" - self.prompt_accept('yes') - - @cmdutils.register(instance='prompt-container', hide=True, scope='window', - modes=[usertypes.KeyMode.yesno], - deprecated='Use :prompt-accept no instead!') - def prompt_no(self): - """Answer no to a yes/no prompt.""" - self.prompt_accept('no') - @cmdutils.register(instance='prompt-container', hide=True, scope='window', modes=[usertypes.KeyMode.prompt], maxsplit=0) def prompt_open_download(self, cmdline: str = None): diff --git a/tests/end2end/features/prompts.feature b/tests/end2end/features/prompts.feature index 7f8ba291d..b11a214b6 100644 --- a/tests/end2end/features/prompts.feature +++ b/tests/end2end/features/prompts.feature @@ -387,22 +387,6 @@ Feature: Prompts Then the javascript message "confirm reply: true" should be logged And the error "No default value was set for this question!" should be shown - Scenario: Javascript confirm with deprecated :prompt-yes command - When I open data/prompt/jsconfirm.html - And I run :click-element id button - And I wait for a prompt - And I run :prompt-yes - Then the javascript message "confirm reply: true" should be logged - And the warning "prompt-yes is deprecated - Use :prompt-accept yes instead!" should be shown - - Scenario: Javascript confirm with deprecated :prompt-no command - When I open data/prompt/jsconfirm.html - And I run :click-element id button - And I wait for a prompt - And I run :prompt-no - Then the javascript message "confirm reply: false" should be logged - And the warning "prompt-no is deprecated - Use :prompt-accept no instead!" should be shown - # Other @qtwebengine_skip From 44e5dc1c5a7d07144603b3bd1785f7e081902651 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 10:45:58 +0200 Subject: [PATCH 68/99] Add a comment to @xfail_norun --- tests/end2end/features/tabs.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/end2end/features/tabs.feature b/tests/end2end/features/tabs.feature index 4c35547dc..8a3c38775 100644 --- a/tests/end2end/features/tabs.feature +++ b/tests/end2end/features/tabs.feature @@ -990,7 +990,7 @@ Feature: Tab management # :tab-take - @xfail_norun + @xfail_norun # Needs qutewm Scenario: Take a tab from another window Given I have a fresh instance When I open data/numbers/1.txt @@ -1015,7 +1015,7 @@ Feature: Tab management # :tab-give - @xfail_norun + @xfail_norun # Needs qutewm Scenario: Give a tab to another window Given I have a fresh instance When I open data/numbers/1.txt From c3441ae4a8d81c90a0ee90846d6d4d4a01bf1fe2 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 11:34:46 +0200 Subject: [PATCH 69/99] Update changelog --- doc/changelog.asciidoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 1d30a6d9e..e0b4caf6d 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -25,6 +25,8 @@ Added - New `colors.statusbar.passthrough.fg`/`.bg` settings. - New `completion.delay` and `completion.min_chars` settings to update the completion less often. +- New `completion.use_best_match` setting to automatically use the best-matching + command in the completion. - New `:tab-give` and `:tab-take` commands, to give tabs to another window, or take them from another window. From 52423fa426753898e71ce9f4ba144fafee101df5 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 11:37:19 +0200 Subject: [PATCH 70/99] Remove unneeded variable --- tests/unit/commands/test_runners.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/commands/test_runners.py b/tests/unit/commands/test_runners.py index fad96c558..18db9f01c 100644 --- a/tests/unit/commands/test_runners.py +++ b/tests/unit/commands/test_runners.py @@ -89,7 +89,7 @@ class TestCompletions: parser = runners.CommandParser(partial_match=True) with pytest.raises(cmdexc.NoSuchCommandError): - result = parser.parse('do') + parser.parse('do') def test_use_best_match(self, config_stub): """Test multiple completion options with use_best_match set to true. From 2e64dda592e81387d598d1c2301a374408fc6eb8 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 11:39:30 +0200 Subject: [PATCH 71/99] Clean up getting matching commands --- qutebrowser/commands/runners.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/qutebrowser/commands/runners.py b/qutebrowser/commands/runners.py index a1f4accd7..52c4ea613 100644 --- a/qutebrowser/commands/runners.py +++ b/qutebrowser/commands/runners.py @@ -214,10 +214,7 @@ class CommandParser: Return: cmdstr modified to the matching completion or unmodified """ - matches = [] - for valid_command in cmdutils.cmd_dict: - if valid_command.find(cmdstr) == 0: - matches.append(valid_command) + matches = [cmd for cmd in cmdutils.cmd_dict if cmdstr in cmd] if len(matches) == 1: cmdstr = matches[0] elif len(matches) > 1 and config.val.completion.use_best_match: From 4f263505eea1d35660bd9180b3fd3aaf599277d0 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 11:49:46 +0200 Subject: [PATCH 72/99] Improve tests for partial matching --- tests/unit/commands/test_runners.py | 33 ++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/tests/unit/commands/test_runners.py b/tests/unit/commands/test_runners.py index 18db9f01c..0cbcd37a5 100644 --- a/tests/unit/commands/test_runners.py +++ b/tests/unit/commands/test_runners.py @@ -21,7 +21,7 @@ import pytest -from qutebrowser.commands import runners, cmdexc +from qutebrowser.commands import runners, cmdexc, cmdutils class TestCommandParser: @@ -66,19 +66,28 @@ class TestCommandParser: with pytest.raises(cmdexc.NoSuchCommandError): parser.parse_all(command) - def test_partial_parsing(self): + +class TestCompletions: + + """Tests for completions.use_best_match.""" + + @pytest.fixture(autouse=True) + def cmdutils_stub(self, monkeypatch, stubs): + """Patch the cmdutils module to provide fake commands.""" + monkeypatch.setattr(cmdutils, 'cmd_dict', { + 'one': stubs.FakeCommand(name='one'), + 'two': stubs.FakeCommand(name='two'), + 'two-foo': stubs.FakeCommand(name='two-foo'), + }) + + def test_partial_parsing(self, config_stub): """Test partial parsing with a runner where it's enabled. The same with it being disabled is tested by test_parse_all. """ parser = runners.CommandParser(partial_match=True) - result = parser.parse('message-i') - assert result.cmd.name == 'message-info' - - -class TestCompletions: - - """Tests for completions.use_best_match.""" + result = parser.parse('on') + assert result.cmd.name == 'one' def test_dont_use_best_match(self, config_stub): """Test multiple completion options with use_best_match set to false. @@ -89,7 +98,7 @@ class TestCompletions: parser = runners.CommandParser(partial_match=True) with pytest.raises(cmdexc.NoSuchCommandError): - parser.parse('do') + parser.parse('tw') def test_use_best_match(self, config_stub): """Test multiple completion options with use_best_match set to true. @@ -99,5 +108,5 @@ class TestCompletions: config_stub.val.completion.use_best_match = True parser = runners.CommandParser(partial_match=True) - result = parser.parse('do') - assert result.cmd.name == 'download-cancel' + result = parser.parse('tw') + assert result.cmd.name == 'two' From 2fccc083af88da7a8de3990b480a644fda9714e9 Mon Sep 17 00:00:00 2001 From: Fritz Reichwald Date: Tue, 17 Oct 2017 12:03:27 +0200 Subject: [PATCH 73/99] fix debian install instructions to fit debian9 and new apt --- doc/install.asciidoc | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/doc/install.asciidoc b/doc/install.asciidoc index 15e3ac93e..3ccc6c677 100644 --- a/doc/install.asciidoc +++ b/doc/install.asciidoc @@ -41,21 +41,17 @@ Debian Stretch / Ubuntu 17.04 and newer Those versions come with QtWebEngine in the repositories. This makes it possible to install qutebrowser via the Debian package. -Install the dependencies via apt-get: - ----- -# apt install python-tox python3-{lxml,pyqt5,sip,jinja2,pygments,yaml,attr} python3-pyqt5.qt{webengine,quick,opengl,sql} libqt5sql5-sqlite ----- - Get the qutebrowser package from the https://github.com/qutebrowser/qutebrowser/releases[release page] and download the https://qutebrowser.org/python3-pypeg2_2.15.2-1_all.deb[PyPEG2 package]. +(If you are using debian testing you can just use the python3-pypeg2 package from the repos) + Install the packages: ---- -# dpkg -i python3-pypeg2_*_all.deb -# dpkg -i qutebrowser_*_all.deb +# apt install ./python3-pypeg2_*_all.deb +# apt install ./qutebrowser_*_all.deb ---- Some additional hints: @@ -66,7 +62,7 @@ Some additional hints: `:help` command: + ---- -# apt-get install --no-install-recommends asciidoc source-highlight +# apt install --no-install-recommends asciidoc source-highlight $ python3 scripts/asciidoc2html.py ---- @@ -76,7 +72,7 @@ $ python3 scripts/asciidoc2html.py - If video or sound don't work with QtWebKit, try installing the gstreamer plugins: + ---- -# apt-get install gstreamer1.0-plugins-{bad,base,good,ugly} +# apt install gstreamer1.0-plugins-{bad,base,good,ugly} ---- On Fedora From 161b96be1eeb4a64147df3784cdc21f49e1d68a6 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 13:10:00 +0200 Subject: [PATCH 74/99] Fix long line --- 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 801ff290d..7f4b079c2 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -557,8 +557,8 @@ class CommandDispatcher: tabbed_browser.tabopen(self._current_url()) self._tabbed_browser.close_tab(self._current_widget(), add_undo=False) - @cmdutils.register(instance='command-dispatcher', hide=True, scope='window', - deprecated='Use :tab-give instead!') + @cmdutils.register(instance='command-dispatcher', hide=True, + scope='window', deprecated='Use :tab-give instead!') def tab_detach(self): """Deprecated way to detach a tab.""" self.tab_give() From 4984c9d05cd05d031f01763001af5c56b382fe0c Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 14:57:41 +0200 Subject: [PATCH 75/99] Update docs --- doc/help/settings.asciidoc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index 7678583b7..d9fddc2f3 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -105,6 +105,7 @@ |<>|When to show the autocompletion window. |<>|Shrink the completion to be smaller than the configured size if there are no scrollbars. |<>|How to format timestamps (e.g. for the history completion). +|<>|Whether to execute the best-matching command on a partial match. |<>|How many URLs to show in the web history. |<>|Whether quitting the application requires a confirmation. |<>|Whether support for the HTML 5 web application cache feature is enabled. @@ -1391,6 +1392,14 @@ Type: <> Default: +pass:[%Y-%m-%d]+ +[[completion.use_best_match]] +=== completion.use_best_match +Whether to execute the best-matching command on a partial match. + +Type: <> + +Default: +pass:[false]+ + [[completion.web_history_max_items]] === completion.web_history_max_items How many URLs to show in the web history. From 12c959052452587a559bb55c717ced5321594474 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 15:01:37 +0200 Subject: [PATCH 76/99] Always use shortest match for completion.use_best_match --- qutebrowser/commands/runners.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qutebrowser/commands/runners.py b/qutebrowser/commands/runners.py index 52c4ea613..fadb6c063 100644 --- a/qutebrowser/commands/runners.py +++ b/qutebrowser/commands/runners.py @@ -214,7 +214,8 @@ class CommandParser: Return: cmdstr modified to the matching completion or unmodified """ - matches = [cmd for cmd in cmdutils.cmd_dict if cmdstr in cmd] + matches = [cmd for cmd in sorted(cmdutils.cmd_dict, key=len) + if cmdstr in cmd] if len(matches) == 1: cmdstr = matches[0] elif len(matches) > 1 and config.val.completion.use_best_match: From 96bec9f9d7139264488dbaeb700dbed36986b5f6 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 15:33:50 +0200 Subject: [PATCH 77/99] Fix error code for "database is locked" See #2930 --- qutebrowser/misc/sql.py | 4 ++-- tests/unit/misc/test_sql.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/qutebrowser/misc/sql.py b/qutebrowser/misc/sql.py index e04c3f6e3..f19de698f 100644 --- a/qutebrowser/misc/sql.py +++ b/qutebrowser/misc/sql.py @@ -68,9 +68,9 @@ class SqliteError(SqlError): # https://github.com/qutebrowser/qutebrowser/issues/2930 # https://github.com/qutebrowser/qutebrowser/issues/3004 environmental_errors = [ + '5', # SQLITE_BUSY ("database is locked") '8', # SQLITE_READONLY - '9', # SQLITE_LOCKED, - '13', # SQLITE_FULL, + '13', # SQLITE_FULL ] self.environmental = error.nativeErrorCode() in environmental_errors diff --git a/tests/unit/misc/test_sql.py b/tests/unit/misc/test_sql.py index fdd5c89c8..89c442b2b 100644 --- a/tests/unit/misc/test_sql.py +++ b/tests/unit/misc/test_sql.py @@ -39,7 +39,7 @@ def test_sqlerror(): class TestSqliteError: @pytest.mark.parametrize('error_code, environmental', [ - ('9', True), # SQLITE_LOCKED + ('5', True), # SQLITE_BUSY ('19', False), # SQLITE_CONSTRAINT ]) def test_environmental(self, error_code, environmental): From 5c6a821b1e9ab0569c0d4e0179dc52b67997e10e Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 15:35:17 +0200 Subject: [PATCH 78/99] Update changelog --- doc/changelog.asciidoc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index e0b4caf6d..665e7d013 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -47,6 +47,14 @@ Removed - The long-deprecated `:prompt-yes`, `:prompt-no`, `:paste-primary` and `:paste` commands have been removed. +v1.0.3 (unreleased) +------------------- + +Fixed +~~~~~ + +- Handle accessing a locked sqlite database gracefully + v1.0.2 ------ From 95761c5023967625b0e4b28bc4b490fbfb7a5604 Mon Sep 17 00:00:00 2001 From: Jay Kamat Date: Tue, 17 Oct 2017 10:36:37 -0400 Subject: [PATCH 79/99] Fix crashes on qute_pylint module when not running in the root Useful for editors that run from non-root directories for integrations, but skips some tests. Shouldn't impact tests run normally. --- .../dev/pylint_checkers/qute_pylint/config.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/scripts/dev/pylint_checkers/qute_pylint/config.py b/scripts/dev/pylint_checkers/qute_pylint/config.py index df08e6833..3b29942e3 100644 --- a/scripts/dev/pylint_checkers/qute_pylint/config.py +++ b/scripts/dev/pylint_checkers/qute_pylint/config.py @@ -27,9 +27,11 @@ import yaml import astroid from pylint import interfaces, checkers from pylint.checkers import utils +from pathlib import Path OPTIONS = None +FAILED_LOAD = False class ConfigChecker(checkers.BaseChecker): @@ -44,6 +46,7 @@ class ConfigChecker(checkers.BaseChecker): None), } priority = -1 + printed_warning = False @utils.check_messages('bad-config-option') def visit_attribute(self, node): @@ -58,6 +61,13 @@ class ConfigChecker(checkers.BaseChecker): def _check_config(self, node, name): """Check that we're accessing proper config options.""" + if FAILED_LOAD: + if not ConfigChecker.printed_warning: + print("[WARN] Could not find configdata.yml. Please run " + + "pylint from qutebrowser root.", file=sys.stderr) + print("Skipping some checks...", file=sys.stderr) + ConfigChecker.printed_warning = True + return if name not in OPTIONS: self.add_message('bad-config-option', node=node, args=name) @@ -66,6 +76,11 @@ def register(linter): """Register this checker.""" linter.register_checker(ConfigChecker(linter)) global OPTIONS - yaml_file = os.path.join('qutebrowser', 'config', 'configdata.yml') - with open(yaml_file, 'r', encoding='utf-8') as f: + global FAILED_LOAD + yaml_file = Path('qutebrowser') / 'config' / 'configdata.yml' + if not yaml_file.exists(): + OPTIONS = None + FAILED_LOAD = True + return + with yaml_file.open(mode='r', encoding='utf-8') as f: OPTIONS = list(yaml.load(f)) From 5d11a1fd75dc1651ba3e58284e9a117d1c67c435 Mon Sep 17 00:00:00 2001 From: Jay Kamat Date: Tue, 17 Oct 2017 11:19:37 -0400 Subject: [PATCH 80/99] Prevent :home from bypassing pinned tab warnings Closes #3138 --- qutebrowser/browser/commands.py | 6 +++++- tests/end2end/features/tabs.feature | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 7f4b079c2..256894d49 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -353,6 +353,10 @@ class CommandDispatcher: Return: A list of URLs that can be opened. """ + if isinstance(url, QUrl): + yield url + return + force_search = False urllist = [u for u in url.split('\n') if u.strip()] if (len(urllist) > 1 and not urlutils.is_url(urllist[0]) and @@ -1210,7 +1214,7 @@ class CommandDispatcher: @cmdutils.register(instance='command-dispatcher', scope='window') def home(self): """Open main startpage in current tab.""" - self._current_widget().openurl(config.val.url.start_pages[0]) + self.openurl(config.val.url.start_pages[0]) def _run_userscript(self, cmd, *args, verbose=False): """Run a userscript given as argument. diff --git a/tests/end2end/features/tabs.feature b/tests/end2end/features/tabs.feature index 8a3c38775..c516bfaa7 100644 --- a/tests/end2end/features/tabs.feature +++ b/tests/end2end/features/tabs.feature @@ -1197,6 +1197,14 @@ Feature: Tab management And the following tabs should be open: - data/numbers/1.txt (active) (pinned) + Scenario: :tab-pin open url + When I open data/numbers/1.txt + And I run :tab-pin + And I run :home + Then the message "Tab is pinned!" should be shown + And the following tabs should be open: + - data/numbers/1.txt (active) (pinned) + Scenario: Cloning a pinned tab When I open data/numbers/1.txt And I run :tab-pin From 62b6d62cd7eddd115f0e23c049ee0c7977f33442 Mon Sep 17 00:00:00 2001 From: Jay Kamat Date: Tue, 17 Oct 2017 14:22:18 -0400 Subject: [PATCH 81/99] Clean up sub-module import and unneeded + --- scripts/dev/pylint_checkers/qute_pylint/config.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/scripts/dev/pylint_checkers/qute_pylint/config.py b/scripts/dev/pylint_checkers/qute_pylint/config.py index 3b29942e3..5ad65cd00 100644 --- a/scripts/dev/pylint_checkers/qute_pylint/config.py +++ b/scripts/dev/pylint_checkers/qute_pylint/config.py @@ -20,14 +20,11 @@ """Custom astroid checker for config calls.""" import sys -import os -import os.path - +import pathlib import yaml import astroid from pylint import interfaces, checkers from pylint.checkers import utils -from pathlib import Path OPTIONS = None @@ -63,7 +60,7 @@ class ConfigChecker(checkers.BaseChecker): """Check that we're accessing proper config options.""" if FAILED_LOAD: if not ConfigChecker.printed_warning: - print("[WARN] Could not find configdata.yml. Please run " + + print("[WARN] Could not find configdata.yml. Please run " "pylint from qutebrowser root.", file=sys.stderr) print("Skipping some checks...", file=sys.stderr) ConfigChecker.printed_warning = True @@ -77,7 +74,7 @@ def register(linter): linter.register_checker(ConfigChecker(linter)) global OPTIONS global FAILED_LOAD - yaml_file = Path('qutebrowser') / 'config' / 'configdata.yml' + yaml_file = pathlib.Path('qutebrowser') / 'config' / 'configdata.yml' if not yaml_file.exists(): OPTIONS = None FAILED_LOAD = True From 807b7701d5c9b110a61bb31e8a10e0d0fcdf9337 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 21:11:14 +0200 Subject: [PATCH 82/99] Re-add blank line --- scripts/dev/pylint_checkers/qute_pylint/config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/dev/pylint_checkers/qute_pylint/config.py b/scripts/dev/pylint_checkers/qute_pylint/config.py index 5ad65cd00..da7fbf32f 100644 --- a/scripts/dev/pylint_checkers/qute_pylint/config.py +++ b/scripts/dev/pylint_checkers/qute_pylint/config.py @@ -21,6 +21,7 @@ import sys import pathlib + import yaml import astroid from pylint import interfaces, checkers From 828ffd49797bf713d81e7e3d124ce91397c55c81 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 21:19:46 +0200 Subject: [PATCH 83/99] Update changelog --- doc/changelog.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 665e7d013..8faf5452a 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -34,6 +34,7 @@ Fixed ~~~~~ - More consistent sizing for favicons with vertical tabs. +- Using `:home` on pinned tabs is now prevented. Deprecated ~~~~~~~~~~ From 9dc9bcaf39cb3560478bd9d71f73ba346516bd36 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 17 Oct 2017 22:37:14 +0200 Subject: [PATCH 84/99] Make standarddir work on HaikuOS For some reason, it returns an empty DataLocation. --- qutebrowser/utils/standarddir.py | 5 +++++ tests/unit/utils/test_standarddir.py | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/qutebrowser/utils/standarddir.py b/qutebrowser/utils/standarddir.py index d6ad7fc39..c5ee356c0 100644 --- a/qutebrowser/utils/standarddir.py +++ b/qutebrowser/utils/standarddir.py @@ -20,6 +20,7 @@ """Utilities to get and initialize data/config paths.""" import os +import sys import shutil import os.path import contextlib @@ -106,6 +107,10 @@ def _init_data(args): if utils.is_windows: app_data_path = _writable_location(QStandardPaths.AppDataLocation) path = os.path.join(app_data_path, 'data') + elif sys.platform.startswith('haiku'): + # HaikuOS returns an empty value for AppDataLocation + config_path = _writable_location(QStandardPaths.ConfigLocation) + path = os.path.join(config_path, 'data') else: path = _writable_location(typ) _create(path) diff --git a/tests/unit/utils/test_standarddir.py b/tests/unit/utils/test_standarddir.py index 20ea88645..1b9e473d1 100644 --- a/tests/unit/utils/test_standarddir.py +++ b/tests/unit/utils/test_standarddir.py @@ -103,6 +103,20 @@ def test_fake_windows(tmpdir, monkeypatch, what): assert func() == str(tmpdir / APPNAME / what) +def test_fake_haiku(tmpdir, monkeypatch): + """Test getting data dir on HaikuOS.""" + locations = { + QStandardPaths.DataLocation: '', + QStandardPaths.ConfigLocation: str(tmpdir / 'config' / APPNAME), + } + monkeypatch.setattr(standarddir.QStandardPaths, 'writableLocation', + locations.get) + monkeypatch.setattr(standarddir.sys, 'platform', 'haiku1') + + standarddir._init_data(args=None) + assert standarddir.data() == str(tmpdir / 'config' / APPNAME / 'data') + + class TestWritableLocation: """Tests for _writable_location.""" From 354c3c8c9b3e75988b334c1526b654c3e7caf8d9 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 18 Oct 2017 09:02:39 +0200 Subject: [PATCH 85/99] Handle unknown filetypes with qute://help --- doc/changelog.asciidoc | 1 + qutebrowser/browser/qutescheme.py | 9 ++++++--- tests/unit/browser/test_qutescheme.py | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 8faf5452a..03eca9485 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -35,6 +35,7 @@ Fixed - More consistent sizing for favicons with vertical tabs. - Using `:home` on pinned tabs is now prevented. +- Fix crash with unknown file types loaded via qute://help Deprecated ~~~~~~~~~~ diff --git a/qutebrowser/browser/qutescheme.py b/qutebrowser/browser/qutescheme.py index b49520002..2498ea7f6 100644 --- a/qutebrowser/browser/qutescheme.py +++ b/qutebrowser/browser/qutescheme.py @@ -29,8 +29,9 @@ import os import time import urllib.parse import textwrap -import pkg_resources +import mimetypes +import pkg_resources from PyQt5.QtCore import QUrlQuery, QUrl import qutebrowser @@ -323,8 +324,10 @@ def qute_help(url): "scripts/asciidoc2html.py.") path = 'html/doc/{}'.format(urlpath) - if urlpath.endswith('.png'): - return 'image/png', utils.read_file(path, binary=True) + if not urlpath.endswith('.html'): + mimetype, _encoding = mimetypes.guess_type(urlpath) + assert mimetype is not None, url + return mimetype, utils.read_file(path, binary=True) try: data = utils.read_file(path) diff --git a/tests/unit/browser/test_qutescheme.py b/tests/unit/browser/test_qutescheme.py index 02e0c484d..6fdaad83c 100644 --- a/tests/unit/browser/test_qutescheme.py +++ b/tests/unit/browser/test_qutescheme.py @@ -146,3 +146,26 @@ class TestHistoryHandler: url = QUrl("qute://history/data?start_time={}".format(now)) _mimetype, data = benchmark(qutescheme.qute_history, url) assert len(json.loads(data)) > 1 + + +class TestHelpHandler: + + """Tests for qute://help.""" + + @pytest.fixture + def data_patcher(self, monkeypatch): + def _patch(path, data): + def _read_file(name, binary=False): + assert path == name + if binary: + return data + return data.decode('utf-8') + + monkeypatch.setattr(qutescheme.utils, 'read_file', _read_file) + return _patch + + def test_unknown_file_type(self, data_patcher): + data_patcher('html/doc/foo.bin', b'\xff') + mimetype, data = qutescheme.qute_help(QUrl('qute://help/foo.bin')) + assert mimetype == 'application/octet-stream' + assert data == b'\xff' From 34787edf4ec5ae49b97a4e09bc00b5421a950a85 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 18 Oct 2017 10:46:12 +0200 Subject: [PATCH 86/99] Add Xresources to config recipes [ci skip] --- doc/help/configuring.asciidoc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/help/configuring.asciidoc b/doc/help/configuring.asciidoc index 997e47246..e442b03a6 100644 --- a/doc/help/configuring.asciidoc +++ b/doc/help/configuring.asciidoc @@ -347,6 +347,26 @@ def bind_chained(key, *commands): bind_chained('', 'clear-keychain', 'search') ---- +Reading colors from Xresources +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can use something like this to read colors from an `~/.Xresources` file: + +[source,python] +---- +def read_xresources(prefix): + props = {} + x = subprocess.run(['xrdb', '-query'], stdout=subprocess.PIPE) + lines = x.stdout.decode().split('\n') + for line in filter(lambda l : l.startswith(prefix), lines): + prop, _, value = line.partition(':\t') + props[prop] = value + return props + +xresources = read_xresources('*') +c.colors.statusbar.normal.bg = xresources['*background'] +---- + Avoiding flake8 errors ^^^^^^^^^^^^^^^^^^^^^^ From 5a9042ab3efb9e69f6b11a341373c302a688578b Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 18 Oct 2017 13:53:26 +0200 Subject: [PATCH 87/99] Add a config.source() method --- doc/changelog.asciidoc | 1 + doc/help/configuring.asciidoc | 3 +++ qutebrowser/config/configfiles.py | 9 ++++++++ tests/unit/config/test_configfiles.py | 32 +++++++++++++++++++++++++++ 4 files changed, 45 insertions(+) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 03eca9485..99b3ef11b 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -29,6 +29,7 @@ Added command in the completion. - New `:tab-give` and `:tab-take` commands, to give tabs to another window, or take them from another window. +- New `config.source(...)` method for `config.py` to source another file. Fixed ~~~~~ diff --git a/doc/help/configuring.asciidoc b/doc/help/configuring.asciidoc index e442b03a6..af555beb3 100644 --- a/doc/help/configuring.asciidoc +++ b/doc/help/configuring.asciidoc @@ -238,6 +238,9 @@ that via `import utils` as well. While it's in some cases possible to import code from the qutebrowser installation, doing so is unsupported and discouraged. +To read config data from a different file with `c` and `config` available, you +can use `config.source('otherfile.py')` in your `config.py`. + Getting the config directory ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/qutebrowser/config/configfiles.py b/qutebrowser/config/configfiles.py index e1a10848e..605c7372d 100644 --- a/qutebrowser/config/configfiles.py +++ b/qutebrowser/config/configfiles.py @@ -259,6 +259,15 @@ class ConfigAPI: with self._handle_error('unbinding', key): self._keyconfig.unbind(key, mode=mode) + def source(self, filename): + if not os.path.isabs(filename): + filename = str(self.configdir / filename) + + try: + read_config_py(filename) + except configexc.ConfigFileErrors as e: + self.errors += e.errors + class ConfigPyWriter: diff --git a/tests/unit/config/test_configfiles.py b/tests/unit/config/test_configfiles.py index 9a2ff37ab..2159a6604 100644 --- a/tests/unit/config/test_configfiles.py +++ b/tests/unit/config/test_configfiles.py @@ -580,6 +580,38 @@ class TestConfigPy: assert isinstance(error.exception, ZeroDivisionError) assert error.traceback is not None + @pytest.mark.parametrize('location', ['abs', 'rel']) + def test_source(self, tmpdir, confpy, location): + if location == 'abs': + subfile = tmpdir / 'subfile.py' + arg = str(subfile) + else: + subfile = tmpdir / 'config' / 'subfile.py' + arg = 'subfile.py' + + subfile.write_text("c.content.javascript.enabled = False", + encoding='utf-8') + confpy.write("config.source('{}')".format(arg)) + confpy.read() + + assert not config.instance._values['content.javascript.enabled'] + + def test_source_errors(self, tmpdir, confpy): + subfile = tmpdir / 'config' / 'subfile.py' + subfile.write_text("c.foo = 42", encoding='utf-8') + confpy.write("config.source('subfile.py')") + error = confpy.read(error=True) + + assert error.text == "While setting 'foo'" + assert isinstance(error.exception, configexc.NoOptionError) + + def test_source_not_found(self, confpy): + confpy.write("config.source('doesnotexist.py')") + error = confpy.read(error=True) + + assert error.text == "Error while reading doesnotexist.py" + assert isinstance(error.exception, FileNotFoundError) + class TestConfigPyWriter: From 378498bbd7767a2277ab6fba9e54899959a7c972 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 18 Oct 2017 14:06:54 +0200 Subject: [PATCH 88/99] Add a test for multiple config.source() errors --- tests/unit/config/test_configfiles.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/unit/config/test_configfiles.py b/tests/unit/config/test_configfiles.py index 2159a6604..c0ba1f1ae 100644 --- a/tests/unit/config/test_configfiles.py +++ b/tests/unit/config/test_configfiles.py @@ -605,6 +605,20 @@ class TestConfigPy: assert error.text == "While setting 'foo'" assert isinstance(error.exception, configexc.NoOptionError) + def test_source_multiple_errors(self, tmpdir, confpy): + subfile = tmpdir / 'config' / 'subfile.py' + subfile.write_text("c.foo = 42", encoding='utf-8') + confpy.write("config.source('subfile.py')", "c.bar = 23") + + with pytest.raises(configexc.ConfigFileErrors) as excinfo: + configfiles.read_config_py(confpy.filename) + + errors = excinfo.value.errors + assert len(errors) == 2 + + for error in errors: + assert isinstance(error.exception, configexc.NoOptionError) + def test_source_not_found(self, confpy): confpy.write("config.source('doesnotexist.py')") error = confpy.read(error=True) From 2bfa853847a66925650894cba0afea9b5ace08dc Mon Sep 17 00:00:00 2001 From: Martin Fraga Date: Thu, 19 Oct 2017 01:44:10 -0700 Subject: [PATCH 89/99] Add keyhint radius configuration option The radius for the keyhint dialog box should be configurable vi via c.keyhint.radius. The default was set to 6px, which is the previous hardcoded value. --- qutebrowser/config/configdata.yml | 7 +++++++ qutebrowser/misc/keyhintwidget.py | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 3d296fcaa..e5870e3fc 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -978,6 +978,13 @@ keyhint.blacklist: Globs are supported, so `;*` will blacklist all keychains starting with `;`. Use `*` to disable keyhints. +keyhint.radius: + type: + name: Int + minval: 0 + default: 6 + desc: The rounding radius for the edges of the keyhint dialog. + # emacs: ' keyhint.delay: diff --git a/qutebrowser/misc/keyhintwidget.py b/qutebrowser/misc/keyhintwidget.py index ce1f324e4..98dc8e275 100644 --- a/qutebrowser/misc/keyhintwidget.py +++ b/qutebrowser/misc/keyhintwidget.py @@ -54,9 +54,9 @@ class KeyHintView(QLabel): background-color: {{ conf.colors.keyhint.bg }}; padding: 6px; {% if conf.statusbar.position == 'top' %} - border-bottom-right-radius: 6px; + border-bottom-right-radius: {{ conf.keyhint.radius }}px; {% else %} - border-top-right-radius: 6px; + border-top-right-radius: {{ conf.keyhint.radius }}px; {% endif %} } """ From 455b90ecad1006281e2ebc0393f57de80aef4291 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 20 Oct 2017 07:14:32 +0200 Subject: [PATCH 90/99] Log which dictionaries have been found See #3166 --- qutebrowser/browser/webengine/webenginesettings.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qutebrowser/browser/webengine/webenginesettings.py b/qutebrowser/browser/webengine/webenginesettings.py index 47be9ffed..b74356727 100644 --- a/qutebrowser/browser/webengine/webenginesettings.py +++ b/qutebrowser/browser/webengine/webenginesettings.py @@ -36,7 +36,8 @@ from PyQt5.QtWebEngineWidgets import (QWebEngineSettings, QWebEngineProfile, from qutebrowser.browser import shared from qutebrowser.browser.webengine import spell from qutebrowser.config import config, websettings -from qutebrowser.utils import utils, standarddir, javascript, qtutils, message +from qutebrowser.utils import (utils, standarddir, javascript, qtutils, message, + log) # The default QWebEngineProfile default_profile = None @@ -145,6 +146,7 @@ class DictionaryLanguageSetter(DefaultProfileSetter): raise ValueError("'settings' may not be set with " "DictionaryLanguageSetter!") filenames = [self._find_installed(code) for code in value] + log.config.debug("Found dicts: {}".format(filenames)) super()._set([f for f in filenames if f], settings) From fd8e5e30c62908bb7c5d9dc1c1eff488efa54fdc Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 20 Oct 2017 07:36:51 +0200 Subject: [PATCH 91/99] Re-add scroll filtering and disable it for mark/scroll tests See #2233 --- qutebrowser/browser/webengine/webenginetab.py | 7 +++++-- qutebrowser/qutebrowser.py | 3 ++- tests/end2end/features/test_marks_bdd.py | 9 +++++++++ tests/end2end/features/test_scroll_bdd.py | 9 +++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index a5a15e0db..1e625d93c 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -293,6 +293,7 @@ class WebEngineScroller(browsertab.AbstractScroller): def __init__(self, tab, parent=None): super().__init__(tab, parent) + self._args = objreg.get('args') self._pos_perc = (0, 0) self._pos_px = QPoint() self._at_bottom = False @@ -333,9 +334,11 @@ class WebEngineScroller(browsertab.AbstractScroller): perc_y = min(100, round(100 / dy * jsret['px']['y'])) self._at_bottom = math.ceil(jsret['px']['y']) >= dy - self._pos_perc = perc_x, perc_y - self.perc_changed.emit(*self._pos_perc) + if (self._pos_perc != (perc_x, perc_y) or + 'no-scroll-filtering' in self._args.debug_flags): + self._pos_perc = perc_x, perc_y + self.perc_changed.emit(*self._pos_perc) js_code = javascript.assemble('scroll', 'pos') self._tab.run_js_async(js_code, update_pos_cb) diff --git a/qutebrowser/qutebrowser.py b/qutebrowser/qutebrowser.py index 1b1cfb013..ad53f45ca 100644 --- a/qutebrowser/qutebrowser.py +++ b/qutebrowser/qutebrowser.py @@ -159,7 +159,8 @@ def debug_flag_error(flag): debug-exit: Turn on debugging of late exit. pdb-postmortem: Drop into pdb on exceptions. """ - valid_flags = ['debug-exit', 'pdb-postmortem', 'no-sql-history'] + valid_flags = ['debug-exit', 'pdb-postmortem', 'no-sql-history', + 'no-scroll-filtering'] if flag in valid_flags: return flag diff --git a/tests/end2end/features/test_marks_bdd.py b/tests/end2end/features/test_marks_bdd.py index 5b8e352dd..5d31298ff 100644 --- a/tests/end2end/features/test_marks_bdd.py +++ b/tests/end2end/features/test_marks_bdd.py @@ -17,10 +17,19 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . +import pytest + import pytest_bdd as bdd bdd.scenarios('marks.feature') +@pytest.fixture(autouse=True) +def turn_on_scroll_logging(quteproc): + """Make sure all scrolling changes are logged.""" + quteproc.send_cmd(":debug-pyeval -q objreg.get('args')." + "debug_flags.append('no-scroll-filtering')") + + @bdd.then(bdd.parsers.parse("the page should be scrolled to {x} {y}")) def check_y(request, quteproc, x, y): data = quteproc.get_session() diff --git a/tests/end2end/features/test_scroll_bdd.py b/tests/end2end/features/test_scroll_bdd.py index 69199ebf3..966d5c9bb 100644 --- a/tests/end2end/features/test_scroll_bdd.py +++ b/tests/end2end/features/test_scroll_bdd.py @@ -17,5 +17,14 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . +import pytest + import pytest_bdd as bdd bdd.scenarios('scroll.feature') + + +@pytest.fixture(autouse=True) +def turn_on_scroll_logging(quteproc): + """Make sure all scrolling changes are logged.""" + quteproc.send_cmd(":debug-pyeval -q objreg.get('args')." + "debug_flags.append('no-scroll-filtering')") From 280dddda6b5e078eaf89d5ed8599f60857ff9349 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 20 Oct 2017 08:07:10 +0200 Subject: [PATCH 92/99] Set backend in TestRectOnView.test_zoomed --- tests/unit/browser/webkit/test_webkitelem.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/unit/browser/webkit/test_webkitelem.py b/tests/unit/browser/webkit/test_webkitelem.py index 871241a04..3174d7281 100644 --- a/tests/unit/browser/webkit/test_webkitelem.py +++ b/tests/unit/browser/webkit/test_webkitelem.py @@ -31,6 +31,8 @@ QWebElement = pytest.importorskip('PyQt5.QtWebKit').QWebElement from qutebrowser.browser import webelem from qutebrowser.browser.webkit import webkitelem +from qutebrowser.misc import objects +from qutebrowser.utils import usertypes def get_webelem(geometry=None, frame=None, *, null=False, style=None, @@ -715,8 +717,10 @@ class TestRectOnView: @pytest.mark.parametrize('js_rect', [None, {}]) @pytest.mark.parametrize('zoom_text_only', [True, False]) - def test_zoomed(self, stubs, config_stub, js_rect, zoom_text_only): + def test_zoomed(self, stubs, config_stub, js_rect, monkeypatch, + zoom_text_only): """Make sure the coordinates are adjusted when zoomed.""" + monkeypatch.setattr(objects, 'backend', usertypes.Backend.QtWebKit) config_stub.val.zoom.text_only = zoom_text_only geometry = QRect(10, 10, 4, 4) frame = stubs.FakeWebFrame(QRect(0, 0, 100, 100), zoom=0.5) From dd927ded6ba3b03d9450c8e375b25651f67f90bf Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 20 Oct 2017 08:25:43 +0200 Subject: [PATCH 93/99] Only update tab/window title on scroll if needed This way, if {scroll_pos} is not in the window/tab title template, we don't redraw anything unnecessarily. See #2233 --- qutebrowser/mainwindow/tabbedbrowser.py | 19 ++++++++++++----- qutebrowser/mainwindow/tabwidget.py | 28 ++++++++++++++++--------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/qutebrowser/mainwindow/tabbedbrowser.py b/qutebrowser/mainwindow/tabbedbrowser.py index 0571d7e34..a280df650 100644 --- a/qutebrowser/mainwindow/tabbedbrowser.py +++ b/qutebrowser/mainwindow/tabbedbrowser.py @@ -173,8 +173,18 @@ class TabbedBrowser(tabwidget.TabWidget): widgets.append(widget) return widgets - def _update_window_title(self): - """Change the window title to match the current tab.""" + def _update_window_title(self, field=None): + """Change the window title to match the current tab. + + Args: + idx: The tab index to update. + field: A field name which was updated. If given, the title + is only set if the given field is in the template. + """ + title_format = config.val.window.title_format + if field is not None and ('{' + field + '}') not in title_format: + return + idx = self.currentIndex() if idx == -1: # (e.g. last tab removed) @@ -183,7 +193,6 @@ class TabbedBrowser(tabwidget.TabWidget): fields = self.get_tab_fields(idx) fields['id'] = self._win_id - title_format = config.val.window.title_format title = title_format.format(**fields) self.window().setWindowTitle(title) @@ -696,8 +705,8 @@ class TabbedBrowser(tabwidget.TabWidget): log.webview.debug("Not updating scroll position because index is " "-1") return - self._update_window_title() - self._update_tab_title(idx) + self._update_window_title('scroll_pos') + self._update_tab_title(idx, 'scroll_pos') def _on_renderer_process_terminated(self, tab, status, code): """Show an error when a renderer process terminated.""" diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py index 56cb922f8..03c9929e0 100644 --- a/qutebrowser/mainwindow/tabwidget.py +++ b/qutebrowser/mainwindow/tabwidget.py @@ -121,21 +121,29 @@ class TabWidget(QTabWidget): """Get the tab title user data.""" return self.tabBar().page_title(idx) - def _update_tab_title(self, idx): - """Update the tab text for the given tab.""" + def _update_tab_title(self, idx, field=None): + """Update the tab text for the given tab. + + Args: + idx: The tab index to update. + field: A field name which was updated. If given, the title + is only set if the given field is in the template. + """ tab = self.widget(idx) + if tab.data.pinned: + fmt = config.val.tabs.title.format_pinned + else: + fmt = config.val.tabs.title.format + + if (field is not None and + (fmt is None or ('{' + field + '}') not in fmt)): + return + fields = self.get_tab_fields(idx) fields['title'] = fields['title'].replace('&', '&&') fields['index'] = idx + 1 - fmt = config.val.tabs.title.format - fmt_pinned = config.val.tabs.title.format_pinned - - if tab.data.pinned: - title = '' if fmt_pinned is None else fmt_pinned.format(**fields) - else: - title = '' if fmt is None else fmt.format(**fields) - + title = '' if fmt is None else fmt.format(**fields) self.tabBar().setTabText(idx, title) def get_tab_fields(self, idx): From 8504d41db3fa30c392da9b0813e9c6791f546b2a Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 20 Oct 2017 08:58:28 +0200 Subject: [PATCH 94/99] Use Qt API for QtWebEngine scrolling See #2233 Fixes #2822 --- qutebrowser/browser/webengine/webenginetab.py | 50 ++++++++----------- qutebrowser/javascript/scroll.js | 27 ---------- 2 files changed, 20 insertions(+), 57 deletions(-) diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 1e625d93c..2decf3599 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -24,7 +24,7 @@ import functools import html as html_utils import sip -from PyQt5.QtCore import pyqtSlot, Qt, QEvent, QPoint, QUrl, QTimer +from PyQt5.QtCore import pyqtSlot, Qt, QEvent, QPoint, QPointF, QUrl, QTimer from PyQt5.QtGui import QKeyEvent from PyQt5.QtNetwork import QAuthenticator from PyQt5.QtWidgets import QApplication @@ -308,40 +308,30 @@ class WebEngineScroller(browsertab.AbstractScroller): for _ in range(min(count, 5000)): self._tab.key_press(key, modifier) - @pyqtSlot() - def _update_pos(self): + @pyqtSlot(QPointF) + def _update_pos(self, pos): """Update the scroll position attributes when it changed.""" - def update_pos_cb(jsret): - """Callback after getting scroll position via JS.""" - if jsret is None: - # This can happen when the callback would get called after - # shutting down a tab - return - log.webview.vdebug(jsret) - assert isinstance(jsret, dict), jsret - self._pos_px = QPoint(jsret['px']['x'], jsret['px']['y']) + self._pos_px = pos.toPoint() + contents_size = self._widget.page().contentsSize() - dx = jsret['scroll']['width'] - jsret['inner']['width'] - if dx == 0: - perc_x = 0 - else: - perc_x = min(100, round(100 / dx * jsret['px']['x'])) + scrollable_x = contents_size.width() - self._widget.width() + if scrollable_x == 0: + perc_x = 0 + else: + perc_x = min(100, round(100 / scrollable_x * pos.x())) - dy = jsret['scroll']['height'] - jsret['inner']['height'] - if dy == 0: - perc_y = 0 - else: - perc_y = min(100, round(100 / dy * jsret['px']['y'])) + scrollable_y = contents_size.height() - self._widget.height() + if scrollable_y == 0: + perc_y = 0 + else: + perc_y = min(100, round(100 / scrollable_y * pos.y())) - self._at_bottom = math.ceil(jsret['px']['y']) >= dy + self._at_bottom = math.ceil(pos.y()) >= scrollable_y - if (self._pos_perc != (perc_x, perc_y) or - 'no-scroll-filtering' in self._args.debug_flags): - self._pos_perc = perc_x, perc_y - self.perc_changed.emit(*self._pos_perc) - - js_code = javascript.assemble('scroll', 'pos') - self._tab.run_js_async(js_code, update_pos_cb) + if (self._pos_perc != (perc_x, perc_y) or + 'no-scroll-filtering' in self._args.debug_flags): + self._pos_perc = perc_x, perc_y + self.perc_changed.emit(*self._pos_perc) def pos_px(self): return self._pos_px diff --git a/qutebrowser/javascript/scroll.js b/qutebrowser/javascript/scroll.js index 35f412783..188320f11 100644 --- a/qutebrowser/javascript/scroll.js +++ b/qutebrowser/javascript/scroll.js @@ -71,32 +71,5 @@ window._qutebrowser.scroll = (function() { window.scrollBy(dx, dy); }; - funcs.pos = function() { - var pos = { - "px": {"x": window.scrollX, "y": window.scrollY}, - "scroll": { - "width": Math.max( - document.body.scrollWidth, - document.body.offsetWidth, - document.documentElement.scrollWidth, - document.documentElement.offsetWidth - ), - "height": Math.max( - document.body.scrollHeight, - document.body.offsetHeight, - document.documentElement.scrollHeight, - document.documentElement.offsetHeight - ), - }, - "inner": { - "width": window.innerWidth, - "height": window.innerHeight, - }, - }; - - // console.log(JSON.stringify(pos)); - return pos; - }; - return funcs; })(); From c3e9343a6d73d1660f5d92989d84d1702477cc38 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 20 Oct 2017 08:59:27 +0200 Subject: [PATCH 95/99] Update changelog for scrolling improvements See #2233, #2822 --- doc/changelog.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 99b3ef11b..a7fe6cb96 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -37,6 +37,7 @@ Fixed - More consistent sizing for favicons with vertical tabs. - Using `:home` on pinned tabs is now prevented. - Fix crash with unknown file types loaded via qute://help +- Scrolling performance improvements Deprecated ~~~~~~~~~~ From 5fe6e60ffdd045b5fb4cac184290516a2c76235b Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 20 Oct 2017 09:12:23 +0200 Subject: [PATCH 96/99] Fix lint --- qutebrowser/browser/webengine/webenginesettings.py | 4 ++-- qutebrowser/config/configfiles.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/qutebrowser/browser/webengine/webenginesettings.py b/qutebrowser/browser/webengine/webenginesettings.py index b74356727..12503a7c0 100644 --- a/qutebrowser/browser/webengine/webenginesettings.py +++ b/qutebrowser/browser/webengine/webenginesettings.py @@ -36,8 +36,8 @@ from PyQt5.QtWebEngineWidgets import (QWebEngineSettings, QWebEngineProfile, from qutebrowser.browser import shared from qutebrowser.browser.webengine import spell from qutebrowser.config import config, websettings -from qutebrowser.utils import (utils, standarddir, javascript, qtutils, message, - log) +from qutebrowser.utils import (utils, standarddir, javascript, qtutils, + message, log) # The default QWebEngineProfile default_profile = None diff --git a/qutebrowser/config/configfiles.py b/qutebrowser/config/configfiles.py index 605c7372d..1c6ebff13 100644 --- a/qutebrowser/config/configfiles.py +++ b/qutebrowser/config/configfiles.py @@ -260,6 +260,7 @@ class ConfigAPI: self._keyconfig.unbind(key, mode=mode) def source(self, filename): + """Read the given config file from disk.""" if not os.path.isabs(filename): filename = str(self.configdir / filename) From 3dc06aad24b1be667d2841d552a54efeaef8bb3d Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 20 Oct 2017 09:15:22 +0200 Subject: [PATCH 97/99] Update changelog --- doc/changelog.asciidoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index a7fe6cb96..435a8f979 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -30,6 +30,8 @@ Added - New `:tab-give` and `:tab-take` commands, to give tabs to another window, or take them from another window. - New `config.source(...)` method for `config.py` to source another file. +- New `keyhint.radius` option to configure the edge rounding for the key hint + widget. Fixed ~~~~~ From 589e9b71533621d979fbbca89773d0c0afc67253 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 20 Oct 2017 10:05:42 +0200 Subject: [PATCH 98/99] Fix string escaping in config.source test --- tests/unit/config/test_configfiles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/config/test_configfiles.py b/tests/unit/config/test_configfiles.py index c0ba1f1ae..d1ddf9f2b 100644 --- a/tests/unit/config/test_configfiles.py +++ b/tests/unit/config/test_configfiles.py @@ -591,7 +591,7 @@ class TestConfigPy: subfile.write_text("c.content.javascript.enabled = False", encoding='utf-8') - confpy.write("config.source('{}')".format(arg)) + confpy.write("config.source({!r})".format(arg)) confpy.read() assert not config.instance._values['content.javascript.enabled'] From 4c2aeb01a8562608589f2135c024eec7d3185be7 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 20 Oct 2017 12:47:48 +0200 Subject: [PATCH 99/99] Update docs --- doc/help/settings.asciidoc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index d9fddc2f3..eda28c955 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -209,6 +209,7 @@ |<>|Enable Spatial Navigation. |<>|Keychains that shouldn't be shown in the keyhint dialog. |<>|Time from pressing a key to seeing the keyhint dialog (ms). +|<>|The rounding radius for the edges of the keyhint dialog. |<>|Time (in ms) to show messages in the statusbar for. |<>|Show messages in unfocused windows. |<>|How to open links in an existing instance if a new one is launched. @@ -2414,6 +2415,14 @@ Type: <> Default: +pass:[500]+ +[[keyhint.radius]] +=== keyhint.radius +The rounding radius for the edges of the keyhint dialog. + +Type: <> + +Default: +pass:[6]+ + [[messages.timeout]] === messages.timeout Time (in ms) to show messages in the statusbar for.