mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
Merge pull request #1138 from RumovZ/introduced
Add search keyword for "first review in x days"
This commit is contained in:
commit
2cc23ce2bc
7 changed files with 53 additions and 4 deletions
|
@ -146,6 +146,7 @@ browsing-studied-today = Studied
|
||||||
browsing-added-today = Added
|
browsing-added-today = Added
|
||||||
browsing-again-today = Again
|
browsing-again-today = Again
|
||||||
browsing-edited-today = Edited
|
browsing-edited-today = Edited
|
||||||
|
browsing-sidebar-first-review = First Review
|
||||||
browsing-sidebar-due-today = Due
|
browsing-sidebar-due-today = Due
|
||||||
browsing-sidebar-untagged = Untagged
|
browsing-sidebar-untagged = Untagged
|
||||||
browsing-sidebar-overdue = Overdue
|
browsing-sidebar-overdue = Overdue
|
||||||
|
|
|
@ -513,6 +513,12 @@ class SidebarTreeView(QTreeView):
|
||||||
type=type,
|
type=type,
|
||||||
search_node=SearchNode(rated=SearchNode.Rated(days=1)),
|
search_node=SearchNode(rated=SearchNode.Rated(days=1)),
|
||||||
)
|
)
|
||||||
|
root.add_simple(
|
||||||
|
name=tr.browsing_sidebar_first_review(),
|
||||||
|
icon=icon,
|
||||||
|
type=type,
|
||||||
|
search_node=SearchNode(introduced_in_days=1),
|
||||||
|
)
|
||||||
root.add_simple(
|
root.add_simple(
|
||||||
name=tr.browsing_again_today(),
|
name=tr.browsing_again_today(),
|
||||||
icon=icon,
|
icon=icon,
|
||||||
|
|
|
@ -872,6 +872,7 @@ message SearchNode {
|
||||||
int32 due_on_day = 16;
|
int32 due_on_day = 16;
|
||||||
string tag = 17;
|
string tag = 17;
|
||||||
string note = 18;
|
string note = 18;
|
||||||
|
uint32 introduced_in_days = 19;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ impl TryFrom<pb::SearchNode> for Node {
|
||||||
ease: rated.rating().into(),
|
ease: rated.rating().into(),
|
||||||
}),
|
}),
|
||||||
Filter::AddedInDays(u) => Node::Search(SearchNode::AddedInDays(u)),
|
Filter::AddedInDays(u) => Node::Search(SearchNode::AddedInDays(u)),
|
||||||
|
Filter::IntroducedInDays(u) => Node::Search(SearchNode::IntroducedInDays(u)),
|
||||||
Filter::DueInDays(i) => Node::Search(SearchNode::Property {
|
Filter::DueInDays(i) => Node::Search(SearchNode::Property {
|
||||||
operator: "<=".to_string(),
|
operator: "<=".to_string(),
|
||||||
kind: PropertyKind::Due(i),
|
kind: PropertyKind::Due(i),
|
||||||
|
|
|
@ -74,6 +74,7 @@ pub enum SearchNode {
|
||||||
CardTemplate(TemplateKind),
|
CardTemplate(TemplateKind),
|
||||||
Deck(String),
|
Deck(String),
|
||||||
DeckId(DeckId),
|
DeckId(DeckId),
|
||||||
|
IntroducedInDays(u32),
|
||||||
NotetypeId(NotetypeId),
|
NotetypeId(NotetypeId),
|
||||||
Notetype(String),
|
Notetype(String),
|
||||||
Rated {
|
Rated {
|
||||||
|
@ -334,6 +335,7 @@ fn search_node_for_text_with_argument<'a>(
|
||||||
"prop" => parse_prop(val)?,
|
"prop" => parse_prop(val)?,
|
||||||
"added" => parse_added(val)?,
|
"added" => parse_added(val)?,
|
||||||
"edited" => parse_edited(val)?,
|
"edited" => parse_edited(val)?,
|
||||||
|
"introduced" => parse_introduced(val)?,
|
||||||
"rated" => parse_rated(val)?,
|
"rated" => parse_rated(val)?,
|
||||||
"is" => parse_state(val)?,
|
"is" => parse_state(val)?,
|
||||||
"did" => parse_did(val)?,
|
"did" => parse_did(val)?,
|
||||||
|
@ -528,6 +530,11 @@ fn parse_edited(s: &str) -> ParseResult<SearchNode> {
|
||||||
parse_u32(s, "edited:").map(|n| SearchNode::EditedInDays(n.max(1)))
|
parse_u32(s, "edited:").map(|n| SearchNode::EditedInDays(n.max(1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// eg introduced:1
|
||||||
|
fn parse_introduced(s: &str) -> ParseResult<SearchNode> {
|
||||||
|
parse_u32(s, "introduced:").map(|n| SearchNode::IntroducedInDays(n.max(1)))
|
||||||
|
}
|
||||||
|
|
||||||
/// eg rated:3 or rated:10:2
|
/// eg rated:3 or rated:10:2
|
||||||
/// second arg must be between 1-4
|
/// second arg must be between 1-4
|
||||||
fn parse_rated(s: &str) -> ParseResult<SearchNode> {
|
fn parse_rated(s: &str) -> ParseResult<SearchNode> {
|
||||||
|
|
|
@ -129,6 +129,7 @@ impl SqlWriter<'_> {
|
||||||
// other
|
// other
|
||||||
SearchNode::AddedInDays(days) => self.write_added(*days)?,
|
SearchNode::AddedInDays(days) => self.write_added(*days)?,
|
||||||
SearchNode::EditedInDays(days) => self.write_edited(*days)?,
|
SearchNode::EditedInDays(days) => self.write_edited(*days)?,
|
||||||
|
SearchNode::IntroducedInDays(days) => self.write_introduced(*days)?,
|
||||||
SearchNode::CardTemplate(template) => match template {
|
SearchNode::CardTemplate(template) => match template {
|
||||||
TemplateKind::Ordinal(_) => self.write_template(template),
|
TemplateKind::Ordinal(_) => self.write_template(template),
|
||||||
TemplateKind::Name(name) => {
|
TemplateKind::Name(name) => {
|
||||||
|
@ -479,20 +480,37 @@ impl SqlWriter<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_added(&mut self, days: u32) -> Result<()> {
|
fn previous_day_cutoff(&mut self, days_back: u32) -> Result<TimestampSecs> {
|
||||||
let timing = self.col.timing_today()?;
|
let timing = self.col.timing_today()?;
|
||||||
let cutoff = (timing.next_day_at.0 - (86_400 * (days as i64))) * 1_000;
|
Ok(timing.next_day_at.adding_secs(-86_400 * days_back as i64))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_added(&mut self, days: u32) -> Result<()> {
|
||||||
|
let cutoff = self.previous_day_cutoff(days)?.as_millis();
|
||||||
write!(self.sql, "c.id > {}", cutoff).unwrap();
|
write!(self.sql, "c.id > {}", cutoff).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_edited(&mut self, days: u32) -> Result<()> {
|
fn write_edited(&mut self, days: u32) -> Result<()> {
|
||||||
let timing = self.col.timing_today()?;
|
let cutoff = self.previous_day_cutoff(days)?;
|
||||||
let cutoff = timing.next_day_at.0 - (86_400 * (days as i64));
|
|
||||||
write!(self.sql, "n.mod > {}", cutoff).unwrap();
|
write!(self.sql, "n.mod > {}", cutoff).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_introduced(&mut self, days: u32) -> Result<()> {
|
||||||
|
let cutoff = self.previous_day_cutoff(days)?.as_millis();
|
||||||
|
write!(
|
||||||
|
self.sql,
|
||||||
|
concat!(
|
||||||
|
"(select min(id) > {cutoff} from revlog where cid = c.id)",
|
||||||
|
"and c.id in (select cid from revlog where id > {cutoff})"
|
||||||
|
),
|
||||||
|
cutoff = cutoff,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn write_regex(&mut self, word: &str) {
|
fn write_regex(&mut self, word: &str) {
|
||||||
self.sql.push_str("n.flds regexp ?");
|
self.sql.push_str("n.flds regexp ?");
|
||||||
self.args.push(format!(r"(?i){}", word));
|
self.args.push(format!(r"(?i){}", word));
|
||||||
|
@ -547,6 +565,7 @@ impl SearchNode {
|
||||||
fn required_table(&self) -> RequiredTable {
|
fn required_table(&self) -> RequiredTable {
|
||||||
match self {
|
match self {
|
||||||
SearchNode::AddedInDays(_) => RequiredTable::Cards,
|
SearchNode::AddedInDays(_) => RequiredTable::Cards,
|
||||||
|
SearchNode::IntroducedInDays(_) => RequiredTable::Cards,
|
||||||
SearchNode::Deck(_) => RequiredTable::Cards,
|
SearchNode::Deck(_) => RequiredTable::Cards,
|
||||||
SearchNode::DeckId(_) => RequiredTable::Cards,
|
SearchNode::DeckId(_) => RequiredTable::Cards,
|
||||||
SearchNode::Rated { .. } => RequiredTable::Cards,
|
SearchNode::Rated { .. } => RequiredTable::Cards,
|
||||||
|
@ -652,6 +671,19 @@ mod test {
|
||||||
);
|
);
|
||||||
assert_eq!(s(ctx, "added:0").0, s(ctx, "added:1").0,);
|
assert_eq!(s(ctx, "added:0").0, s(ctx, "added:1").0,);
|
||||||
|
|
||||||
|
// introduced
|
||||||
|
assert_eq!(
|
||||||
|
s(ctx, "introduced:3").0,
|
||||||
|
format!(
|
||||||
|
concat!(
|
||||||
|
"((select min(id) > {cutoff} from revlog where cid = c.id)",
|
||||||
|
"and c.id in (select cid from revlog where id > {cutoff}))"
|
||||||
|
),
|
||||||
|
cutoff = (timing.next_day_at.0 - (86_400 * 3)) * 1_000,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(s(ctx, "introduced:0").0, s(ctx, "introduced:1").0,);
|
||||||
|
|
||||||
// deck
|
// deck
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
s(ctx, "deck:default"),
|
s(ctx, "deck:default"),
|
||||||
|
|
|
@ -84,6 +84,7 @@ fn write_search_node(node: &SearchNode) -> String {
|
||||||
SingleField { field, text, is_re } => write_single_field(field, text, *is_re),
|
SingleField { field, text, is_re } => write_single_field(field, text, *is_re),
|
||||||
AddedInDays(u) => format!("added:{}", u),
|
AddedInDays(u) => format!("added:{}", u),
|
||||||
EditedInDays(u) => format!("edited:{}", u),
|
EditedInDays(u) => format!("edited:{}", u),
|
||||||
|
IntroducedInDays(u) => format!("introduced:{}", u),
|
||||||
CardTemplate(t) => write_template(t),
|
CardTemplate(t) => write_template(t),
|
||||||
Deck(s) => maybe_quote(&format!("deck:{}", s)),
|
Deck(s) => maybe_quote(&format!("deck:{}", s)),
|
||||||
DeckId(DeckIdType(i)) => format!("did:{}", i),
|
DeckId(DeckIdType(i)) => format!("did:{}", i),
|
||||||
|
|
Loading…
Reference in a new issue