From c1094b66609ff9e750560cf4f24651e1992806a8 Mon Sep 17 00:00:00 2001 From: Justin Partain Date: Thu, 26 Oct 2017 09:16:56 -0400 Subject: [PATCH 1/9] Feature - incremental_search Added config option to find on a page incrementally, renewing the search each time a new character is entered. --- qutebrowser/config/configdata.yml | 5 +++++ qutebrowser/mainwindow/statusbar/command.py | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 1318e8979..4843ad7c8 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -43,6 +43,11 @@ ignore_case: default: smart desc: When to find text on a page case-insensitively. +incremental_search: + type: Bool + default: False + desc: Find text on a page incrementally, renewing the search for each typing character. + new_instance_open_target: type: name: String diff --git a/qutebrowser/mainwindow/statusbar/command.py b/qutebrowser/mainwindow/statusbar/command.py index af2dc3dc9..1a42001c4 100644 --- a/qutebrowser/mainwindow/statusbar/command.py +++ b/qutebrowser/mainwindow/statusbar/command.py @@ -26,7 +26,8 @@ from qutebrowser.keyinput import modeman, modeparsers from qutebrowser.commands import cmdexc, cmdutils from qutebrowser.misc import cmdhistory, editor from qutebrowser.misc import miscwidgets as misc -from qutebrowser.utils import usertypes, log, objreg, message +from qutebrowser.utils import usertypes, log, objreg +from qutebrowser.config import config class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit): @@ -45,6 +46,7 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit): update_completion: Emitted when the completion should be shown/updated. show_cmd: Emitted when command input should be shown. hide_cmd: Emitted when command input can be hidden. + update_search: Emitted when search term could be updated. """ got_cmd = pyqtSignal([str], [str, int]) @@ -53,6 +55,7 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit): update_completion = pyqtSignal() show_cmd = pyqtSignal() hide_cmd = pyqtSignal() + update_search = pyqtSignal() def __init__(self, *, win_id, private, parent=None): misc.CommandLineEdit.__init__(self, parent=parent) @@ -66,6 +69,8 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit): self.cursorPositionChanged.connect(self.update_completion) self.textChanged.connect(self.update_completion) self.textChanged.connect(self.updateGeometry) + self.textChanged.connect(self.update_search) + self.update_search.connect(self.incrementSearch) def prefix(self): """Get the currently entered command prefix.""" @@ -238,3 +243,13 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit): text = 'x' width = self.fontMetrics().width(text) return QSize(width, height) + + def incrementSearch(self): + if config.val.incremental_search == True: + search_prefixes = { + '/': 'search -- ', + '?': 'search -r -- ', + } + if self.prefix() == '/' or self.prefix() == '?': + text = self.text() + self.got_cmd[str].emit(search_prefixes[text[0]] + text[1:]) From 77054cc063793644de415109ebb0a7d6a76ef95a Mon Sep 17 00:00:00 2001 From: Justin Partain Date: Thu, 26 Oct 2017 09:18:34 -0400 Subject: [PATCH 2/9] Make 'Text not found on page!' warnings replace --- qutebrowser/browser/commands.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 3075a24da..8ba3a6f35 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1749,7 +1749,8 @@ class CommandDispatcher: elif going_up and tab.scroller.pos_px().y() > old_scroll_pos.y(): message.info("Search hit TOP, continuing at BOTTOM") else: - message.warning("Text '{}' not found on page!".format(text)) + message.warning("Text '{}' not found on page!".format(text), + replace=True) @cmdutils.register(instance='command-dispatcher', scope='window', maxsplit=0) From bb2fcddcd44d818ea30daa59bb9d9dacf506d669 Mon Sep 17 00:00:00 2001 From: Justin Partain Date: Thu, 26 Oct 2017 10:17:40 -0400 Subject: [PATCH 3/9] Update incremental_search PR with changes from review --- qutebrowser/browser/commands.py | 2 +- qutebrowser/config/configdata.yml | 2 +- qutebrowser/mainwindow/statusbar/command.py | 15 +++++++-------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 8ba3a6f35..c85302c46 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1750,7 +1750,7 @@ class CommandDispatcher: message.info("Search hit TOP, continuing at BOTTOM") else: message.warning("Text '{}' not found on page!".format(text), - replace=True) + replace=True) @cmdutils.register(instance='command-dispatcher', scope='window', maxsplit=0) diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 4843ad7c8..58d3ea0d7 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -45,7 +45,7 @@ ignore_case: incremental_search: type: Bool - default: False + default: True desc: Find text on a page incrementally, renewing the search for each typing character. new_instance_open_target: diff --git a/qutebrowser/mainwindow/statusbar/command.py b/qutebrowser/mainwindow/statusbar/command.py index 1a42001c4..106c2597f 100644 --- a/qutebrowser/mainwindow/statusbar/command.py +++ b/qutebrowser/mainwindow/statusbar/command.py @@ -46,7 +46,6 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit): update_completion: Emitted when the completion should be shown/updated. show_cmd: Emitted when command input should be shown. hide_cmd: Emitted when command input can be hidden. - update_search: Emitted when search term could be updated. """ got_cmd = pyqtSignal([str], [str, int]) @@ -55,7 +54,6 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit): update_completion = pyqtSignal() show_cmd = pyqtSignal() hide_cmd = pyqtSignal() - update_search = pyqtSignal() def __init__(self, *, win_id, private, parent=None): misc.CommandLineEdit.__init__(self, parent=parent) @@ -69,8 +67,7 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit): self.cursorPositionChanged.connect(self.update_completion) self.textChanged.connect(self.update_completion) self.textChanged.connect(self.updateGeometry) - self.textChanged.connect(self.update_search) - self.update_search.connect(self.incrementSearch) + self.textChanged.connect(self._incremental_search) def prefix(self): """Get the currently entered command prefix.""" @@ -244,12 +241,14 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit): width = self.fontMetrics().width(text) return QSize(width, height) - def incrementSearch(self): - if config.val.incremental_search == True: + @pyqtSlot(str) + def _incremental_search(self, text): + if config.val.incremental_search: search_prefixes = { '/': 'search -- ', '?': 'search -r -- ', } - if self.prefix() == '/' or self.prefix() == '?': - text = self.text() + + # len(text) check is for when user presses + if self.prefix() in '/?' and len(text) != 0: self.got_cmd[str].emit(search_prefixes[text[0]] + text[1:]) From 4eebd2a85d0172eec130b661b8d1dbb945514eda Mon Sep 17 00:00:00 2001 From: Justin Partain Date: Thu, 26 Oct 2017 10:50:02 -0400 Subject: [PATCH 4/9] Create config.search.* group with ignore_case and incremental --- qutebrowser/browser/commands.py | 2 +- qutebrowser/config/configdata.yml | 6 +++--- qutebrowser/mainwindow/statusbar/command.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index c85302c46..ec84522c2 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1770,7 +1770,7 @@ class CommandDispatcher: return options = { - 'ignore_case': config.val.ignore_case, + 'ignore_case': config.val.search.ignore_case, 'reverse': reverse, } diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 58d3ea0d7..ab77024a4 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -33,7 +33,7 @@ history_gap_interval: Items with less time between them are grouped when being displayed in `:history`. Use -1 to disable separation. -ignore_case: +search.ignore_case: type: name: String valid_values: @@ -43,10 +43,10 @@ ignore_case: default: smart desc: When to find text on a page case-insensitively. -incremental_search: +search.incremental: type: Bool default: True - desc: Find text on a page incrementally, renewing the search for each typing character. + desc: Find text on a page incrementally, renewing the search for each typed character. new_instance_open_target: type: diff --git a/qutebrowser/mainwindow/statusbar/command.py b/qutebrowser/mainwindow/statusbar/command.py index 106c2597f..ebe48a050 100644 --- a/qutebrowser/mainwindow/statusbar/command.py +++ b/qutebrowser/mainwindow/statusbar/command.py @@ -243,7 +243,7 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit): @pyqtSlot(str) def _incremental_search(self, text): - if config.val.incremental_search: + if config.val.search.incremental: search_prefixes = { '/': 'search -- ', '?': 'search -r -- ', From 8451899a7687b63d80483efe60d530e97226f0f6 Mon Sep 17 00:00:00 2001 From: Justin Partain Date: Thu, 26 Oct 2017 12:03:11 -0400 Subject: [PATCH 5/9] Add block for ignore_case --- qutebrowser/config/configdata.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index ab77024a4..15be675ae 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -33,6 +33,9 @@ history_gap_interval: Items with less time between them are grouped when being displayed in `:history`. Use -1 to disable separation. +ignore_case: + renamed: search.ignore_case + search.ignore_case: type: name: String From 9f511fe18c25343bb0b5f8a0bc064b32ca997663 Mon Sep 17 00:00:00 2001 From: Justin Partain Date: Thu, 26 Oct 2017 13:00:07 -0400 Subject: [PATCH 6/9] pylint fix, change if len(text) to if text --- qutebrowser/mainwindow/statusbar/command.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qutebrowser/mainwindow/statusbar/command.py b/qutebrowser/mainwindow/statusbar/command.py index ebe48a050..5fcb3bee9 100644 --- a/qutebrowser/mainwindow/statusbar/command.py +++ b/qutebrowser/mainwindow/statusbar/command.py @@ -249,6 +249,6 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit): '?': 'search -r -- ', } - # len(text) check is for when user presses - if self.prefix() in '/?' and len(text) != 0: + # `if text` check is for when user presses and `len(text)` is 0 + if self.prefix() in '/?' and text: self.got_cmd[str].emit(search_prefixes[text[0]] + text[1:]) From bcd9d13684e45cf3adc90bebe6d3b1654696fbbc Mon Sep 17 00:00:00 2001 From: Justin Partain Date: Fri, 27 Oct 2017 08:49:22 -0400 Subject: [PATCH 7/9] Update tests to use search.ignore_case --- tests/end2end/features/qutescheme.feature | 14 +++++----- tests/end2end/features/search.feature | 34 +++++++++++------------ tests/end2end/test_invocations.py | 6 ++-- tests/unit/config/test_configcommands.py | 5 ++-- tests/unit/config/test_configdata.py | 2 +- 5 files changed, 31 insertions(+), 30 deletions(-) diff --git a/tests/end2end/features/qutescheme.feature b/tests/end2end/features/qutescheme.feature index 1f13a8ac1..755c103e7 100644 --- a/tests/end2end/features/qutescheme.feature +++ b/tests/end2end/features/qutescheme.feature @@ -99,19 +99,19 @@ Feature: Special qute:// pages # qute://settings Scenario: Focusing input fields in qute://settings and entering valid value - When I set ignore_case to never + When I set search.ignore_case to never And I open qute://settings # scroll to the right - the table does not fit in the default screen And I run :scroll-to-perc -x 100 - And I run :jseval document.getElementById('input-ignore_case').value = '' - And I run :click-element id input-ignore_case + And I run :jseval document.getElementById('input-search.ignore_case').value = '' + And I run :click-element id input-search.ignore_case And I wait for "Entering mode KeyMode.insert *" in the log And I press the keys "always" And I press the key "" # an explicit Tab to unfocus the input field seems to stabilize the tests And I press the key "" - And I wait for "Config option changed: ignore_case *" in the log - Then the option ignore_case should be set to always + And I wait for "Config option changed: search.ignore_case *" in the log + Then the option search.ignore_case should be set to always # Sometimes, an unrelated value gets set @flaky @@ -119,8 +119,8 @@ Feature: Special qute:// pages When I open qute://settings # scroll to the right - the table does not fit in the default screen And I run :scroll-to-perc -x 100 - And I run :jseval document.getElementById('input-ignore_case').value = '' - And I run :click-element id input-ignore_case + And I run :jseval document.getElementById('input-search.ignore_case').value = '' + And I run :click-element id input-search.ignore_case And I wait for "Entering mode KeyMode.insert *" in the log And I press the keys "foo" And I press the key "" diff --git a/tests/end2end/features/search.feature b/tests/end2end/features/search.feature index 56fcca207..d1a00b5b6 100644 --- a/tests/end2end/features/search.feature +++ b/tests/end2end/features/search.feature @@ -22,7 +22,7 @@ Feature: Searching on a page Then "Bar" should be found Scenario: Searching with --reverse - When I set ignore_case to always + When I set search.ignore_case to always And I run :search -r foo And I wait for "search found foo with flags FindBackward" in the log Then "Foo" should be found @@ -52,28 +52,28 @@ Feature: Searching on a page And I wait for "search didn't find blub" in the log Then the warning "Text 'blub' not found on page!" should be shown - ## ignore_case + ## search.ignore_case - Scenario: Searching text with ignore_case = always - When I set ignore_case to always + Scenario: Searching text with search.ignore_case = always + When I set search.ignore_case to always And I run :search bar And I wait for "search found bar" in the log Then "Bar" should be found - Scenario: Searching text with ignore_case = never - When I set ignore_case to never + Scenario: Searching text with search.ignore_case = never + When I set search.ignore_case to never And I run :search bar And I wait for "search found bar with flags FindCaseSensitively" in the log Then "bar" should be found - Scenario: Searching text with ignore_case = smart (lower-case) - When I set ignore_case to smart + Scenario: Searching text with search.ignore_case = smart (lower-case) + When I set search.ignore_case to smart And I run :search bar And I wait for "search found bar" in the log Then "Bar" should be found - Scenario: Searching text with ignore_case = smart (upper-case) - When I set ignore_case to smart + Scenario: Searching text with search.ignore_case = smart (upper-case) + When I set search.ignore_case to smart And I run :search Foo And I wait for "search found Foo with flags FindCaseSensitively" in the log Then "Foo" should be found # even though foo was first @@ -81,7 +81,7 @@ Feature: Searching on a page ## :search-next Scenario: Jumping to next match - When I set ignore_case to always + When I set search.ignore_case to always And I run :search foo And I wait for "search found foo" in the log And I run :search-next @@ -89,7 +89,7 @@ Feature: Searching on a page Then "Foo" should be found Scenario: Jumping to next match with count - When I set ignore_case to always + When I set search.ignore_case to always And I run :search baz And I wait for "search found baz" in the log And I run :search-next with count 2 @@ -97,7 +97,7 @@ Feature: Searching on a page Then "BAZ" should be found Scenario: Jumping to next match with --reverse - When I set ignore_case to always + When I set search.ignore_case to always And I run :search --reverse foo And I wait for "search found foo with flags FindBackward" in the log And I run :search-next @@ -121,7 +121,7 @@ Feature: Searching on a page # https://github.com/qutebrowser/qutebrowser/issues/2438 Scenario: Jumping to next match after clearing - When I set ignore_case to always + When I set search.ignore_case to always And I run :search foo And I wait for "search found foo" in the log And I run :search @@ -132,7 +132,7 @@ Feature: Searching on a page ## :search-prev Scenario: Jumping to previous match - When I set ignore_case to always + When I set search.ignore_case to always And I run :search foo And I wait for "search found foo" in the log And I run :search-next @@ -142,7 +142,7 @@ Feature: Searching on a page Then "foo" should be found Scenario: Jumping to previous match with count - When I set ignore_case to always + When I set search.ignore_case to always And I run :search baz And I wait for "search found baz" in the log And I run :search-next @@ -154,7 +154,7 @@ Feature: Searching on a page Then "baz" should be found Scenario: Jumping to previous match with --reverse - When I set ignore_case to always + When I set search.ignore_case to always And I run :search --reverse foo And I wait for "search found foo with flags FindBackward" in the log And I run :search-next diff --git a/tests/end2end/test_invocations.py b/tests/end2end/test_invocations.py index dc9486142..ef4808718 100644 --- a/tests/end2end/test_invocations.py +++ b/tests/end2end/test_invocations.py @@ -359,14 +359,14 @@ def test_qute_settings_persistence(short_tmpdir, request, quteproc_new): args = _base_args(request.config) + ['--basedir', str(short_tmpdir)] quteproc_new.start(args) quteproc_new.open_path( - 'qute://settings/set?option=ignore_case&value=always') - assert quteproc_new.get_setting('ignore_case') == 'always' + 'qute://settings/set?option=search.ignore_case&value=always') + assert quteproc_new.get_setting('search.ignore_case') == 'always' quteproc_new.send_cmd(':quit') quteproc_new.wait_for_quit() quteproc_new.start(args) - assert quteproc_new.get_setting('ignore_case') == 'always' + assert quteproc_new.get_setting('search.ignore_case') == 'always' @pytest.mark.no_xvfb diff --git a/tests/unit/config/test_configcommands.py b/tests/unit/config/test_configcommands.py index 7137f50db..4c0c833a1 100644 --- a/tests/unit/config/test_configcommands.py +++ b/tests/unit/config/test_configcommands.py @@ -281,7 +281,7 @@ class TestSource: def test_config_source(self, tmpdir, commands, config_stub, config_tmpdir, use_default_dir, clear): assert config_stub.val.content.javascript.enabled - config_stub.val.ignore_case = 'always' + config_stub.val.search.ignore_case = 'always' if use_default_dir: pyfile = config_tmpdir / 'config.py' @@ -295,7 +295,8 @@ class TestSource: commands.config_source(arg, clear=clear) assert not config_stub.val.content.javascript.enabled - assert config_stub.val.ignore_case == ('smart' if clear else 'always') + ignore_case = config_stub.val.search.ignore_case + assert ignore_case == ('smart' if clear else 'always') def test_errors(self, commands, config_tmpdir): pyfile = config_tmpdir / 'config.py' diff --git a/tests/unit/config/test_configdata.py b/tests/unit/config/test_configdata.py index 7edb1b0d6..b7e960ac6 100644 --- a/tests/unit/config/test_configdata.py +++ b/tests/unit/config/test_configdata.py @@ -34,7 +34,7 @@ def test_init(config_stub): # configdata.init() is called by config_stub config_stub.val.aliases = {} assert isinstance(configdata.DATA, dict) - assert 'ignore_case' in configdata.DATA + assert 'search.ignore_case' in configdata.DATA def test_data(config_stub): From aff6510e35c730321e78bfc40f86b3a8210eab31 Mon Sep 17 00:00:00 2001 From: Justin Partain Date: Fri, 27 Oct 2017 08:49:53 -0400 Subject: [PATCH 8/9] Refactor _incremental_search() based on PR review --- qutebrowser/mainwindow/statusbar/command.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/qutebrowser/mainwindow/statusbar/command.py b/qutebrowser/mainwindow/statusbar/command.py index 5fcb3bee9..cddd3b953 100644 --- a/qutebrowser/mainwindow/statusbar/command.py +++ b/qutebrowser/mainwindow/statusbar/command.py @@ -243,12 +243,13 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit): @pyqtSlot(str) def _incremental_search(self, text): - if config.val.search.incremental: - search_prefixes = { - '/': 'search -- ', - '?': 'search -r -- ', - } + if not config.val.search.incremental: + return - # `if text` check is for when user presses and `len(text)` is 0 - if self.prefix() in '/?' and text: - self.got_cmd[str].emit(search_prefixes[text[0]] + text[1:]) + search_prefixes = { + '/': 'search -- ', + '?': 'search -r -- ', + } + + if self.prefix() in ['/', '?']: + self.got_cmd[str].emit(search_prefixes[text[0]] + text[1:]) From 8f5394934f9c0cabaa4711d3658c33a5e51dfa33 Mon Sep 17 00:00:00 2001 From: Justin Partain Date: Tue, 12 Dec 2017 11:32:52 -0500 Subject: [PATCH 9/9] Fix bad merge when rebasing incremental_search feature --- qutebrowser/mainwindow/statusbar/command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/mainwindow/statusbar/command.py b/qutebrowser/mainwindow/statusbar/command.py index cddd3b953..8ae4fd566 100644 --- a/qutebrowser/mainwindow/statusbar/command.py +++ b/qutebrowser/mainwindow/statusbar/command.py @@ -26,7 +26,7 @@ from qutebrowser.keyinput import modeman, modeparsers from qutebrowser.commands import cmdexc, cmdutils from qutebrowser.misc import cmdhistory, editor from qutebrowser.misc import miscwidgets as misc -from qutebrowser.utils import usertypes, log, objreg +from qutebrowser.utils import usertypes, log, objreg, message from qutebrowser.config import config