mirror of
https://github.com/ankitects/anki.git
synced 2025-12-13 14:50:59 -05:00
new search interface, support negating tags, use tag: not t:
This commit is contained in:
parent
62375e37a3
commit
36825006d0
3 changed files with 146 additions and 14 deletions
92
anki/deck.py
92
anki/deck.py
|
|
@ -47,7 +47,7 @@ REV_CARDS_NEW_FIRST = 1
|
||||||
REV_CARDS_DUE_FIRST = 2
|
REV_CARDS_DUE_FIRST = 2
|
||||||
REV_CARDS_RANDOM = 3
|
REV_CARDS_RANDOM = 3
|
||||||
|
|
||||||
DECK_VERSION = 31
|
DECK_VERSION = 32
|
||||||
|
|
||||||
# parts of the code assume we only have one deck
|
# parts of the code assume we only have one deck
|
||||||
decksTable = Table(
|
decksTable = Table(
|
||||||
|
|
@ -1661,6 +1661,85 @@ where id = :id""", pending)
|
||||||
self.finishProgress()
|
self.finishProgress()
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
|
# Find
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
def _parseQuery(self, query):
|
||||||
|
tokens = []
|
||||||
|
res = []
|
||||||
|
# break query into words or phrases
|
||||||
|
for match in re.findall('"(.+?)"|([^ "]+)', query):
|
||||||
|
tokens.append(match[0] or match[1])
|
||||||
|
for c, token in enumerate(tokens):
|
||||||
|
isNeg = token.startswith("-")
|
||||||
|
if isNeg:
|
||||||
|
token = token[1:]
|
||||||
|
isTag = token.startswith("tag:")
|
||||||
|
if isTag:
|
||||||
|
# tag
|
||||||
|
token = token[4:]
|
||||||
|
res.append((token, isNeg, isTag))
|
||||||
|
return res
|
||||||
|
|
||||||
|
def _findCards(self, query):
|
||||||
|
"Find facts matching QUERY."
|
||||||
|
tquery = ""
|
||||||
|
fquery = ""
|
||||||
|
args = {}
|
||||||
|
for c, (token, isNeg, isTag) in enumerate(self._parseQuery(query)):
|
||||||
|
if isTag:
|
||||||
|
# a tag
|
||||||
|
if tquery:
|
||||||
|
if isNeg:
|
||||||
|
tquery += " except "
|
||||||
|
else:
|
||||||
|
tquery += " intersect "
|
||||||
|
elif isNeg:
|
||||||
|
tquery += "select id from cards except "
|
||||||
|
if token == "none":
|
||||||
|
tquery += """
|
||||||
|
select cards.id from cards, facts where facts.tags = ''
|
||||||
|
and cards.factId = facts.id """
|
||||||
|
else:
|
||||||
|
token = token.replace("*", "%")
|
||||||
|
ids = self.s.column0(
|
||||||
|
"select id from tags where tag like :tag", tag=token)
|
||||||
|
tquery += """
|
||||||
|
select cardId from cardTags where
|
||||||
|
cardTags.tagId in %s""" % ids2str(ids)
|
||||||
|
else:
|
||||||
|
# a field
|
||||||
|
if fquery:
|
||||||
|
if isNeg:
|
||||||
|
fquery += " except "
|
||||||
|
else:
|
||||||
|
fquery += " intersect "
|
||||||
|
elif isNeg:
|
||||||
|
fquery += "select id from facts except "
|
||||||
|
args["_ff_%d" % c] = "%"+token+"%"
|
||||||
|
q = "select factId from fields where value like :_ff_%d" % c
|
||||||
|
fquery += q
|
||||||
|
return (tquery, fquery, args)
|
||||||
|
|
||||||
|
def findCardsWhere(self, query):
|
||||||
|
(tquery, fquery, args) = self._findCards(query)
|
||||||
|
q = ""
|
||||||
|
x = []
|
||||||
|
if tquery:
|
||||||
|
x.append(" id in (%s)" % tquery)
|
||||||
|
if fquery:
|
||||||
|
x.append(" factId in (%s)" % fquery)
|
||||||
|
if x:
|
||||||
|
q += " and ".join(x)
|
||||||
|
return q, args
|
||||||
|
|
||||||
|
def findCards(self, query):
|
||||||
|
q, args = self.findCardsWhere(query)
|
||||||
|
query = "select id from cards"
|
||||||
|
if q:
|
||||||
|
query += " where " + q
|
||||||
|
return self.s.column0(query, **args)
|
||||||
|
|
||||||
# Find and replace
|
# Find and replace
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
|
|
@ -2460,9 +2539,9 @@ create index if not exists ix_mediaDeleted_factId on mediaDeleted (mediaId)""")
|
||||||
deck.s.statement("""
|
deck.s.statement("""
|
||||||
create index if not exists ix_tags_tag on tags (tag)""")
|
create index if not exists ix_tags_tag on tags (tag)""")
|
||||||
deck.s.statement("""
|
deck.s.statement("""
|
||||||
create index if not exists ix_cardTags_cardId on cardTags (cardId)""")
|
create index if not exists ix_cardTags_tagCard on cardTags (tagId, cardId)""")
|
||||||
deck.s.statement("""
|
deck.s.statement("""
|
||||||
create index if not exists ix_cardTags_tagId on cardTags (tagId)""")
|
create index if not exists ix_cardTags_cardId on cardTags (cardId)""")
|
||||||
_addIndices = staticmethod(_addIndices)
|
_addIndices = staticmethod(_addIndices)
|
||||||
|
|
||||||
def _addViews(deck):
|
def _addViews(deck):
|
||||||
|
|
@ -2832,6 +2911,13 @@ nextFactor, reps, thinkingTime, yesCount, noCount from reviewHistory""")
|
||||||
deck.version = 31
|
deck.version = 31
|
||||||
deck.s.commit()
|
deck.s.commit()
|
||||||
deck.s.statement("vacuum")
|
deck.s.statement("vacuum")
|
||||||
|
if deck.version < 32:
|
||||||
|
deck.s.execute("drop index if exists ix_cardTags_tagId")
|
||||||
|
deck.s.execute("drop index if exists ix_cardTags_cardId")
|
||||||
|
DeckStorage._addIndices(deck)
|
||||||
|
deck.s.execute("analyze")
|
||||||
|
deck.version = 32
|
||||||
|
deck.s.commit()
|
||||||
# this check we do regardless of version number since doing it on init
|
# this check we do regardless of version number since doing it on init
|
||||||
# seems to crash
|
# seems to crash
|
||||||
if (deck.s.scalar("pragma page_size") == 1024 or
|
if (deck.s.scalar("pragma page_size") == 1024 or
|
||||||
|
|
|
||||||
22
anki/tags.py
22
anki/tags.py
|
|
@ -21,18 +21,18 @@ from anki.db import *
|
||||||
def initTagTables(s):
|
def initTagTables(s):
|
||||||
try:
|
try:
|
||||||
s.statement("""
|
s.statement("""
|
||||||
create table tags (
|
create table tags (
|
||||||
id integer not null,
|
id integer not null,
|
||||||
tag text not null collate nocase,
|
tag text not null collate nocase,
|
||||||
priority integer not null default 2,
|
priority integer not null default 2,
|
||||||
primary key(id))""")
|
primary key(id))""")
|
||||||
s.statement("""
|
s.statement("""
|
||||||
create table cardTags (
|
create table cardTags (
|
||||||
id integer not null,
|
id integer not null,
|
||||||
cardId integer not null,
|
cardId integer not null,
|
||||||
tagId integer not null,
|
tagId integer not null,
|
||||||
src integer not null,
|
src integer not null,
|
||||||
primary key(id))""")
|
primary key(id))""")
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -211,3 +211,49 @@ select question, answer from cards where factId = :id""",
|
||||||
id=f.id)
|
id=f.id)
|
||||||
assert stripHTML(q) == u"e"
|
assert stripHTML(q) == u"e"
|
||||||
assert stripHTML(a) == u"r"
|
assert stripHTML(a) == u"r"
|
||||||
|
|
||||||
|
def test_findCards():
|
||||||
|
deck = DeckStorage.Deck()
|
||||||
|
deck.addModel(BasicModel())
|
||||||
|
f = deck.newFact()
|
||||||
|
f['Front'] = u'dog'
|
||||||
|
f['Back'] = u'cat'
|
||||||
|
f.tags = u"monkey"
|
||||||
|
deck.addFact(f)
|
||||||
|
f = deck.newFact()
|
||||||
|
f['Front'] = u'goats are fun'
|
||||||
|
f['Back'] = u'sheep'
|
||||||
|
f.tags = u"sheep goat horse"
|
||||||
|
deck.addFact(f)
|
||||||
|
f = deck.newFact()
|
||||||
|
f['Front'] = u'cat'
|
||||||
|
f['Back'] = u'sheep'
|
||||||
|
deck.addFact(f)
|
||||||
|
assert not deck.findCards("tag:donkey")
|
||||||
|
assert len(deck.findCards("tag:sheep")) == 1
|
||||||
|
assert len(deck.findCards("tag:sheep tag:goat")) == 1
|
||||||
|
assert len(deck.findCards("tag:sheep tag:monkey")) == 0
|
||||||
|
assert len(deck.findCards("tag:monkey")) == 1
|
||||||
|
assert len(deck.findCards("tag:sheep -tag:monkey")) == 1
|
||||||
|
assert len(deck.findCards("-tag:sheep")) == 2
|
||||||
|
assert len(deck.findCards("cat")) == 2
|
||||||
|
assert len(deck.findCards("cat -dog")) == 1
|
||||||
|
assert len(deck.findCards("cat -dog")) == 1
|
||||||
|
assert len(deck.findCards("are goats")) == 1
|
||||||
|
assert len(deck.findCards('"are goats"')) == 0
|
||||||
|
assert len(deck.findCards('"goats are"')) == 1
|
||||||
|
# make sure card templates and models match too
|
||||||
|
assert len(deck.findCards('tag:basic')) == 3
|
||||||
|
assert len(deck.findCards('tag:forward')) == 3
|
||||||
|
deck.addModel(JapaneseModel())
|
||||||
|
f = deck.newFact()
|
||||||
|
f['Expression'] = u'foo'
|
||||||
|
f['Meaning'] = u'bar'
|
||||||
|
deck.addFact(f)
|
||||||
|
deck.currentModel.cardModels[1].active = True
|
||||||
|
f = deck.newFact()
|
||||||
|
f['Expression'] = u'baz'
|
||||||
|
f['Meaning'] = u'qux'
|
||||||
|
c = deck.addFact(f)
|
||||||
|
assert len(deck.findCards('tag:recognition')) == 2
|
||||||
|
assert len(deck.findCards('tag:recall')) == 1
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue