From 224bad25667e407325db9b248c23da1ed5e458d3 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 20 Mar 2020 11:54:39 +1000 Subject: [PATCH] handle empty searches and leading/trailing whitespace --- rslib/src/search/parser.rs | 30 ++++++++++++++++++++++++++++-- rslib/src/search/sqlwriter.rs | 1 + 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/rslib/src/search/parser.rs b/rslib/src/search/parser.rs index 03ad4692b..98252e90a 100644 --- a/rslib/src/search/parser.rs +++ b/rslib/src/search/parser.rs @@ -76,6 +76,7 @@ pub(super) enum SearchNode<'a> { operator: String, kind: PropertyKind, }, + WholeCollection, } #[derive(Debug, PartialEq)] @@ -106,6 +107,11 @@ pub(super) enum TemplateKind { /// Parse the input string into a list of nodes. #[allow(dead_code)] pub(super) fn parse(input: &str) -> Result> { + let input = input.trim(); + if input.is_empty() { + return Ok(vec![Node::Search(SearchNode::WholeCollection)]); + } + let (_, nodes) = all_consuming(group_inner)(input) .map_err(|_e| AnkiError::invalid_input("unable to parse search"))?; Ok(nodes) @@ -150,12 +156,19 @@ fn group_inner(input: &str) -> IResult<&str, Vec> { }; } - Ok((remaining, nodes)) + if nodes.is_empty() { + Err(nom::Err::Error((remaining, nom::error::ErrorKind::Many1))) + } else { + Ok((remaining, nodes)) + } +} + +fn whitespace0(s: &str) -> IResult<&str, Vec> { + many0(one_of(" \u{3000}"))(s) } /// Optional leading space, then a (negated) group or text fn node(s: &str) -> IResult<&str, Node> { - let whitespace0 = many0(one_of(" \u{3000}")); preceded(whitespace0, alt((negated_node, group, text)))(s) } @@ -374,6 +387,19 @@ mod test { use Node::*; use SearchNode::*; + assert_eq!(parse("")?, vec![Search(SearchNode::WholeCollection)]); + assert_eq!(parse(" ")?, vec![Search(SearchNode::WholeCollection)]); + + // leading/trailing/interspersed whitespace + assert_eq!( + parse(" t t2 ")?, + vec![ + Search(UnqualifiedText("t".into())), + And, + Search(UnqualifiedText("t2".into())) + ] + ); + assert_eq!( parse(r#"hello -(world and "foo:bar baz") OR test"#)?, vec![ diff --git a/rslib/src/search/sqlwriter.rs b/rslib/src/search/sqlwriter.rs index 268df9e2a..2501f806c 100644 --- a/rslib/src/search/sqlwriter.rs +++ b/rslib/src/search/sqlwriter.rs @@ -79,6 +79,7 @@ impl SqlWriter<'_, '_> { write!(self.sql, "c.id in ({})", cids).unwrap(); } SearchNode::Property { operator, kind } => self.write_prop(operator, kind)?, + SearchNode::WholeCollection => write!(self.sql, "true").unwrap(), }; Ok(()) }