diff --git a/rslib/src/decks/mod.rs b/rslib/src/decks/mod.rs index 773cdda6d..fe0290e50 100644 --- a/rslib/src/decks/mod.rs +++ b/rslib/src/decks/mod.rs @@ -1,13 +1,16 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +mod counts; +mod schema11; +mod tree; +mod undo; + pub use crate::backend_proto::{ deck_kind::Kind as DeckKind, filtered_search_term::FilteredSearchOrder, Deck as DeckProto, DeckCommon, DeckKind as DeckKindProto, FilteredDeck, FilteredSearchTerm, NormalDeck, }; -use crate::{ - backend_proto as pb, markdown::render_markdown, text::sanitize_html_no_images, undo::Undo, -}; +use crate::{backend_proto as pb, markdown::render_markdown, text::sanitize_html_no_images}; use crate::{ collection::Collection, deckconf::DeckConfID, @@ -18,9 +21,6 @@ use crate::{ timestamp::TimestampSecs, types::Usn, }; -mod counts; -mod schema11; -mod tree; pub(crate) use counts::DueCounts; pub use schema11::DeckSchema11; use std::{borrow::Cow, sync::Arc}; @@ -285,7 +285,7 @@ impl Collection { // rename children col.rename_child_decks(&existing_deck, &deck.name, usn)?; } - col.update_single_deck_inner_undo_only(deck, &existing_deck)?; + col.update_single_deck_undoable(deck, &existing_deck)?; if name_changed { // after updating, we need to ensure all grandparents exist, which may not be the case // in the parent->child case @@ -312,18 +312,6 @@ impl Collection { self.storage.add_or_update_deck_with_existing_id(deck) } - /// Update an individual, existing deck. Caller is responsible for ensuring deck - /// is normalized, matches parents, is not a duplicate name, and bumping mtime. - pub(crate) fn update_single_deck_inner_undo_only( - &mut self, - deck: &mut Deck, - original: &Deck, - ) -> Result<()> { - self.state.deck_cache.clear(); - self.save_undo(Box::new(DeckUpdated(original.clone()))); - self.storage.update_deck(deck) - } - pub(crate) fn ensure_deck_name_unique(&self, deck: &mut Deck, usn: Usn) -> Result<()> { loop { match self.storage.get_deck_id(&deck.name)? { @@ -371,7 +359,7 @@ impl Collection { let new_name = format!("{}\x1f{}", new_name, child_only.join("\x1f")); child.name = new_name; child.set_modified(usn); - self.update_single_deck_inner_undo_only(&mut child, &original)?; + self.update_single_deck_undoable(&mut child, &original)?; } Ok(()) @@ -601,7 +589,7 @@ impl Collection { deck.reset_stats_if_day_changed(today); mutator(&mut deck.common); deck.set_modified(usn); - self.update_single_deck_inner_undo_only(deck, &original) + self.update_single_deck_undoable(deck, &original) } pub fn drag_drop_decks( @@ -647,19 +635,6 @@ impl Collection { } } -#[derive(Debug)] -pub(crate) struct DeckUpdated(Deck); - -impl Undo for DeckUpdated { - fn undo(mut self: Box, col: &mut crate::collection::Collection) -> Result<()> { - let current = col - .storage - .get_deck(self.0.id)? - .ok_or_else(|| AnkiError::invalid_input("deck disappeared"))?; - col.update_single_deck_inner_undo_only(&mut self.0, ¤t) - } -} - #[cfg(test)] mod test { use super::{human_deck_name_to_native, immediate_parent_name, normalize_native_name}; diff --git a/rslib/src/decks/undo.rs b/rslib/src/decks/undo.rs new file mode 100644 index 000000000..ba41b981a --- /dev/null +++ b/rslib/src/decks/undo.rs @@ -0,0 +1,33 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +use crate::prelude::*; +use crate::undo::Undo; + +#[derive(Debug)] +pub(crate) struct DeckUpdated(Deck); + +impl Undo for DeckUpdated { + fn undo(mut self: Box, col: &mut crate::collection::Collection) -> Result<()> { + let current = col + .storage + .get_deck(self.0.id)? + .ok_or_else(|| AnkiError::invalid_input("deck disappeared"))?; + col.update_single_deck_undoable(&mut self.0, ¤t) + } +} + +impl Collection { + /// Update an individual, existing deck. Caller is responsible for ensuring deck + /// is normalized, matches parents, is not a duplicate name, and bumping mtime. + /// Clears deck cache. + pub(super) fn update_single_deck_undoable( + &mut self, + deck: &mut Deck, + original: &Deck, + ) -> Result<()> { + self.state.deck_cache.clear(); + self.save_undo(Box::new(DeckUpdated(original.clone()))); + self.storage.update_deck(deck) + } +} diff --git a/rslib/src/revlog.rs b/rslib/src/revlog/mod.rs similarity index 72% rename from rslib/src/revlog.rs rename to rslib/src/revlog/mod.rs index 5d5cb9727..d81810c11 100644 --- a/rslib/src/revlog.rs +++ b/rslib/src/revlog/mod.rs @@ -1,11 +1,10 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +mod undo; + +use crate::serde::{default_on_invalid, deserialize_int_from_number}; use crate::{define_newtype, prelude::*}; -use crate::{ - serde::{default_on_invalid, deserialize_int_from_number}, - undo::Undo, -}; use num_enum::TryFromPrimitive; use serde::Deserialize; use serde_repr::{Deserialize_repr, Serialize_repr}; @@ -82,14 +81,6 @@ impl RevlogEntry { } impl Collection { - /// Add the provided revlog entry, modifying the ID if it is not unique. - pub(crate) fn add_revlog_entry(&mut self, mut entry: RevlogEntry) -> Result { - entry.id = self.storage.add_revlog_entry(&entry, true)?; - let id = entry.id; - self.save_undo(Box::new(RevlogAdded(entry))); - Ok(id) - } - pub(crate) fn log_manually_scheduled_review( &mut self, card: &Card, @@ -107,28 +98,7 @@ impl Collection { taken_millis: 0, review_kind: RevlogReviewKind::Manual, }; - self.add_revlog_entry(entry)?; - Ok(()) - } -} - -#[derive(Debug)] -pub(crate) struct RevlogAdded(RevlogEntry); -#[derive(Debug)] -pub(crate) struct RevlogRemoved(RevlogEntry); - -impl Undo for RevlogAdded { - fn undo(self: Box, col: &mut crate::collection::Collection) -> Result<()> { - col.storage.remove_revlog_entry(self.0.id)?; - col.save_undo(Box::new(RevlogRemoved(self.0))); - Ok(()) - } -} - -impl Undo for RevlogRemoved { - fn undo(self: Box, col: &mut crate::collection::Collection) -> Result<()> { - col.storage.add_revlog_entry(&self.0, false)?; - col.save_undo(Box::new(RevlogAdded(self.0))); + self.add_revlog_entry_undoable(entry)?; Ok(()) } } diff --git a/rslib/src/revlog/undo.rs b/rslib/src/revlog/undo.rs new file mode 100644 index 000000000..01d7e1110 --- /dev/null +++ b/rslib/src/revlog/undo.rs @@ -0,0 +1,36 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +use super::RevlogEntry; +use crate::{prelude::*, undo::Undo}; + +#[derive(Debug)] +pub(crate) struct RevlogAdded(RevlogEntry); +#[derive(Debug)] +pub(crate) struct RevlogRemoved(RevlogEntry); + +impl Undo for RevlogAdded { + fn undo(self: Box, col: &mut Collection) -> Result<()> { + col.storage.remove_revlog_entry(self.0.id)?; + col.save_undo(Box::new(RevlogRemoved(self.0))); + Ok(()) + } +} + +impl Undo for RevlogRemoved { + fn undo(self: Box, col: &mut Collection) -> Result<()> { + col.storage.add_revlog_entry(&self.0, false)?; + col.save_undo(Box::new(RevlogAdded(self.0))); + Ok(()) + } +} + +impl Collection { + /// Add the provided revlog entry, modifying the ID if it is not unique. + pub(crate) fn add_revlog_entry_undoable(&mut self, mut entry: RevlogEntry) -> Result { + entry.id = self.storage.add_revlog_entry(&entry, true)?; + let id = entry.id; + self.save_undo(Box::new(RevlogAdded(entry))); + Ok(id) + } +} diff --git a/rslib/src/scheduler/answering/mod.rs b/rslib/src/scheduler/answering/mod.rs index ae695ad97..07e1cad2b 100644 --- a/rslib/src/scheduler/answering/mod.rs +++ b/rslib/src/scheduler/answering/mod.rs @@ -305,7 +305,7 @@ impl Collection { answer.answered_at, answer.milliseconds_taken, ); - self.add_revlog_entry(revlog)?; + self.add_revlog_entry_undoable(revlog)?; Ok(()) } diff --git a/rslib/src/tags.rs b/rslib/src/tags/mod.rs similarity index 96% rename from rslib/src/tags.rs rename to rslib/src/tags/mod.rs index 18c2cea80..7ddc7751a 100644 --- a/rslib/src/tags.rs +++ b/rslib/src/tags/mod.rs @@ -1,6 +1,8 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +mod undo; + use crate::{ backend_proto::TagTreeNode, collection::Collection, @@ -9,7 +11,6 @@ use crate::{ prelude::*, text::{normalize_to_nfc, to_re}, types::Usn, - undo::Undo, }; use regex::{NoExpand, Regex, Replacer}; @@ -244,23 +245,11 @@ impl Collection { } else if let Cow::Owned(new_name) = normalized_name { tag.name = new_name; } - self.register_tag_inner(&tag)?; + self.register_tag_undoable(&tag)?; Ok(true) } } - /// Adds an already-validated tag to the DB and undo list. - /// Caller is responsible for setting usn. - pub(crate) fn register_tag_inner(&mut self, tag: &Tag) -> Result<()> { - self.save_undo(Box::new(AddedTag(tag.clone()))); - self.storage.register_tag(&tag) - } - - pub(crate) fn remove_single_tag(&mut self, tag: &Tag) -> Result<()> { - self.save_undo(Box::new(RemovedTag(tag.clone()))); - self.storage.remove_single_tag(&tag.name) - } - /// If parent tag(s) exist and differ in case, return a rewritten tag. fn adjusted_case_for_parents(&self, tag: &str) -> Result> { if let Some(parent_tag) = self.first_existing_parent_tag(&tag)? { @@ -482,24 +471,6 @@ impl Collection { } } -#[derive(Debug)] -struct AddedTag(Tag); - -#[derive(Debug)] -struct RemovedTag(Tag); - -impl Undo for AddedTag { - fn undo(self: Box, col: &mut Collection) -> Result<()> { - col.remove_single_tag(&self.0) - } -} - -impl Undo for RemovedTag { - fn undo(self: Box, col: &mut Collection) -> Result<()> { - col.register_tag_inner(&self.0) - } -} - #[cfg(test)] mod test { use super::*; diff --git a/rslib/src/tags/undo.rs b/rslib/src/tags/undo.rs new file mode 100644 index 000000000..00297503f --- /dev/null +++ b/rslib/src/tags/undo.rs @@ -0,0 +1,37 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +use super::Tag; +use crate::{prelude::*, undo::Undo}; + +#[derive(Debug)] +struct AddedTag(Tag); + +#[derive(Debug)] +struct RemovedTag(Tag); + +impl Undo for AddedTag { + fn undo(self: Box, col: &mut Collection) -> Result<()> { + col.remove_single_tag_undoable(&self.0) + } +} + +impl Undo for RemovedTag { + fn undo(self: Box, col: &mut Collection) -> Result<()> { + col.register_tag_undoable(&self.0) + } +} + +impl Collection { + /// Adds an already-validated tag to the DB and undo list. + /// Caller is responsible for setting usn. + pub(super) fn register_tag_undoable(&mut self, tag: &Tag) -> Result<()> { + self.save_undo(Box::new(AddedTag(tag.clone()))); + self.storage.register_tag(&tag) + } + + fn remove_single_tag_undoable(&mut self, tag: &Tag) -> Result<()> { + self.save_undo(Box::new(RemovedTag(tag.clone()))); + self.storage.remove_single_tag(&tag.name) + } +}