mirror of
https://github.com/ankitects/anki.git
synced 2025-11-12 07:37:11 -05:00
start on filter/cram updates, deck:filtered
- cram decks no longer pull cards from other cram decks, as tests like is:due don't make sense on crammed decks - cram decks now default to not overriding the original deck's steps - remove obsolote dyn_failed sort order - have to fix this in upgrade - search/limit/order properties have been merged into a list, in case we may want to support multiple queries in the future (eg 10 cards from tag A, 20 cards from tag B) - added a resched option to disable boosting/failure - not yet implemented - added an unused flag to allow cards to persist in the cram deck after graduation. implementing this will take some work and won't come in 2.0 - instead of is:filtereddeck, use deck:filtered
This commit is contained in:
parent
44b4f18e6c
commit
d6bce7c873
6 changed files with 59 additions and 47 deletions
|
|
@ -33,9 +33,8 @@ DYN_RANDOM = 1
|
||||||
DYN_SMALLINT = 2
|
DYN_SMALLINT = 2
|
||||||
DYN_BIGINT = 3
|
DYN_BIGINT = 3
|
||||||
DYN_LAPSES = 4
|
DYN_LAPSES = 4
|
||||||
DYN_FAILED = 5
|
DYN_ADDED = 5
|
||||||
DYN_ADDED = 6
|
DYN_DUE = 6
|
||||||
DYN_DUE = 7
|
|
||||||
|
|
||||||
# model types
|
# model types
|
||||||
MODEL_STD = 0
|
MODEL_STD = 0
|
||||||
|
|
@ -77,7 +76,6 @@ def dynOrderLabels():
|
||||||
2: _("Increasing intervals"),
|
2: _("Increasing intervals"),
|
||||||
3: _("Decreasing intervals"),
|
3: _("Decreasing intervals"),
|
||||||
4: _("Most lapses"),
|
4: _("Most lapses"),
|
||||||
5: _("Failed today"),
|
5: _("Order added"),
|
||||||
6: _("Order added"),
|
6: _("Order due"),
|
||||||
7: _("Order due"),
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,13 +35,13 @@ defaultDynamicDeck = {
|
||||||
'dyn': 1,
|
'dyn': 1,
|
||||||
'desc': "",
|
'desc': "",
|
||||||
'usn': 0,
|
'usn': 0,
|
||||||
'delays': [1, 10],
|
'delays': None,
|
||||||
'separate': True,
|
'separate': True,
|
||||||
'search': "",
|
|
||||||
'limit': 100,
|
|
||||||
'order': 0,
|
|
||||||
# added in beta13
|
# added in beta13
|
||||||
'resched': True,
|
'resched': True,
|
||||||
|
# list of (search, limit, order); we only use first element for now
|
||||||
|
'terms': [["", 100, 0]],
|
||||||
|
'return': True, # currently unused
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConf = {
|
defaultConf = {
|
||||||
|
|
@ -142,7 +142,7 @@ class DeckManager(object):
|
||||||
if deck['dyn']:
|
if deck['dyn']:
|
||||||
# deleting a cramming deck returns cards to their previous deck
|
# deleting a cramming deck returns cards to their previous deck
|
||||||
# rather than deleting the cards
|
# rather than deleting the cards
|
||||||
self.col.sched.remDyn(did)
|
self.col.sched.emptyDyn(did)
|
||||||
if childrenToo:
|
if childrenToo:
|
||||||
for name, id in self.children(did):
|
for name, id in self.children(did):
|
||||||
self.rem(id, cardsToo)
|
self.rem(id, cardsToo)
|
||||||
|
|
|
||||||
|
|
@ -236,10 +236,6 @@ class Finder(object):
|
||||||
return "type = %d" % n
|
return "type = %d" % n
|
||||||
elif val == "suspended":
|
elif val == "suspended":
|
||||||
return "c.queue = -1"
|
return "c.queue = -1"
|
||||||
elif val == "regulardeck":
|
|
||||||
return "not c.odid"
|
|
||||||
elif val == "filterdeck":
|
|
||||||
return "c.odid"
|
|
||||||
elif val == "due":
|
elif val == "due":
|
||||||
return """
|
return """
|
||||||
(c.queue in (2,3) and c.due <= %d) or
|
(c.queue in (2,3) and c.due <= %d) or
|
||||||
|
|
@ -312,6 +308,9 @@ class Finder(object):
|
||||||
# if searching for all decks, skip
|
# if searching for all decks, skip
|
||||||
if val == "*":
|
if val == "*":
|
||||||
return "skip"
|
return "skip"
|
||||||
|
# deck types
|
||||||
|
elif val == "filtered":
|
||||||
|
return "c.odid"
|
||||||
def dids(did):
|
def dids(did):
|
||||||
if not did:
|
if not did:
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ order by due""" % self._deckLimit(),
|
||||||
return card.queue
|
return card.queue
|
||||||
|
|
||||||
def answerButtons(self, card):
|
def answerButtons(self, card):
|
||||||
if not card.odid and card.odue:
|
if card.odue:
|
||||||
conf = self._lapseConf(card)
|
conf = self._lapseConf(card)
|
||||||
if len(conf['delays']) > 1:
|
if len(conf['delays']) > 1:
|
||||||
return 3
|
return 3
|
||||||
|
|
@ -849,22 +849,29 @@ did = ? and queue = 2 and due <= ? limit ?""",
|
||||||
did = did or self.col.decks.selected()
|
did = did or self.col.decks.selected()
|
||||||
deck = self.col.decks.get(did)
|
deck = self.col.decks.get(did)
|
||||||
assert deck['dyn']
|
assert deck['dyn']
|
||||||
# move any existing cards back first
|
# move any existing cards back first, then fill
|
||||||
self.remDyn(did)
|
self.emptyDyn(did)
|
||||||
# gather card ids and sort
|
ids = self._fillDyn(deck)
|
||||||
order = self._dynOrder(deck)
|
if not ids:
|
||||||
limit = " limit %d" % deck['limit']
|
return
|
||||||
search = deck['search'] + " -is:suspended is:regulardeck"
|
|
||||||
try:
|
|
||||||
ids = self.col.findCards(search, order=order+limit)
|
|
||||||
except:
|
|
||||||
ids = []
|
|
||||||
# move the cards over
|
|
||||||
self._moveToDyn(did, ids)
|
|
||||||
# and change to our new deck
|
# and change to our new deck
|
||||||
self.col.decks.select(did)
|
self.col.decks.select(did)
|
||||||
|
return ids
|
||||||
|
|
||||||
def remDyn(self, did, lim=None):
|
def _fillDyn(self, deck):
|
||||||
|
search, limit, order = deck['terms'][0]
|
||||||
|
orderlimit = self._dynOrder(order, limit)
|
||||||
|
search += " -is:suspended -deck:filtered"
|
||||||
|
try:
|
||||||
|
ids = self.col.findCards(search, order=orderlimit)
|
||||||
|
except:
|
||||||
|
ids = []
|
||||||
|
return ids
|
||||||
|
# move the cards over
|
||||||
|
self._moveToDyn(deck['id'], ids)
|
||||||
|
return ids
|
||||||
|
|
||||||
|
def emptyDyn(self, did, lim=None):
|
||||||
if not lim:
|
if not lim:
|
||||||
lim = "did = %s" % did
|
lim = "did = %s" % did
|
||||||
# move out of cram queue
|
# move out of cram queue
|
||||||
|
|
@ -875,28 +882,26 @@ due = odue, odue = 0, odid = 0, usn = ?, mod = ? where %s""" % lim,
|
||||||
self.col.usn(), intTime())
|
self.col.usn(), intTime())
|
||||||
|
|
||||||
def remFromDyn(self, cids):
|
def remFromDyn(self, cids):
|
||||||
self.remDyn(None, "id in %s and odid" % ids2str(cids))
|
self.emptyDyn(None, "id in %s and odid" % ids2str(cids))
|
||||||
|
|
||||||
def _dynOrder(self, deck):
|
def _dynOrder(self, o, l):
|
||||||
o = deck['order']
|
|
||||||
if o == DYN_OLDEST:
|
if o == DYN_OLDEST:
|
||||||
return "c.mod"
|
t = "c.mod"
|
||||||
elif o == DYN_RANDOM:
|
elif o == DYN_RANDOM:
|
||||||
return "random()"
|
t = "random()"
|
||||||
elif o == DYN_SMALLINT:
|
elif o == DYN_SMALLINT:
|
||||||
return "ivl"
|
t = "ivl"
|
||||||
elif o == DYN_BIGINT:
|
elif o == DYN_BIGINT:
|
||||||
return "ivl desc"
|
t = "ivl desc"
|
||||||
elif o == DYN_LAPSES:
|
elif o == DYN_LAPSES:
|
||||||
return "lapses desc"
|
t = "lapses desc"
|
||||||
# elif o == DYN_FAILED:
|
|
||||||
# return """
|
|
||||||
# and c.id in (select cid from revlog where ease = 1 and time > %d)
|
|
||||||
# order by c.mod""" % ((self.dayCutoff-86400)*1000)
|
|
||||||
elif o == DYN_ADDED:
|
elif o == DYN_ADDED:
|
||||||
return "n.id"
|
t = "n.id"
|
||||||
elif o == DYN_DUE:
|
elif o == DYN_DUE:
|
||||||
return "c.due"
|
t = "c.due"
|
||||||
|
else:
|
||||||
|
raise Exception()
|
||||||
|
return t + " limit %d" % l
|
||||||
|
|
||||||
def _moveToDyn(self, did, ids):
|
def _moveToDyn(self, did, ids):
|
||||||
deck = self.col.decks.get(did)
|
deck = self.col.decks.get(did)
|
||||||
|
|
@ -966,12 +971,13 @@ did = ?, queue = %s, due = ?, mod = ?, usn = ? where id = ?""" % queue, data)
|
||||||
return conf['new']
|
return conf['new']
|
||||||
# dynamic deck; override some attributes, use original deck for others
|
# dynamic deck; override some attributes, use original deck for others
|
||||||
oconf = self.col.decks.confForDid(card.odid)
|
oconf = self.col.decks.confForDid(card.odid)
|
||||||
|
delays = conf['delays'] or oconf['new']['delays']
|
||||||
return dict(
|
return dict(
|
||||||
# original deck
|
# original deck
|
||||||
ints=oconf['new']['ints'],
|
ints=oconf['new']['ints'],
|
||||||
initialFactor=oconf['new']['initialFactor'],
|
initialFactor=oconf['new']['initialFactor'],
|
||||||
# overrides
|
# overrides
|
||||||
delays=conf['delays'],
|
delays=delays,
|
||||||
separate=conf['separate'],
|
separate=conf['separate'],
|
||||||
order=NEW_CARDS_DUE,
|
order=NEW_CARDS_DUE,
|
||||||
perDay=self.reportLimit
|
perDay=self.reportLimit
|
||||||
|
|
@ -984,6 +990,7 @@ did = ?, queue = %s, due = ?, mod = ?, usn = ? where id = ?""" % queue, data)
|
||||||
return conf['lapse']
|
return conf['lapse']
|
||||||
# dynamic deck; override some attributes, use original deck for others
|
# dynamic deck; override some attributes, use original deck for others
|
||||||
oconf = self.col.decks.confForDid(card.odid)
|
oconf = self.col.decks.confForDid(card.odid)
|
||||||
|
delays = conf['delays'] or oconf['lapse']['delays']
|
||||||
return dict(
|
return dict(
|
||||||
# original deck
|
# original deck
|
||||||
minInt=oconf['lapse']['minInt'],
|
minInt=oconf['lapse']['minInt'],
|
||||||
|
|
@ -991,7 +998,7 @@ did = ?, queue = %s, due = ?, mod = ?, usn = ? where id = ?""" % queue, data)
|
||||||
leechAction=oconf['lapse']['leechAction'],
|
leechAction=oconf['lapse']['leechAction'],
|
||||||
mult=oconf['lapse']['mult'],
|
mult=oconf['lapse']['mult'],
|
||||||
# overrides
|
# overrides
|
||||||
delays=conf['delays'],
|
delays=delays,
|
||||||
resched=conf['resched'],
|
resched=conf['resched'],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -527,6 +527,12 @@ def test_cram():
|
||||||
assert d.sched.counts() == (1,0,0)
|
assert d.sched.counts() == (1,0,0)
|
||||||
# grab it and check estimates
|
# grab it and check estimates
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
|
assert d.sched.answerButtons(c) == 2
|
||||||
|
assert d.sched.nextIvl(c, 1) == 600
|
||||||
|
assert d.sched.nextIvl(c, 2) == 138*60*60*24
|
||||||
|
cram = d.decks.get(did)
|
||||||
|
cram['delays'] = [1, 10]
|
||||||
|
assert d.sched.answerButtons(c) == 3
|
||||||
assert d.sched.nextIvl(c, 1) == 60
|
assert d.sched.nextIvl(c, 1) == 60
|
||||||
assert d.sched.nextIvl(c, 2) == 600
|
assert d.sched.nextIvl(c, 2) == 600
|
||||||
assert d.sched.nextIvl(c, 3) == 138*60*60*24
|
assert d.sched.nextIvl(c, 3) == 138*60*60*24
|
||||||
|
|
@ -618,7 +624,7 @@ def test_cram_rem():
|
||||||
assert c.type == c.queue == 1
|
assert c.type == c.queue == 1
|
||||||
assert c.due != oldDue
|
assert c.due != oldDue
|
||||||
# if we terminate cramming prematurely it should be set back to new
|
# if we terminate cramming prematurely it should be set back to new
|
||||||
d.sched.remDyn(did)
|
d.sched.emptyDyn(did)
|
||||||
c.load()
|
c.load()
|
||||||
assert c.type == c.queue == 0
|
assert c.type == c.queue == 0
|
||||||
assert c.due == oldDue
|
assert c.due == oldDue
|
||||||
|
|
|
||||||
4
thirdparty/README
vendored
4
thirdparty/README
vendored
|
|
@ -1 +1,3 @@
|
||||||
The files in this folder are covered by their respective licenses.
|
The files in this folder are covered by their respective licenses and are
|
||||||
|
provided to minimize external dependencies. The _portaudio.so files were
|
||||||
|
extracted from Ubuntu 32bit and 64 distributions - check md5s to confirm.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue