From fda2bfdb4e77721bde478dda21812067da024cb8 Mon Sep 17 00:00:00 2001 From: RumovZ Date: Sat, 9 Jan 2021 10:51:15 +0100 Subject: [PATCH] Use backend filters instead of literal searches --- pylib/anki/rsbackend.py | 7 +++ qt/aqt/browser.py | 113 ++++++++++++++++++---------------------- 2 files changed, 59 insertions(+), 61 deletions(-) diff --git a/pylib/anki/rsbackend.py b/pylib/anki/rsbackend.py index 1653bfe88..26bbc87ec 100644 --- a/pylib/anki/rsbackend.py +++ b/pylib/anki/rsbackend.py @@ -46,6 +46,7 @@ TagUsnTuple = pb.TagUsnTuple NoteType = pb.NoteType DeckTreeNode = pb.DeckTreeNode StockNoteType = pb.StockNoteType +NamedFilter = pb.FilterToSearchIn.NamedFilter ConcatSeparator = pb.ConcatenateSearchesIn.Separator SyncAuth = pb.SyncAuth SyncOutput = pb.SyncCollectionOut @@ -261,6 +262,12 @@ class RustBackend(RustBackendGenerated): err.ParseFromString(err_bytes) raise proto_exception_to_native(err) + def filters_to_searches(self, **kwargs) -> List[str]: + return [ + self.filter_to_search(pb.FilterToSearchIn(**dict([f]))) + for f in kwargs.items() + ] + def translate_string_in( key: TRValue, **kwargs: Union[str, int, float] diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py index 3c448f89b..bb5a5be55 100644 --- a/qt/aqt/browser.py +++ b/qt/aqt/browser.py @@ -4,7 +4,6 @@ from __future__ import annotations import html -import re import time from concurrent.futures import Future from dataclasses import dataclass @@ -21,7 +20,7 @@ from anki.consts import * from anki.lang import without_unicode_isolation from anki.models import NoteType from anki.notes import Note -from anki.rsbackend import ConcatSeparator, DeckTreeNode, InvalidInput +from anki.rsbackend import ConcatSeparator, DeckTreeNode, InvalidInput, NamedFilter from anki.stats import CardStats from anki.utils import htmlToTextLine, ids2str, isMac, isWin from aqt import AnkiQt, gui_hooks @@ -1110,14 +1109,14 @@ QTableView {{ gridline-color: {grid} }} item = SidebarItem( tr(TR.BROWSING_WHOLE_COLLECTION), ":/icons/collection.svg", - self._filterFunc(""), + self._filterFunc(name=NamedFilter.WHOLE_COLLECTION), item_type=SidebarItemType.COLLECTION, ) root.addChild(item) item = SidebarItem( tr(TR.BROWSING_CURRENT_DECK), ":/icons/deck.svg", - self._filterFunc("deck:current"), + self._filterFunc(name=NamedFilter.CURRENT_DECK), item_type=SidebarItemType.CURRENT_DECK, ) root.addChild(item) @@ -1140,7 +1139,7 @@ QTableView {{ gridline-color: {grid} }} item = SidebarItem( t, ":/icons/tag.svg", - lambda t=t: self.setFilter("tag", t), # type: ignore + lambda t=t: self.setFilter(tag=t), # type: ignore item_type=SidebarItemType.TAG, ) root.addChild(item) @@ -1153,7 +1152,7 @@ QTableView {{ gridline-color: {grid} }} def set_filter(): full_name = head + node.name # pylint: disable=cell-var-from-loop - return lambda: self.setFilter("deck", full_name) + return lambda: self.setFilter(deck=full_name) def toggle_expand(): did = node.deck_id # pylint: disable=cell-var-from-loop @@ -1180,7 +1179,7 @@ QTableView {{ gridline-color: {grid} }} item = SidebarItem( m.name, ":/icons/notetype.svg", - lambda m=m: self.setFilter("note", m.name), # type: ignore + lambda m=m: self.setFilter(note=m.name), # type: ignore item_type=SidebarItemType.NOTETYPE, ) root.addChild(item) @@ -1208,47 +1207,38 @@ QTableView {{ gridline-color: {grid} }} ml.popupOver(self.form.filter) - def setFilter(self, *args): - if len(args) == 1: - txt = args[0] - else: - txt = "" - items = [] - for i, a in enumerate(args): - if i % 2 == 0: - txt += a + ":" - else: - txt += re.sub(r'["*_\\]', r"\\\g<0>", a) - txt = '"{}"'.format(txt.replace('"', '\\"')) - items.append(txt) - txt = "" - txt = " AND ".join(items) + def setFilter(self, *args, **kwargs): + # args are literal searches, kwargs are searches provided by the backend try: - if self.mw.app.keyboardModifiers() & Qt.AltModifier: - txt = self.col.backend.negate_search(txt) + filters = self.col.backend.filters_to_searches(**kwargs) + search = self.col.backend.concatenate_searches( + sep=ConcatSeparator.AND, searches=list(args) + filters + ) + mods = self.mw.app.keyboardModifiers() + if mods & Qt.AltModifier: + search = self.col.backend.negate_search(search) cur = str(self.form.searchEdit.lineEdit().text()) if cur != self._searchPrompt: - mods = self.mw.app.keyboardModifiers() if mods & Qt.ControlModifier and mods & Qt.ShiftModifier: - txt = self.col.backend.replace_search_term( - search=cur, replacement=txt + search = self.col.backend.replace_search_term( + search=cur, replacement=search ) elif mods & Qt.ControlModifier: - txt = self.col.backend.concatenate_searches( + search = self.col.backend.concatenate_searches( # pylint: disable=no-member sep=ConcatSeparator.AND, - searches=[cur, txt], + searches=[cur, search], ) elif mods & Qt.ShiftModifier: - txt = self.col.backend.concatenate_searches( + search = self.col.backend.concatenate_searches( # pylint: disable=no-member sep=ConcatSeparator.OR, - searches=[cur, txt], + searches=[cur, search], ) except InvalidInput as e: showWarning(str(e)) else: - self.form.searchEdit.lineEdit().setText(txt) + self.form.searchEdit.lineEdit().setText(search) self.onSearchActivated() def _simpleFilters(self, items): @@ -1257,18 +1247,21 @@ QTableView {{ gridline-color: {grid} }} if row is None: ml.addSeparator() else: - label, filter = row - ml.addItem(label, self._filterFunc(filter)) + label, filter_name = row + ml.addItem(label, self._filterFunc(name=filter_name)) return ml - def _filterFunc(self, *args): - return lambda *, f=args: self.setFilter(*f) + def _filterFunc(self, *args, **kwargs): + return lambda: self.setFilter(*args, **kwargs) def _commonFilters(self): return self._simpleFilters( ( - (tr(TR.BROWSING_WHOLE_COLLECTION), ""), - (tr(TR.BROWSING_CURRENT_DECK), '"deck:current"'), + (tr(TR.BROWSING_WHOLE_COLLECTION), NamedFilter.WHOLE_COLLECTION), + ( + tr(TR.BROWSING_CURRENT_DECK), + NamedFilter.CURRENT_DECK, + ), ) ) @@ -1277,9 +1270,9 @@ QTableView {{ gridline-color: {grid} }} subm.addChild( self._simpleFilters( ( - (tr(TR.BROWSING_ADDED_TODAY), '"added:1"'), - (tr(TR.BROWSING_STUDIED_TODAY), '"rated:1"'), - (tr(TR.BROWSING_AGAIN_TODAY), '"rated:1:1"'), + (tr(TR.BROWSING_ADDED_TODAY), NamedFilter.ADDED_TODAY), + (tr(TR.BROWSING_STUDIED_TODAY), NamedFilter.STUDIED_TODAY), + (tr(TR.BROWSING_AGAIN_TODAY), NamedFilter.AGAIN_TODAY), ) ) ) @@ -1290,20 +1283,20 @@ QTableView {{ gridline-color: {grid} }} subm.addChild( self._simpleFilters( ( - (tr(TR.ACTIONS_NEW), '"is:new"'), - (tr(TR.SCHEDULING_LEARNING), '"is:learn"'), - (tr(TR.SCHEDULING_REVIEW), '"is:review"'), - (tr(TR.FILTERING_IS_DUE), '"is:due"'), + (tr(TR.ACTIONS_NEW), NamedFilter.NEW), + (tr(TR.SCHEDULING_LEARNING), NamedFilter.LEARN), + (tr(TR.SCHEDULING_REVIEW), NamedFilter.REVIEW), + (tr(TR.FILTERING_IS_DUE), NamedFilter.DUE), None, - (tr(TR.BROWSING_SUSPENDED), '"is:suspended"'), - (tr(TR.BROWSING_BURIED), '"is:buried"'), + (tr(TR.BROWSING_SUSPENDED), NamedFilter.SUSPENDED), + (tr(TR.BROWSING_BURIED), NamedFilter.BURIED), None, - (tr(TR.ACTIONS_RED_FLAG), '"flag:1"'), - (tr(TR.ACTIONS_ORANGE_FLAG), '"flag:2"'), - (tr(TR.ACTIONS_GREEN_FLAG), '"flag:3"'), - (tr(TR.ACTIONS_BLUE_FLAG), '"flag:4"'), - (tr(TR.BROWSING_NO_FLAG), '"flag:0"'), - (tr(TR.BROWSING_ANY_FLAG), '"-flag:0"'), + (tr(TR.ACTIONS_RED_FLAG), NamedFilter.RED_FLAG), + (tr(TR.ACTIONS_ORANGE_FLAG), NamedFilter.ORANGE_FLAG), + (tr(TR.ACTIONS_GREEN_FLAG), NamedFilter.GREEN_FLAG), + (tr(TR.ACTIONS_BLUE_FLAG), NamedFilter.BLUE_FLAG), + (tr(TR.BROWSING_NO_FLAG), NamedFilter.NO_FLAG), + (tr(TR.BROWSING_ANY_FLAG), NamedFilter.ANY_FLAG), ) ) ) @@ -1320,7 +1313,7 @@ QTableView {{ gridline-color: {grid} }} tagList = MenuList() for t in sorted(self.col.tags.all(), key=lambda s: s.lower()): - tagList.addItem(self._escapeMenuItem(t), self._filterFunc("tag", t)) + tagList.addItem(self._escapeMenuItem(t), self._filterFunc(tag=t)) m.addChild(tagList.chunked()) return m @@ -1333,13 +1326,11 @@ QTableView {{ gridline-color: {grid} }} fullname = parent_prefix + node.name if node.children: subm = parent.addMenu(escaped_name) - subm.addItem( - tr(TR.ACTIONS_FILTER), self._filterFunc("deck", fullname) - ) + subm.addItem(tr(TR.ACTIONS_FILTER), self._filterFunc(deck=fullname)) subm.addSeparator() addDecks(subm, node.children, fullname + "::") else: - parent.addItem(escaped_name, self._filterFunc("deck", fullname)) + parent.addItem(escaped_name, self._filterFunc(deck=fullname)) alldecks = self.col.decks.deck_tree() ml = MenuList() @@ -1361,12 +1352,12 @@ QTableView {{ gridline-color: {grid} }} escaped_nt_name = self._escapeMenuItem(nt["name"]) # no sub menu if it's a single template if len(nt["tmpls"]) == 1: - noteTypes.addItem(escaped_nt_name, self._filterFunc("note", nt["name"])) + noteTypes.addItem(escaped_nt_name, self._filterFunc(note=nt["name"])) else: subm = noteTypes.addMenu(escaped_nt_name) subm.addItem( - tr(TR.BROWSING_ALL_CARD_TYPES), self._filterFunc("note", nt["name"]) + tr(TR.BROWSING_ALL_CARD_TYPES), self._filterFunc(note=nt["name"]) ) subm.addSeparator() @@ -1380,7 +1371,7 @@ QTableView {{ gridline-color: {grid} }} name=self._escapeMenuItem(tmpl["name"]), ) subm.addItem( - name, self._filterFunc("note", nt["name"], "card", str(c + 1)) + name, self._filterFunc(note=nt["name"], template=c + 1) ) m.addChild(noteTypes.chunked())