summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2022-06-13 16:18:42 +0200
committerFlorian Bruhin <me@the-compiler.org>2022-06-13 18:05:37 +0200
commit265b018c172f8c1f6d9e7f8850256363f0629f82 (patch)
tree753c3cafebe47edf1338a953cb85f7a72f6f6cd4
parent583354d524ff42cfb24ff5618d3f8b1919e9d554 (diff)
downloadqutebrowser-265b018c172f8c1f6d9e7f8850256363f0629f82.tar.gz
qutebrowser-265b018c172f8c1f6d9e7f8850256363f0629f82.zip
Add a SearchMatch helper class
-rw-r--r--qutebrowser/browser/browsertab.py53
-rw-r--r--qutebrowser/browser/commands.py24
-rw-r--r--qutebrowser/browser/webengine/webenginetab.py52
-rw-r--r--qutebrowser/mainwindow/mainwindow.py2
-rw-r--r--qutebrowser/mainwindow/statusbar/searchmatch.py17
-rw-r--r--qutebrowser/mainwindow/tabbedbrowser.py7
6 files changed, 85 insertions, 70 deletions
diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py
index f8ac3d24c..7745cff4b 100644
--- a/qutebrowser/browser/browsertab.py
+++ b/qutebrowser/browser/browsertab.py
@@ -287,6 +287,43 @@ class AbstractPrinting:
diag.open(do_print)
+@dataclasses.dataclass
+class SearchMatch:
+
+ """The currently highlighted search match.
+
+ Attributes:
+ current: The currently active search match on the page.
+ 0 if no search is active or the feature isn't available.
+ total: The total number of search matches on the page.
+ 0 if no search is active or the feature isn't available.
+ """
+
+ current: int = 0
+ total: int = 0
+
+ def reset(self) -> None:
+ """Reset match counter information.
+
+ Stale information could lead to next_result or prev_result misbehaving.
+ """
+ self.current = 0
+ self.total = 0
+
+ def at_limit(self, going_up: bool) -> bool:
+ """Whether the SearchMatch is currently at the first/last result."""
+ return (
+ self.total != 0 and
+ (
+ going_up and self.current == 1 or
+ not going_up and self.current == self.total
+ )
+ )
+
+ def __str__(self) -> str:
+ return f"{self.current}/{self.total}"
+
+
class AbstractSearch(QObject):
"""Attribute ``search`` of AbstractTab for doing searches.
@@ -295,23 +332,20 @@ class AbstractSearch(QObject):
text: The last thing this view was searched for.
search_displayed: Whether we're currently displaying search results in
this view.
- current_match: The currently active search match on the page.
- 0 if no search is active or the feature isn't available.
- total_match_count: The total number of search matches on the page.
- 0 if no search is active or the feature isn't available.
+ match: The currently active search match.
_flags: The flags of the last search (needs to be set by subclasses).
_widget: The underlying WebView widget.
Signals:
finished: A search has finished. True if the text was found, false otherwise.
- search_match_changed: The currently active search match has changed.
- Emits (0, 0) if no search is active.
- Will not be emitted if search matches are not available.
+ match_changed: The currently active search match has changed.
+ Emits SearchMatch(0, 0) if no search is active.
+ Will not be emitted if search matches are not available.
cleared: An existing search was cleared.
"""
finished = pyqtSignal(bool)
- search_match_changed = pyqtSignal(int, int)
+ match_changed = pyqtSignal(SearchMatch)
cleared = pyqtSignal()
_Callback = Callable[[bool], None]
@@ -322,8 +356,7 @@ class AbstractSearch(QObject):
self._widget = cast(_WidgetType, None)
self.text: Optional[str] = None
self.search_displayed = False
- self.current_match = 0
- self.total_match_count = 0
+ self.match = SearchMatch()
def _is_case_sensitive(self, ignore_case: usertypes.IgnoreCase) -> bool:
"""Check if case-sensitivity should be used.
diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py
index 939f02108..50dae13ea 100644
--- a/qutebrowser/browser/commands.py
+++ b/qutebrowser/browser/commands.py
@@ -1538,14 +1538,14 @@ class CommandDispatcher:
message.error(str(e))
ed.backup()
- def _search_cb(self, found, *, tab, old_current_match, options, text, prev):
+ def _search_cb(self, found, *, tab, old_match, options, text, prev):
"""Callback called from search/search_next/search_prev.
Args:
found: Whether the text was found.
tab: The AbstractTab in which the search was made.
- old_current_match: The previously active match before the search
- was performed.
+ old_match: The previously active search match before the search was
+ performed.
options: The options (dict) the search was made with.
text: The text searched for.
prev: Whether we're searching backwards (i.e. :search-prev)
@@ -1560,20 +1560,19 @@ class CommandDispatcher:
if not config.val.search.wrap_messages:
return
- new_current_match = tab.search.current_match
# Check if the match count change is opposite to the search direction
- if old_current_match > 0:
+ if old_match.current > 0:
if not going_up:
- if old_current_match > new_current_match:
+ if old_match.current > tab.search.match.current:
message.info("Search hit BOTTOM, continuing at TOP",
replace="search-hit-msg")
- elif old_current_match == new_current_match:
+ elif old_match.current == tab.search.match.current:
message.info("Search hit BOTTOM", replace="search-hit-msg")
elif going_up:
- if old_current_match < new_current_match:
+ if old_match.current < tab.search.match.current:
message.info("Search hit TOP, continuing at BOTTOM",
replace="search-hit-msg")
- elif old_current_match == new_current_match:
+ elif old_match.current == tab.search.match.current:
message.info("Search hit TOP", replace="search-hit-msg")
else:
message.warning(f"Text '{text}' not found on page!",
@@ -1605,7 +1604,8 @@ class CommandDispatcher:
self._tabbed_browser.search_options = dict(options)
cb = functools.partial(self._search_cb, tab=tab,
- old_current_match=0, options=options,
+ old_match=browsertab.SearchMatch(),
+ options=options,
text=text, prev=False)
options['result_cb'] = cb
@@ -1638,7 +1638,7 @@ class CommandDispatcher:
return
cb = functools.partial(self._search_cb, tab=tab,
- old_current_match=tab.search.current_match,
+ old_match=tab.search.match,
options=window_options, text=window_text,
prev=False)
@@ -1672,7 +1672,7 @@ class CommandDispatcher:
return
cb = functools.partial(self._search_cb, tab=tab,
- old_current_match=tab.search.current_match,
+ old_match=tab.search.match,
options=window_options, text=window_text,
prev=True)
diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py
index 1d02f7e99..e513e4e24 100644
--- a/qutebrowser/browser/webengine/webenginetab.py
+++ b/qutebrowser/browser/webengine/webenginetab.py
@@ -112,25 +112,21 @@ class _WebEngineSearchWrapHandler:
self.flag_wrap = True
self.nowrap_available = False
- def prevent_wrapping(self, current_match, total_match_count, *, going_up):
+ def prevent_wrapping(
+ self,
+ match: browsertab.SearchMatch,
+ *,
+ going_up: bool,
+ ) -> None:
"""Prevent wrapping if possible and required.
Returns True if a wrap was prevented and False if not.
Args:
- current_match: The currently active search match on the page.
- total_match_count: The total number of search matches on the page.
+ match: The currently active search match on the page.
going_up: Whether the search would scroll the page up or down.
"""
- return (
- self.nowrap_available and
- not self.flag_wrap and
- total_match_count != 0 and
- (
- going_up and current_match == 1 or
- not going_up and current_match == total_match_count
- )
- )
+ return self.nowrap_available and not self.flag_wrap and match.at_limit(going_up)
class WebEngineSearch(browsertab.AbstractSearch):
@@ -224,11 +220,10 @@ class WebEngineSearch(browsertab.AbstractSearch):
def _on_find_finished(self, find_text_result):
"""Unwrap the result, store it, and pass it along."""
- self.current_match = find_text_result.activeMatch()
- self.total_match_count = find_text_result.numberOfMatches()
- log.webview.debug("Active search match: {}/{}"
- .format(self.current_match, self.total_match_count))
- self.search_match_changed.emit(self.current_match, self.total_match_count)
+ self.match.current = find_text_result.activeMatch()
+ self.match.total = find_text_result.numberOfMatches()
+ log.webview.debug(f"Active search match: {self.match}")
+ self.match_changed.emit(self.match)
def search(self, text, *, ignore_case=usertypes.IgnoreCase.never,
reverse=False, wrap=True, result_cb=None):
@@ -241,7 +236,7 @@ class WebEngineSearch(browsertab.AbstractSearch):
self.text = text
self._flags = self._args_to_flags(reverse, ignore_case)
- self._reset_match_data()
+ self.match.reset()
self._wrap_handler.flag_wrap = wrap
self._find(text, self._flags, result_cb, 'search')
@@ -249,23 +244,21 @@ class WebEngineSearch(browsertab.AbstractSearch):
def clear(self):
if self.search_displayed:
self.cleared.emit()
- self.search_match_changed.emit(0, 0)
+ self.match_changed.emit(browsertab.SearchMatch())
self.search_displayed = False
- self._reset_match_data()
+ self.match.reset()
self._widget.page().findText('')
def prev_result(self, *, result_cb=None):
# The int() here makes sure we get a copy of the flags.
flags = QWebEnginePage.FindFlags(int(self._flags))
if flags & QWebEnginePage.FindBackward:
- if self._wrap_handler.prevent_wrapping(self.current_match,
- self.total_match_count, going_up=False):
+ if self._wrap_handler.prevent_wrapping(self.match, going_up=False):
result_cb(True)
return
flags &= ~QWebEnginePage.FindBackward
else:
- if self._wrap_handler.prevent_wrapping(self.current_match,
- self.total_match_count, going_up=True):
+ if self._wrap_handler.prevent_wrapping(self.match, going_up=True):
result_cb(True)
return
flags |= QWebEnginePage.FindBackward
@@ -273,20 +266,11 @@ class WebEngineSearch(browsertab.AbstractSearch):
def next_result(self, *, result_cb=None):
going_up = self._flags & QWebEnginePage.FindBackward
- if self._wrap_handler.prevent_wrapping(self.current_match,
- self.total_match_count, going_up=going_up):
+ if self._wrap_handler.prevent_wrapping(self.match, going_up=going_up):
result_cb(True)
return
self._find(self.text, self._flags, result_cb, 'next_result')
- def _reset_match_data(self):
- """Reset match counter information.
-
- Stale information could lead to next_result or prev_result misbehaving.
- """
- self.current_match = 0
- self.total_match_count = 0
-
class WebEngineCaret(browsertab.AbstractCaret):
diff --git a/qutebrowser/mainwindow/mainwindow.py b/qutebrowser/mainwindow/mainwindow.py
index c9744cfc1..22245d8c1 100644
--- a/qutebrowser/mainwindow/mainwindow.py
+++ b/qutebrowser/mainwindow/mainwindow.py
@@ -538,7 +538,7 @@ class MainWindow(QWidget):
self.status.url.on_load_status_changed)
self.tabbed_browser.cur_search_match_changed.connect(
- self.status.search_match.set_match_index)
+ self.status.search_match.set_match)
self.tabbed_browser.cur_caret_selection_toggled.connect(
self.status.on_caret_selection_toggled)
diff --git a/qutebrowser/mainwindow/statusbar/searchmatch.py b/qutebrowser/mainwindow/statusbar/searchmatch.py
index 6e9a435de..da337b19a 100644
--- a/qutebrowser/mainwindow/statusbar/searchmatch.py
+++ b/qutebrowser/mainwindow/statusbar/searchmatch.py
@@ -23,6 +23,7 @@
from PyQt5.QtCore import pyqtSlot
from qutebrowser.utils import log
+from qutebrowser.browser import browsertab
from qutebrowser.mainwindow.statusbar import textbase
@@ -30,20 +31,18 @@ class SearchMatch(textbase.TextBase):
"""The part of the statusbar that displays the search match counter."""
- @pyqtSlot(int, int)
- def set_match_index(self, current: int, total: int) -> None:
+ @pyqtSlot(browsertab.SearchMatch)
+ def set_match(self, match: browsertab.SearchMatch) -> None:
"""Set the match counts in the statusbar.
- Passing (0, 0) hides the match counter.
+ Passing SearchMatch(0, 0) hides the match counter.
Args:
- current: The currently active search match.
- total: The total number of search matches on the page.
+ match: The currently active search match.
"""
- if current <= 0 and total <= 0:
+ if match.current <= 0 and match.total <= 0:
self.setText('')
log.statusbar.debug('Clearing search match text.')
else:
- self.setText('Match [{}/{}]'.format(current, total))
- log.statusbar.debug('Setting search match text to {}/{}'
- .format(current, total))
+ self.setText(f'Match [{match}]')
+ log.statusbar.debug(f'Setting search match text to {match}')
diff --git a/qutebrowser/mainwindow/tabbedbrowser.py b/qutebrowser/mainwindow/tabbedbrowser.py
index 9a98b3d70..c623ce809 100644
--- a/qutebrowser/mainwindow/tabbedbrowser.py
+++ b/qutebrowser/mainwindow/tabbedbrowser.py
@@ -202,7 +202,7 @@ class TabbedBrowser(QWidget):
cur_link_hovered = pyqtSignal(str)
cur_scroll_perc_changed = pyqtSignal(int, int)
cur_load_status_changed = pyqtSignal(usertypes.LoadStatus)
- cur_search_match_changed = pyqtSignal(int, int)
+ cur_search_match_changed = pyqtSignal(browsertab.SearchMatch)
cur_fullscreen_requested = pyqtSignal(bool)
cur_caret_selection_toggled = pyqtSignal(browsertab.SelectionState)
close_window = pyqtSignal()
@@ -349,7 +349,7 @@ class TabbedBrowser(QWidget):
self._filter.create(self.cur_fullscreen_requested, tab))
tab.caret.selection_toggled.connect(
self._filter.create(self.cur_caret_selection_toggled, tab))
- tab.search.search_match_changed.connect(
+ tab.search.match_changed.connect(
self._filter.create(self.cur_search_match_changed, tab))
# misc
tab.scroller.perc_changed.connect(self._on_scroll_pos_changed)
@@ -905,8 +905,7 @@ class TabbedBrowser(QWidget):
.format(current_mode.name, mode_on_change))
self._now_focused = tab
self.current_tab_changed.emit(tab)
- self.cur_search_match_changed.emit(tab.search.current_match,
- tab.search.total_match_count)
+ self.cur_search_match_changed.emit(tab.search.match)
QTimer.singleShot(0, self._update_window_title)
self._tab_insert_idx_left = self.widget.currentIndex()
self._tab_insert_idx_right = self.widget.currentIndex() + 1