Implement negate_search

This commit is contained in:
RumovZ 2021-01-06 13:57:35 +01:00
parent 95b4e4cc84
commit 713db05f27
4 changed files with 34 additions and 4 deletions

View file

@ -87,6 +87,7 @@ service BackendService {
rpc NormalizeSearch (String) returns (String);
rpc SearchCards (SearchCardsIn) returns (SearchCardsOut);
rpc SearchNotes (SearchNotesIn) returns (SearchNotesOut);
rpc NegateSearch (String) returns (String);
rpc FindAndReplace (FindAndReplaceIn) returns (UInt32);
// scheduling

View file

@ -32,7 +32,9 @@ use crate::{
},
sched::cutoff::local_minutes_west_for_stamp,
sched::timespan::{answer_button_time, time_span},
search::{normalize_search, SortMode},
search::{
concatenate_searches, negate_search, normalize_search, replace_search_term, SortMode,
},
stats::studied_today,
sync::{
get_remote_sync_meta, sync_abort, sync_login, FullSyncProgress, NormalSyncProgress,
@ -430,6 +432,9 @@ impl BackendService for Backend {
})
}
fn negate_search(&self, input: pb::String) -> Result<pb::String> {
Ok(negate_search(&input.val)?.into())
}
fn find_and_replace(&self, input: pb::FindAndReplaceIn) -> BackendResult<pb::UInt32> {
let mut search = if input.regex {
input.search

View file

@ -5,4 +5,4 @@ mod sqlwriter;
mod writer;
pub use cards::SortMode;
pub use writer::normalize_search;
pub use writer::{concatenate_searches, negate_search, normalize_search, replace_search_term};

View file

@ -14,8 +14,32 @@ pub fn normalize_search(input: &str) -> Result<String> {
Ok(write_nodes(&parse(input)?))
}
fn write_nodes(nodes: &[Node]) -> String {
nodes.iter().map(|node| write_node(node)).collect()
/// Take an Anki-style search string and return the negated counterpart.
/// Empty searches (whole collection) remain unchanged.
pub fn negate_search(input: &str) -> Result<String> {
let mut nodes = parse(input)?;
use Node::*;
Ok(if nodes.len() == 1 {
let node = nodes.remove(0);
match node {
Not(n) => write_node(&n),
Search(SearchNode::WholeCollection) => "".to_string(),
Group(_) | Search(_) => write_node(&Not(Box::new(node))),
_ => unreachable!(),
}
} else {
write_node(&Not(Box::new(Group(nodes))))
})
}
}
}
fn write_nodes<'a, I>(nodes: I) -> String
where
I: IntoIterator<Item = &'a Node<'a>>,
{
nodes.into_iter().map(|node| write_node(node)).collect()
}
fn write_node(node: &Node) -> String {