Use backend filters instead of literal searches

This commit is contained in:
RumovZ 2021-01-09 10:51:15 +01:00
parent 9ef691c06f
commit fda2bfdb4e
2 changed files with 59 additions and 61 deletions

View file

@ -46,6 +46,7 @@ TagUsnTuple = pb.TagUsnTuple
NoteType = pb.NoteType NoteType = pb.NoteType
DeckTreeNode = pb.DeckTreeNode DeckTreeNode = pb.DeckTreeNode
StockNoteType = pb.StockNoteType StockNoteType = pb.StockNoteType
NamedFilter = pb.FilterToSearchIn.NamedFilter
ConcatSeparator = pb.ConcatenateSearchesIn.Separator ConcatSeparator = pb.ConcatenateSearchesIn.Separator
SyncAuth = pb.SyncAuth SyncAuth = pb.SyncAuth
SyncOutput = pb.SyncCollectionOut SyncOutput = pb.SyncCollectionOut
@ -261,6 +262,12 @@ class RustBackend(RustBackendGenerated):
err.ParseFromString(err_bytes) err.ParseFromString(err_bytes)
raise proto_exception_to_native(err) 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( def translate_string_in(
key: TRValue, **kwargs: Union[str, int, float] key: TRValue, **kwargs: Union[str, int, float]

View file

@ -4,7 +4,6 @@
from __future__ import annotations from __future__ import annotations
import html import html
import re
import time import time
from concurrent.futures import Future from concurrent.futures import Future
from dataclasses import dataclass from dataclasses import dataclass
@ -21,7 +20,7 @@ from anki.consts import *
from anki.lang import without_unicode_isolation from anki.lang import without_unicode_isolation
from anki.models import NoteType from anki.models import NoteType
from anki.notes import Note 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.stats import CardStats
from anki.utils import htmlToTextLine, ids2str, isMac, isWin from anki.utils import htmlToTextLine, ids2str, isMac, isWin
from aqt import AnkiQt, gui_hooks from aqt import AnkiQt, gui_hooks
@ -1110,14 +1109,14 @@ QTableView {{ gridline-color: {grid} }}
item = SidebarItem( item = SidebarItem(
tr(TR.BROWSING_WHOLE_COLLECTION), tr(TR.BROWSING_WHOLE_COLLECTION),
":/icons/collection.svg", ":/icons/collection.svg",
self._filterFunc(""), self._filterFunc(name=NamedFilter.WHOLE_COLLECTION),
item_type=SidebarItemType.COLLECTION, item_type=SidebarItemType.COLLECTION,
) )
root.addChild(item) root.addChild(item)
item = SidebarItem( item = SidebarItem(
tr(TR.BROWSING_CURRENT_DECK), tr(TR.BROWSING_CURRENT_DECK),
":/icons/deck.svg", ":/icons/deck.svg",
self._filterFunc("deck:current"), self._filterFunc(name=NamedFilter.CURRENT_DECK),
item_type=SidebarItemType.CURRENT_DECK, item_type=SidebarItemType.CURRENT_DECK,
) )
root.addChild(item) root.addChild(item)
@ -1140,7 +1139,7 @@ QTableView {{ gridline-color: {grid} }}
item = SidebarItem( item = SidebarItem(
t, t,
":/icons/tag.svg", ":/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, item_type=SidebarItemType.TAG,
) )
root.addChild(item) root.addChild(item)
@ -1153,7 +1152,7 @@ QTableView {{ gridline-color: {grid} }}
def set_filter(): def set_filter():
full_name = head + node.name # pylint: disable=cell-var-from-loop 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(): def toggle_expand():
did = node.deck_id # pylint: disable=cell-var-from-loop did = node.deck_id # pylint: disable=cell-var-from-loop
@ -1180,7 +1179,7 @@ QTableView {{ gridline-color: {grid} }}
item = SidebarItem( item = SidebarItem(
m.name, m.name,
":/icons/notetype.svg", ":/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, item_type=SidebarItemType.NOTETYPE,
) )
root.addChild(item) root.addChild(item)
@ -1208,47 +1207,38 @@ QTableView {{ gridline-color: {grid} }}
ml.popupOver(self.form.filter) ml.popupOver(self.form.filter)
def setFilter(self, *args): def setFilter(self, *args, **kwargs):
if len(args) == 1: # args are literal searches, kwargs are searches provided by the backend
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)
try: try:
if self.mw.app.keyboardModifiers() & Qt.AltModifier: filters = self.col.backend.filters_to_searches(**kwargs)
txt = self.col.backend.negate_search(txt) 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()) cur = str(self.form.searchEdit.lineEdit().text())
if cur != self._searchPrompt: if cur != self._searchPrompt:
mods = self.mw.app.keyboardModifiers()
if mods & Qt.ControlModifier and mods & Qt.ShiftModifier: if mods & Qt.ControlModifier and mods & Qt.ShiftModifier:
txt = self.col.backend.replace_search_term( search = self.col.backend.replace_search_term(
search=cur, replacement=txt search=cur, replacement=search
) )
elif mods & Qt.ControlModifier: elif mods & Qt.ControlModifier:
txt = self.col.backend.concatenate_searches( search = self.col.backend.concatenate_searches(
# pylint: disable=no-member # pylint: disable=no-member
sep=ConcatSeparator.AND, sep=ConcatSeparator.AND,
searches=[cur, txt], searches=[cur, search],
) )
elif mods & Qt.ShiftModifier: elif mods & Qt.ShiftModifier:
txt = self.col.backend.concatenate_searches( search = self.col.backend.concatenate_searches(
# pylint: disable=no-member # pylint: disable=no-member
sep=ConcatSeparator.OR, sep=ConcatSeparator.OR,
searches=[cur, txt], searches=[cur, search],
) )
except InvalidInput as e: except InvalidInput as e:
showWarning(str(e)) showWarning(str(e))
else: else:
self.form.searchEdit.lineEdit().setText(txt) self.form.searchEdit.lineEdit().setText(search)
self.onSearchActivated() self.onSearchActivated()
def _simpleFilters(self, items): def _simpleFilters(self, items):
@ -1257,18 +1247,21 @@ QTableView {{ gridline-color: {grid} }}
if row is None: if row is None:
ml.addSeparator() ml.addSeparator()
else: else:
label, filter = row label, filter_name = row
ml.addItem(label, self._filterFunc(filter)) ml.addItem(label, self._filterFunc(name=filter_name))
return ml return ml
def _filterFunc(self, *args): def _filterFunc(self, *args, **kwargs):
return lambda *, f=args: self.setFilter(*f) return lambda: self.setFilter(*args, **kwargs)
def _commonFilters(self): def _commonFilters(self):
return self._simpleFilters( return self._simpleFilters(
( (
(tr(TR.BROWSING_WHOLE_COLLECTION), ""), (tr(TR.BROWSING_WHOLE_COLLECTION), NamedFilter.WHOLE_COLLECTION),
(tr(TR.BROWSING_CURRENT_DECK), '"deck:current"'), (
tr(TR.BROWSING_CURRENT_DECK),
NamedFilter.CURRENT_DECK,
),
) )
) )
@ -1277,9 +1270,9 @@ QTableView {{ gridline-color: {grid} }}
subm.addChild( subm.addChild(
self._simpleFilters( self._simpleFilters(
( (
(tr(TR.BROWSING_ADDED_TODAY), '"added:1"'), (tr(TR.BROWSING_ADDED_TODAY), NamedFilter.ADDED_TODAY),
(tr(TR.BROWSING_STUDIED_TODAY), '"rated:1"'), (tr(TR.BROWSING_STUDIED_TODAY), NamedFilter.STUDIED_TODAY),
(tr(TR.BROWSING_AGAIN_TODAY), '"rated:1:1"'), (tr(TR.BROWSING_AGAIN_TODAY), NamedFilter.AGAIN_TODAY),
) )
) )
) )
@ -1290,20 +1283,20 @@ QTableView {{ gridline-color: {grid} }}
subm.addChild( subm.addChild(
self._simpleFilters( self._simpleFilters(
( (
(tr(TR.ACTIONS_NEW), '"is:new"'), (tr(TR.ACTIONS_NEW), NamedFilter.NEW),
(tr(TR.SCHEDULING_LEARNING), '"is:learn"'), (tr(TR.SCHEDULING_LEARNING), NamedFilter.LEARN),
(tr(TR.SCHEDULING_REVIEW), '"is:review"'), (tr(TR.SCHEDULING_REVIEW), NamedFilter.REVIEW),
(tr(TR.FILTERING_IS_DUE), '"is:due"'), (tr(TR.FILTERING_IS_DUE), NamedFilter.DUE),
None, None,
(tr(TR.BROWSING_SUSPENDED), '"is:suspended"'), (tr(TR.BROWSING_SUSPENDED), NamedFilter.SUSPENDED),
(tr(TR.BROWSING_BURIED), '"is:buried"'), (tr(TR.BROWSING_BURIED), NamedFilter.BURIED),
None, None,
(tr(TR.ACTIONS_RED_FLAG), '"flag:1"'), (tr(TR.ACTIONS_RED_FLAG), NamedFilter.RED_FLAG),
(tr(TR.ACTIONS_ORANGE_FLAG), '"flag:2"'), (tr(TR.ACTIONS_ORANGE_FLAG), NamedFilter.ORANGE_FLAG),
(tr(TR.ACTIONS_GREEN_FLAG), '"flag:3"'), (tr(TR.ACTIONS_GREEN_FLAG), NamedFilter.GREEN_FLAG),
(tr(TR.ACTIONS_BLUE_FLAG), '"flag:4"'), (tr(TR.ACTIONS_BLUE_FLAG), NamedFilter.BLUE_FLAG),
(tr(TR.BROWSING_NO_FLAG), '"flag:0"'), (tr(TR.BROWSING_NO_FLAG), NamedFilter.NO_FLAG),
(tr(TR.BROWSING_ANY_FLAG), '"-flag:0"'), (tr(TR.BROWSING_ANY_FLAG), NamedFilter.ANY_FLAG),
) )
) )
) )
@ -1320,7 +1313,7 @@ QTableView {{ gridline-color: {grid} }}
tagList = MenuList() tagList = MenuList()
for t in sorted(self.col.tags.all(), key=lambda s: s.lower()): 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()) m.addChild(tagList.chunked())
return m return m
@ -1333,13 +1326,11 @@ QTableView {{ gridline-color: {grid} }}
fullname = parent_prefix + node.name fullname = parent_prefix + node.name
if node.children: if node.children:
subm = parent.addMenu(escaped_name) subm = parent.addMenu(escaped_name)
subm.addItem( subm.addItem(tr(TR.ACTIONS_FILTER), self._filterFunc(deck=fullname))
tr(TR.ACTIONS_FILTER), self._filterFunc("deck", fullname)
)
subm.addSeparator() subm.addSeparator()
addDecks(subm, node.children, fullname + "::") addDecks(subm, node.children, fullname + "::")
else: else:
parent.addItem(escaped_name, self._filterFunc("deck", fullname)) parent.addItem(escaped_name, self._filterFunc(deck=fullname))
alldecks = self.col.decks.deck_tree() alldecks = self.col.decks.deck_tree()
ml = MenuList() ml = MenuList()
@ -1361,12 +1352,12 @@ QTableView {{ gridline-color: {grid} }}
escaped_nt_name = self._escapeMenuItem(nt["name"]) escaped_nt_name = self._escapeMenuItem(nt["name"])
# no sub menu if it's a single template # no sub menu if it's a single template
if len(nt["tmpls"]) == 1: 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: else:
subm = noteTypes.addMenu(escaped_nt_name) subm = noteTypes.addMenu(escaped_nt_name)
subm.addItem( 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() subm.addSeparator()
@ -1380,7 +1371,7 @@ QTableView {{ gridline-color: {grid} }}
name=self._escapeMenuItem(tmpl["name"]), name=self._escapeMenuItem(tmpl["name"]),
) )
subm.addItem( 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()) m.addChild(noteTypes.chunked())