split search errors into separate file

This commit is contained in:
Damien Elmes 2021-04-01 16:18:28 +10:00
parent 094e4ad461
commit f14a631f68
2 changed files with 136 additions and 128 deletions

View file

@ -1,11 +1,14 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
mod search;
pub use search::{ParseError, SearchErrorKind};
use crate::i18n::I18n;
pub use failure::{Error, Fail};
use nom::error::{ErrorKind as NomErrorKind, ParseError as NomParseError};
use reqwest::StatusCode;
use std::{io, num::ParseIntError, str::Utf8Error};
use std::{io, str::Utf8Error};
use tempfile::PathPersistError;
pub type Result<T, E = AnkiError> = std::result::Result<T, E>;
@ -128,67 +131,7 @@ impl AnkiError {
DbErrorKind::Locked => "Anki already open, or media currently syncing.".into(),
_ => format!("{:?}", self),
},
AnkiError::SearchError(kind) => {
let reason = match kind {
SearchErrorKind::MisplacedAnd => tr.search_misplaced_and(),
SearchErrorKind::MisplacedOr => tr.search_misplaced_or(),
SearchErrorKind::EmptyGroup => tr.search_empty_group(),
SearchErrorKind::UnopenedGroup => tr.search_unopened_group(),
SearchErrorKind::UnclosedGroup => tr.search_unclosed_group(),
SearchErrorKind::EmptyQuote => tr.search_empty_quote(),
SearchErrorKind::UnclosedQuote => tr.search_unclosed_quote(),
SearchErrorKind::MissingKey => tr.search_missing_key(),
SearchErrorKind::UnknownEscape(ctx) => {
tr.search_unknown_escape(ctx.replace('`', "'"))
}
SearchErrorKind::InvalidState(state) => {
tr.search_invalid_argument("is:", state.replace('`', "'"))
}
SearchErrorKind::InvalidFlag => tr.search_invalid_flag(),
SearchErrorKind::InvalidPropProperty(prop) => {
tr.search_invalid_argument("prop:", prop.replace('`', "'"))
}
SearchErrorKind::InvalidPropOperator(ctx) => {
tr.search_invalid_prop_operator(ctx.as_str())
}
SearchErrorKind::Regex(text) => {
format!("<pre>`{}`</pre>", text.replace('`', "'")).into()
}
SearchErrorKind::Other(Some(info)) => info.into(),
SearchErrorKind::Other(None) => tr.search_invalid_other(),
SearchErrorKind::InvalidNumber { provided, context } => tr
.search_invalid_number(
context.replace('`', "'"),
provided.replace('`', "'"),
),
SearchErrorKind::InvalidWholeNumber { provided, context } => tr
.search_invalid_whole_number(
context.replace('`', "'"),
provided.replace('`', "'"),
),
SearchErrorKind::InvalidPositiveWholeNumber { provided, context } => tr
.search_invalid_positive_whole_number(
context.replace('`', "'"),
provided.replace('`', "'"),
),
SearchErrorKind::InvalidNegativeWholeNumber { provided, context } => tr
.search_invalid_negative_whole_number(
context.replace('`', "'"),
provided.replace('`', "'"),
),
SearchErrorKind::InvalidAnswerButton { provided, context } => tr
.search_invalid_answer_button(
context.replace('`', "'"),
provided.replace('`', "'"),
),
};
tr.search_invalid_search(reason).into()
}
AnkiError::SearchError(kind) => kind.localized_description(&tr),
AnkiError::InvalidInput { info } => {
if info.is_empty() {
tr.errors_invalid_input_empty().into()
@ -414,71 +357,6 @@ impl From<PathPersistError> for AnkiError {
}
}
#[derive(Debug, PartialEq)]
pub enum ParseError<'a> {
Anki(&'a str, SearchErrorKind),
Nom(&'a str, NomErrorKind),
}
#[derive(Debug, PartialEq)]
pub enum SearchErrorKind {
MisplacedAnd,
MisplacedOr,
EmptyGroup,
UnopenedGroup,
UnclosedGroup,
EmptyQuote,
UnclosedQuote,
MissingKey,
UnknownEscape(String),
InvalidState(String),
InvalidFlag,
InvalidPropProperty(String),
InvalidPropOperator(String),
InvalidNumber { provided: String, context: String },
InvalidWholeNumber { provided: String, context: String },
InvalidPositiveWholeNumber { provided: String, context: String },
InvalidNegativeWholeNumber { provided: String, context: String },
InvalidAnswerButton { provided: String, context: String },
Regex(String),
Other(Option<String>),
}
impl From<ParseError<'_>> for AnkiError {
fn from(err: ParseError) -> Self {
match err {
ParseError::Anki(_, kind) => AnkiError::SearchError(kind),
ParseError::Nom(_, _) => AnkiError::SearchError(SearchErrorKind::Other(None)),
}
}
}
impl From<nom::Err<ParseError<'_>>> for AnkiError {
fn from(err: nom::Err<ParseError<'_>>) -> Self {
match err {
nom::Err::Error(e) => e.into(),
nom::Err::Failure(e) => e.into(),
nom::Err::Incomplete(_) => AnkiError::SearchError(SearchErrorKind::Other(None)),
}
}
}
impl<'a> NomParseError<&'a str> for ParseError<'a> {
fn from_error_kind(input: &'a str, kind: NomErrorKind) -> Self {
ParseError::Nom(input, kind)
}
fn append(_: &str, _: NomErrorKind, other: Self) -> Self {
other
}
}
impl From<ParseIntError> for AnkiError {
fn from(_err: ParseIntError) -> Self {
AnkiError::ParseNumError
}
}
impl From<regex::Error> for AnkiError {
fn from(_err: regex::Error) -> Self {
AnkiError::InvalidInput {

130
rslib/src/error/search.rs Normal file
View file

@ -0,0 +1,130 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use super::AnkiError;
use anki_i18n::I18n;
use nom::error::{ErrorKind as NomErrorKind, ParseError as NomParseError};
use std::num::ParseIntError;
#[derive(Debug, PartialEq)]
pub enum ParseError<'a> {
Anki(&'a str, SearchErrorKind),
Nom(&'a str, NomErrorKind),
}
#[derive(Debug, PartialEq)]
pub enum SearchErrorKind {
MisplacedAnd,
MisplacedOr,
EmptyGroup,
UnopenedGroup,
UnclosedGroup,
EmptyQuote,
UnclosedQuote,
MissingKey,
UnknownEscape(String),
InvalidState(String),
InvalidFlag,
InvalidPropProperty(String),
InvalidPropOperator(String),
InvalidNumber { provided: String, context: String },
InvalidWholeNumber { provided: String, context: String },
InvalidPositiveWholeNumber { provided: String, context: String },
InvalidNegativeWholeNumber { provided: String, context: String },
InvalidAnswerButton { provided: String, context: String },
Regex(String),
Other(Option<String>),
}
impl From<ParseError<'_>> for AnkiError {
fn from(err: ParseError) -> Self {
match err {
ParseError::Anki(_, kind) => AnkiError::SearchError(kind),
ParseError::Nom(_, _) => AnkiError::SearchError(SearchErrorKind::Other(None)),
}
}
}
impl From<nom::Err<ParseError<'_>>> for AnkiError {
fn from(err: nom::Err<ParseError<'_>>) -> Self {
match err {
nom::Err::Error(e) => e.into(),
nom::Err::Failure(e) => e.into(),
nom::Err::Incomplete(_) => AnkiError::SearchError(SearchErrorKind::Other(None)),
}
}
}
impl<'a> NomParseError<&'a str> for ParseError<'a> {
fn from_error_kind(input: &'a str, kind: NomErrorKind) -> Self {
ParseError::Nom(input, kind)
}
fn append(_: &str, _: NomErrorKind, other: Self) -> Self {
other
}
}
impl From<ParseIntError> for AnkiError {
fn from(_err: ParseIntError) -> Self {
AnkiError::ParseNumError
}
}
impl SearchErrorKind {
pub fn localized_description(&self, tr: &I18n) -> String {
let reason = match self {
SearchErrorKind::MisplacedAnd => tr.search_misplaced_and(),
SearchErrorKind::MisplacedOr => tr.search_misplaced_or(),
SearchErrorKind::EmptyGroup => tr.search_empty_group(),
SearchErrorKind::UnopenedGroup => tr.search_unopened_group(),
SearchErrorKind::UnclosedGroup => tr.search_unclosed_group(),
SearchErrorKind::EmptyQuote => tr.search_empty_quote(),
SearchErrorKind::UnclosedQuote => tr.search_unclosed_quote(),
SearchErrorKind::MissingKey => tr.search_missing_key(),
SearchErrorKind::UnknownEscape(ctx) => tr.search_unknown_escape(ctx.replace('`', "'")),
SearchErrorKind::InvalidState(state) => {
tr.search_invalid_argument("is:", state.replace('`', "'"))
}
SearchErrorKind::InvalidFlag => tr.search_invalid_flag(),
SearchErrorKind::InvalidPropProperty(prop) => {
tr.search_invalid_argument("prop:", prop.replace('`', "'"))
}
SearchErrorKind::InvalidPropOperator(ctx) => {
tr.search_invalid_prop_operator(ctx.as_str())
}
SearchErrorKind::Regex(text) => {
format!("<pre>`{}`</pre>", text.replace('`', "'")).into()
}
SearchErrorKind::Other(Some(info)) => info.into(),
SearchErrorKind::Other(None) => tr.search_invalid_other(),
SearchErrorKind::InvalidNumber { provided, context } => {
tr.search_invalid_number(context.replace('`', "'"), provided.replace('`', "'"))
}
SearchErrorKind::InvalidWholeNumber { provided, context } => tr
.search_invalid_whole_number(context.replace('`', "'"), provided.replace('`', "'")),
SearchErrorKind::InvalidPositiveWholeNumber { provided, context } => tr
.search_invalid_positive_whole_number(
context.replace('`', "'"),
provided.replace('`', "'"),
),
SearchErrorKind::InvalidNegativeWholeNumber { provided, context } => tr
.search_invalid_negative_whole_number(
context.replace('`', "'"),
provided.replace('`', "'"),
),
SearchErrorKind::InvalidAnswerButton { provided, context } => tr
.search_invalid_answer_button(
context.replace('`', "'"),
provided.replace('`', "'"),
),
};
tr.search_invalid_search(reason).into()
}
}