From ac1b9fadde386ce843e85ee46a370d0c7cf7547f Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 1 Apr 2021 21:09:21 +1000 Subject: [PATCH] merge the filtered deck errors into an enum Fixes the wrong message being shown when trying to move cards to a filtered deck --- pylib/anki/errors.py | 14 ++++--------- rslib/backend.proto | 5 ++--- rslib/src/backend/err.rs | 3 +-- rslib/src/card/mod.rs | 4 ++-- rslib/src/decks/mod.rs | 9 +++++--- rslib/src/error/filtered.rs | 32 +++++++++++++++++++++++++++++ rslib/src/error/mod.rs | 8 ++++---- rslib/src/scheduler/filtered/mod.rs | 3 ++- 8 files changed, 53 insertions(+), 25 deletions(-) create mode 100644 rslib/src/error/filtered.rs diff --git a/pylib/anki/errors.py b/pylib/anki/errors.py index 47bce8c93..0ebcba870 100644 --- a/pylib/anki/errors.py +++ b/pylib/anki/errors.py @@ -50,18 +50,14 @@ class ExistsError(Exception): class DeckRenameError(Exception): - """Legacy error, use DeckIsFilteredError instead.""" + """Legacy error, use FilteredDeckError instead.""" def __init__(self, description: str, *args: object) -> None: super().__init__(description, *args) self.description = description -class DeckIsFilteredError(StringError, DeckRenameError): - pass - - -class FilteredDeckEmpty(StringError): +class FilteredDeckError(StringError, DeckRenameError): pass @@ -95,10 +91,8 @@ def backend_exception_to_pylib(err: _pb.BackendError) -> Exception: return NotFoundError() elif val == "exists": return ExistsError() - elif val == "deck_is_filtered": - return DeckIsFilteredError(err.localized) - elif val == "filtered_deck_empty": - return FilteredDeckEmpty(err.localized) + elif val == "filtered_deck_error": + return FilteredDeckError(err.localized) elif val == "proto_error": return StringError(err.localized) elif val == "search_error": diff --git a/rslib/backend.proto b/rslib/backend.proto index 2ca96464b..88993b155 100644 --- a/rslib/backend.proto +++ b/rslib/backend.proto @@ -568,9 +568,8 @@ message BackendError { string proto_error = 10; Empty not_found_error = 11; Empty exists = 12; - Empty deck_is_filtered = 13; - Empty filtered_deck_empty = 14; - Empty search_error = 15; + Empty filtered_deck_error = 13; + Empty search_error = 14; } } diff --git a/rslib/src/backend/err.rs b/rslib/src/backend/err.rs index 9882cc6c6..5edf8ed15 100644 --- a/rslib/src/backend/err.rs +++ b/rslib/src/backend/err.rs @@ -29,11 +29,10 @@ pub(super) fn anki_error_to_proto_error(err: AnkiError, tr: &I18n) -> pb::Backen AnkiError::ProtoError(info) => V::ProtoError(info), AnkiError::NotFound => V::NotFoundError(pb::Empty {}), AnkiError::Existing => V::Exists(pb::Empty {}), - AnkiError::DeckIsFiltered => V::DeckIsFiltered(pb::Empty {}), + AnkiError::FilteredDeckError(_) => V::FilteredDeckError(pb::Empty {}), AnkiError::SearchError(_) => V::SearchError(pb::Empty {}), AnkiError::TemplateSaveError { .. } => V::TemplateParse(pb::Empty {}), AnkiError::ParseNumError => V::InvalidInput(pb::Empty {}), - AnkiError::FilteredDeckEmpty => V::FilteredDeckEmpty(pb::Empty {}), AnkiError::InvalidRegex(_) => V::InvalidInput(pb::Empty {}), }; diff --git a/rslib/src/card/mod.rs b/rslib/src/card/mod.rs index 06cb1afc5..2b84e682c 100644 --- a/rslib/src/card/mod.rs +++ b/rslib/src/card/mod.rs @@ -3,7 +3,7 @@ pub(crate) mod undo; -use crate::error::{AnkiError, Result}; +use crate::error::{AnkiError, FilteredDeckError, Result}; use crate::notes::NoteId; use crate::{ collection::Collection, config::SchedulerVersion, prelude::*, timestamp::TimestampSecs, @@ -234,7 +234,7 @@ impl Collection { pub fn set_deck(&mut self, cards: &[CardId], deck_id: DeckId) -> Result> { let deck = self.get_deck(deck_id)?.ok_or(AnkiError::NotFound)?; if deck.is_filtered() { - return Err(AnkiError::DeckIsFiltered); + return Err(FilteredDeckError::CanNotMoveCardsInto.into()); } self.storage.set_search_table_to_card_ids(cards, false)?; let sched = self.scheduler_version(); diff --git a/rslib/src/decks/mod.rs b/rslib/src/decks/mod.rs index e102ae46e..c989018d5 100644 --- a/rslib/src/decks/mod.rs +++ b/rslib/src/decks/mod.rs @@ -12,14 +12,17 @@ pub use crate::backend_proto::{ filtered_deck::{search_term::Order as FilteredSearchOrder, SearchTerm as FilteredSearchTerm}, Deck as DeckProto, DeckCommon, DeckKind as DeckKindProto, FilteredDeck, NormalDeck, }; -use crate::{backend_proto as pb, markdown::render_markdown, text::sanitize_html_no_images}; use crate::{ + backend_proto as pb, collection::Collection, deckconf::DeckConfId, define_newtype, + error::FilteredDeckError, error::{AnkiError, Result}, + markdown::render_markdown, prelude::*, text::normalize_to_nfc, + text::sanitize_html_no_images, timestamp::TimestampSecs, types::Usn, }; @@ -421,7 +424,7 @@ impl Collection { let child_split: Vec<_> = deck.name.split('\x1f').collect(); if let Some(parent_deck) = self.first_existing_parent(&deck.name, 0)? { if parent_deck.is_filtered() { - return Err(AnkiError::DeckIsFiltered); + return Err(FilteredDeckError::MustBeLeafNode.into()); } let parent_count = parent_deck.name.matches('\x1f').count() + 1; let need_create = parent_count != child_split.len() - 1; @@ -654,7 +657,7 @@ impl Collection { if let Some(target) = new_parent { if let Some(target) = self.storage.get_deck(target)? { if target.is_filtered() { - return Err(AnkiError::DeckIsFiltered); + return Err(FilteredDeckError::MustBeLeafNode.into()); } target_deck = target; target_name = Some(target_deck.name.as_str()); diff --git a/rslib/src/error/filtered.rs b/rslib/src/error/filtered.rs new file mode 100644 index 000000000..b8fab7009 --- /dev/null +++ b/rslib/src/error/filtered.rs @@ -0,0 +1,32 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +use anki_i18n::I18n; + +use super::AnkiError; + +#[derive(Debug, PartialEq)] +pub enum FilteredDeckError { + MustBeLeafNode, + CanNotMoveCardsInto, + SearchReturnedNoCards, +} + +impl FilteredDeckError { + pub fn localized_description(&self, tr: &I18n) -> String { + match self { + FilteredDeckError::MustBeLeafNode => tr.errors_filtered_parent_deck(), + FilteredDeckError::CanNotMoveCardsInto => { + tr.browsing_cards_cant_be_manually_moved_into() + } + FilteredDeckError::SearchReturnedNoCards => tr.decks_filtered_deck_search_empty(), + } + .into() + } +} + +impl From for AnkiError { + fn from(e: FilteredDeckError) -> Self { + AnkiError::FilteredDeckError(e) + } +} diff --git a/rslib/src/error/mod.rs b/rslib/src/error/mod.rs index 3c4100d87..088fb489c 100644 --- a/rslib/src/error/mod.rs +++ b/rslib/src/error/mod.rs @@ -2,11 +2,13 @@ // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html mod db; +mod filtered; mod network; mod search; pub use { db::{DbError, DbErrorKind}, + filtered::FilteredDeckError, network::{NetworkError, NetworkErrorKind, SyncError, SyncErrorKind}, search::{ParseError, SearchErrorKind}, }; @@ -34,9 +36,8 @@ pub enum AnkiError { CollectionAlreadyOpen, NotFound, Existing, - DeckIsFiltered, + FilteredDeckError(FilteredDeckError), SearchError(SearchErrorKind), - FilteredDeckEmpty, InvalidRegex(String), } @@ -73,8 +74,7 @@ impl AnkiError { } } AnkiError::ParseNumError => tr.errors_parse_number_fail().into(), - AnkiError::DeckIsFiltered => tr.errors_filtered_parent_deck().into(), - AnkiError::FilteredDeckEmpty => tr.decks_filtered_deck_search_empty().into(), + AnkiError::FilteredDeckError(err) => err.localized_description(tr), _ => format!("{:?}", self), } } diff --git a/rslib/src/scheduler/filtered/mod.rs b/rslib/src/scheduler/filtered/mod.rs index 4e91be542..501d4470b 100644 --- a/rslib/src/scheduler/filtered/mod.rs +++ b/rslib/src/scheduler/filtered/mod.rs @@ -8,6 +8,7 @@ use std::convert::{TryFrom, TryInto}; use crate::{ config::ConfigKey, decks::{human_deck_name_to_native, FilteredDeck, FilteredSearchTerm}, + error::FilteredDeckError, search::writer::{deck_search, normalize_search}, }; use crate::{ @@ -176,7 +177,7 @@ impl Collection { // if it failed to match any cards, we revert the changes if count == 0 { - Err(AnkiError::FilteredDeckEmpty) + Err(FilteredDeckError::SearchReturnedNoCards.into()) } else { // update current deck and return id self.set_config(ConfigKey::CurrentDeckId, &deck.id)?;