Implement the prefix r: to search for raw input

This commit is contained in:
RumovZ 2020-11-18 22:26:51 +01:00
parent 88d66fc939
commit 6e51bad7db

View File

@ -287,6 +287,7 @@ fn search_node_for_text_with_argument<'a>(
"dupe" => parse_dupes(val)?,
"prop" => parse_prop(val)?,
"re" => SearchNode::Regex(unescape_quotes(val)),
"r" => SearchNode::UnqualifiedText(unescape_raw(val)),
"nc" => SearchNode::NoCombining(unescape(val)?),
"w" => SearchNode::WordBoundary(unescape(val)?),
// anything else is a field search
@ -419,6 +420,12 @@ fn parse_single_field<'a>(key: &'a str, val: &'a str) -> ParseResult<SearchNode<
text: unescape_quotes(&val[3..]),
is_re: true,
}
} else if val.starts_with("r:") {
SearchNode::SingleField {
field: unescape(key)?,
text: unescape_raw(&val[2..]),
is_re: false,
}
} else {
SearchNode::SingleField {
field: unescape(key)?,
@ -437,6 +444,21 @@ fn unescape_quotes(s: &str) -> Cow<str> {
}
}
/// Unescape quotes but escape wildcards and \s.
fn unescape_raw(s: &str) -> Cow<str> {
lazy_static! {
static ref RE: Regex = Regex::new(r#"\\"?|\*|_"#).unwrap();
}
RE.replace_all(&s, |caps: &Captures| match &caps[0] {
r"\" => r"\\",
"\\\"" => "\"",
r"*" => r"\*",
r"_" => r"\_",
_ => unreachable!(),
})
}
/// Unescape chars with special meaning to the parser.
fn unescape(txt: &str) -> ParseResult<Cow<str>> {
if is_invalid_escape(txt) {
Err(ParseError {})
@ -611,12 +633,21 @@ mod test {
vec![Search(Regex(r"\btest\%".into()))]
);
// treat all chars as literals in raw searches
assert_eq!(parse(r"r:\*_"), parse(r"\\\*\_"));
assert_eq!(parse(r"field:r:\*_"), parse(r"field:\\\*\_"));
// no exceptions for escaping "
assert_eq!(
parse(r#"re:te\"st"#)?,
vec![Search(Regex(r#"te"st"#.into()))]
);
assert!(parse(r#"re:te"st"#).is_err());
assert_eq!(
parse(r#"r:te\"st"#)?,
vec![Search(UnqualifiedText(r#"te"st"#.into()))]
);
assert!(parse(r#"r:te"st"#).is_err());
// spaces are optional if node separation is clear
assert_eq!(parse(r#"a"b"(c)"#)?, parse("a b (c)")?);