Anki/rslib/src/scheduler/queue/builder/gathering.rs
RumovZ bb297b95bc
Global new ignore review limit (#2417)
* Add CardAdder test helper

* Add option to have new cards ignore the review limit

Also entails a lot of refactoring because the old code was deeply
coupled to the previous behaviour.

* Add global option to ignore review limit

* Refactor decrementation

* Unify testing
2023-03-06 19:06:12 +10:00

160 lines
5.5 KiB
Rust

// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use super::DueCard;
use super::NewCard;
use super::QueueBuilder;
use crate::deckconfig::NewCardGatherPriority;
use crate::decks::limits::LimitKind;
use crate::prelude::*;
use crate::scheduler::queue::DueCardKind;
use crate::storage::card::NewCardSorting;
impl QueueBuilder {
pub(super) fn gather_cards(&mut self, col: &mut Collection) -> Result<()> {
self.gather_intraday_learning_cards(col)?;
self.gather_due_cards(col, DueCardKind::Learning)?;
self.gather_due_cards(col, DueCardKind::Review)?;
self.gather_new_cards(col)?;
Ok(())
}
fn gather_intraday_learning_cards(&mut self, col: &mut Collection) -> Result<()> {
col.storage.for_each_intraday_card_in_active_decks(
self.context.timing.next_day_at,
|card| {
self.get_and_update_bury_mode_for_note(card.into());
self.learning.push(card);
},
)?;
Ok(())
}
fn gather_due_cards(&mut self, col: &mut Collection, kind: DueCardKind) -> Result<()> {
if self.limits.root_limit_reached(LimitKind::Review) {
return Ok(());
}
col.storage.for_each_due_card_in_active_decks(
self.context.timing.days_elapsed,
self.context.sort_options.review_order,
kind,
|card| {
if self.limits.root_limit_reached(LimitKind::Review) {
return Ok(false);
}
if !self
.limits
.limit_reached(card.current_deck_id, LimitKind::Review)?
&& self.add_due_card(card)
{
self.limits.decrement_deck_and_parent_limits(
card.current_deck_id,
LimitKind::Review,
)?;
}
Ok(true)
},
)
}
fn gather_new_cards(&mut self, col: &mut Collection) -> Result<()> {
match self.context.sort_options.new_gather_priority {
NewCardGatherPriority::Deck => self.gather_new_cards_by_deck(col),
NewCardGatherPriority::LowestPosition => {
self.gather_new_cards_sorted(col, NewCardSorting::LowestPosition)
}
NewCardGatherPriority::HighestPosition => {
self.gather_new_cards_sorted(col, NewCardSorting::HighestPosition)
}
NewCardGatherPriority::RandomNotes => self.gather_new_cards_sorted(
col,
NewCardSorting::RandomNotes(self.context.timing.days_elapsed),
),
NewCardGatherPriority::RandomCards => self.gather_new_cards_sorted(
col,
NewCardSorting::RandomCards(self.context.timing.days_elapsed),
),
}
}
fn gather_new_cards_by_deck(&mut self, col: &mut Collection) -> Result<()> {
for deck_id in self.limits.active_decks() {
if self.limits.root_limit_reached(LimitKind::New) {
break;
}
if self.limits.limit_reached(deck_id, LimitKind::New)? {
continue;
}
col.storage.for_each_new_card_in_deck(deck_id, |card| {
let limit_reached = self.limits.limit_reached(deck_id, LimitKind::New)?;
if !limit_reached && self.add_new_card(card) {
self.limits
.decrement_deck_and_parent_limits(deck_id, LimitKind::New)?;
}
Ok(!limit_reached)
})?;
}
Ok(())
}
fn gather_new_cards_sorted(
&mut self,
col: &mut Collection,
order: NewCardSorting,
) -> Result<()> {
col.storage
.for_each_new_card_in_active_decks(order, |card| {
if self.limits.root_limit_reached(LimitKind::New) {
return Ok(false);
}
if !self
.limits
.limit_reached(card.current_deck_id, LimitKind::New)?
&& self.add_new_card(card)
{
self.limits
.decrement_deck_and_parent_limits(card.current_deck_id, LimitKind::New)?;
}
Ok(true)
})
}
/// True if limit should be decremented.
fn add_due_card(&mut self, card: DueCard) -> bool {
let bury_this_card = self
.get_and_update_bury_mode_for_note(card.into())
.map(|mode| match card.kind {
DueCardKind::Review => mode.bury_reviews,
DueCardKind::Learning => mode.bury_interday_learning,
})
.unwrap_or_default();
if bury_this_card {
false
} else {
match card.kind {
DueCardKind::Review => self.review.push(card),
DueCardKind::Learning => self.day_learning.push(card),
}
true
}
}
// True if limit should be decremented.
fn add_new_card(&mut self, card: NewCard) -> bool {
let bury_this_card = self
.get_and_update_bury_mode_for_note(card.into())
.map(|mode| mode.bury_new)
.unwrap_or_default();
// no previous siblings seen?
if bury_this_card {
false
} else {
self.new.push(card);
true
}
}
}