From 0b73110f820c30e501e82e34d6447c8533ed2da7 Mon Sep 17 00:00:00 2001 From: RumovZ Date: Thu, 14 Jan 2021 11:14:55 +0100 Subject: [PATCH] Make AnkiError::SearchError work with ParseError Use mock ftl strings for now. --- ftl/core/search.ftl | 34 +++++++++++++++++++ rslib/src/err.rs | 68 ++++++++++++++++++++++++++++++++------ rslib/src/search/parser.rs | 5 +-- 3 files changed, 92 insertions(+), 15 deletions(-) diff --git a/ftl/core/search.ftl b/ftl/core/search.ftl index 8bb63dbe7..0a90c18ed 100644 --- a/ftl/core/search.ftl +++ b/ftl/core/search.ftl @@ -1,4 +1,38 @@ +## Errors shown when invalid search input is encountered. + search-invalid = Invalid search - please check for typing mistakes. +# The literal string `AND` is part of the search syntax. +search-misplaced-and = An `AND` was found but it is not connecting two + search terms. If you want to search for the word itself, wrap it in + double quotes: "and". +# The literal string `OR` is part of the search syntax. +search-misplaced-or = An `OR` was found but it is not connecting two + search terms. If you want to search for the word itself, wrap it in + double quotes: "or". +search-empty-group = A group was found but there was nothing between the + parentheses to search for. +search-empty-quote = A quote was found but there was nothing between the + double quotes to search for. +search-unclosed-quote = An opening double quote `"` was found but there + is no second one to close it. +search-missing-key = A colon `:` must be preceded by a key. +search-unknown-escape = The escape sequence `` is unknown. +search-invalid-id-list = error +search-invalid-state = error +search-invalid-flag = error +search-invalid-added = error +search-invalid-edited = error +search-invalid-rated-days = error +search-invalid-rated-ease = error +search-invalid-dupe-mid = error +search-invalid-dupe-text = error +search-invalid-prop-property = error +search-invalid-prop-operator = error +search-invalid-prop-float = error +search-invalid-prop-integer = error +search-invalid-prop-unsigned = error +search-invalid-did = error +search-invalid-mid = error ## Column labels in browse screen diff --git a/rslib/src/err.rs b/rslib/src/err.rs index e5b309c71..5df552a77 100644 --- a/rslib/src/err.rs +++ b/rslib/src/err.rs @@ -60,7 +60,7 @@ pub enum AnkiError { DeckIsFiltered, #[fail(display = "Invalid search.")] - SearchError(Option), + SearchError(ParseErrorKind), } // error helpers @@ -120,13 +120,38 @@ impl AnkiError { DBErrorKind::Locked => "Anki already open, or media currently syncing.".into(), _ => format!("{:?}", self), }, - AnkiError::SearchError(details) => { - if let Some(details) = details { - details.to_owned() - } else { - i18n.tr(TR::SearchInvalid).to_string() - } - } + AnkiError::SearchError(kind) => { match kind { + ParseErrorKind::MisplacedAnd => i18n.tr(TR::SearchMisplacedAnd), + ParseErrorKind::MisplacedOr => i18n.tr(TR::SearchMisplacedOr), + ParseErrorKind::EmptyGroup => i18n.tr(TR::SearchEmptyGroup), + ParseErrorKind::EmptyQuote => i18n.tr(TR::SearchEmptyQuote), + ParseErrorKind::UnclosedQuote => i18n.tr(TR::SearchUnclosedQuote), + ParseErrorKind::MissingKey => i18n.tr(TR::SearchMissingKey), + ParseErrorKind::UnknownEscape(_seq) => i18n.tr(TR::SearchUnknownEscape), + ParseErrorKind::InvalidIdList => i18n.tr(TR::SearchInvalidIdList), + ParseErrorKind::InvalidState => i18n.tr(TR::SearchInvalidState), + ParseErrorKind::InvalidFlag => i18n.tr(TR::SearchInvalidFlag), + ParseErrorKind::InvalidAdded => i18n.tr(TR::SearchInvalidAdded), + ParseErrorKind::InvalidEdited => i18n.tr(TR::SearchInvalidEdited), + ParseErrorKind::InvalidRatedDays => i18n.tr(TR::SearchInvalidRatedDays), + ParseErrorKind::InvalidRatedEase => i18n.tr(TR::SearchInvalidRatedEase), + ParseErrorKind::InvalidDupeMid => i18n.tr(TR::SearchInvalidDupeMid), + ParseErrorKind::InvalidDupeText => i18n.tr(TR::SearchInvalidDupeText), + ParseErrorKind::InvalidPropProperty => i18n.tr(TR::SearchInvalidPropProperty), + ParseErrorKind::InvalidPropOperator => i18n.tr(TR::SearchInvalidPropOperator), + ParseErrorKind::InvalidPropFloat => i18n.tr(TR::SearchInvalidPropFloat), + ParseErrorKind::InvalidPropInteger => i18n.tr(TR::SearchInvalidPropInteger), + ParseErrorKind::InvalidPropUnsigned => i18n.tr(TR::SearchInvalidPropUnsigned), + ParseErrorKind::InvalidDid => i18n.tr(TR::SearchInvalidDid), + ParseErrorKind::InvalidMid => i18n.tr(TR::SearchInvalidMid), + ParseErrorKind::Regex(text) => text.into(), + ParseErrorKind::Other(opt) => if let Some(info) = opt { + info.into() + } else { + i18n.tr(TR::SearchInvalid) + } + }.into() + }, _ => format!("{:?}", self), } } @@ -164,7 +189,7 @@ impl From for AnkiError { }; } if reason.contains("regex parse error") { - return AnkiError::SearchError(Some(reason.to_owned())); + return AnkiError::SearchError(ParseErrorKind::Regex(reason.to_owned())); } } AnkiError::DBError { @@ -351,8 +376,8 @@ pub enum ParseErrorKind { InvalidEdited, InvalidRatedDays, InvalidRatedEase, - InvalidDupesMid, - InvalidDupesText, + InvalidDupeMid, + InvalidDupeText, InvalidPropProperty, InvalidPropOperator, InvalidPropFloat, @@ -360,6 +385,27 @@ pub enum ParseErrorKind { InvalidPropUnsigned, InvalidDid, InvalidMid, + Regex(String), + Other(Option), +} + +impl From> for AnkiError { + fn from(err: ParseError) -> Self { + match err { + ParseError::Anki(_, kind) => AnkiError::SearchError(kind), + ParseError::Nom(_, _) => AnkiError::SearchError(ParseErrorKind::Other(None)), + } + } +} + +impl From>> for AnkiError { + fn from(err: nom::Err>) -> Self { + match err { + nom::Err::Error(e) => e.into(), + nom::Err::Failure(e) => e.into(), + nom::Err::Incomplete(_) => AnkiError::SearchError(ParseErrorKind::Other(None)), + } + } } impl<'a> NomParseError<&'a str> for ParseError<'a> { diff --git a/rslib/src/search/parser.rs b/rslib/src/search/parser.rs index 01f8fe1f9..f3b6ca2b3 100644 --- a/rslib/src/search/parser.rs +++ b/rslib/src/search/parser.rs @@ -110,10 +110,7 @@ pub(super) fn parse(input: &str) -> Result> { return Ok(vec![Node::Search(SearchNode::WholeCollection)]); } - let (_, nodes) = all_consuming(group_inner)(input).map_err(|e| { - dbg!(e); - AnkiError::SearchError(None) - })?; + let (_, nodes) = all_consuming(group_inner)(input)?; Ok(nodes) }