From 2bbd1fca2a2477fd89aaab9631fbeb0883eb8208 Mon Sep 17 00:00:00 2001 From: RumovZ Date: Wed, 6 Jul 2022 11:26:14 +0200 Subject: [PATCH] Skip card generation if fronts remain unchanged (#1949) Closes #1945 --- rslib/src/notetype/mod.rs | 2 +- rslib/src/notetype/schemachange.rs | 88 +++++++++++++++++++----------- 2 files changed, 57 insertions(+), 33 deletions(-) diff --git a/rslib/src/notetype/mod.rs b/rslib/src/notetype/mod.rs index 419ecb78f..be45b6eba 100644 --- a/rslib/src/notetype/mod.rs +++ b/rslib/src/notetype/mod.rs @@ -695,7 +695,7 @@ impl Collection { original.config.sort_field_idx, normalize, )?; - self.update_cards_for_changed_templates(notetype, original.templates.len())?; + self.update_cards_for_changed_templates(notetype, &original.templates)?; self.update_notetype_undoable(notetype, original)?; } else { // adding with existing id for old undo code, bypass undo diff --git a/rslib/src/notetype/schemachange.rs b/rslib/src/notetype/schemachange.rs index c3d9310d6..d5168407f 100644 --- a/rslib/src/notetype/schemachange.rs +++ b/rslib/src/notetype/schemachange.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; -use super::{CardGenContext, Notetype}; +use super::{CardGenContext, CardTemplate, Notetype}; use crate::{ prelude::*, search::{JoinSearches, SortMode, TemplateKind}, @@ -52,6 +52,10 @@ impl TemplateOrdChanges { changes } + + fn is_empty(&self) -> bool { + *self == Self::default() + } } impl Collection { @@ -130,47 +134,67 @@ impl Collection { pub(crate) fn update_cards_for_changed_templates( &mut self, nt: &Notetype, - previous_template_count: usize, + old_templates: &[CardTemplate], ) -> Result<()> { - let ords: Vec<_> = nt.templates.iter().map(|f| f.ord).collect(); let usn = self.usn()?; - if ords_changed(&ords, previous_template_count) { + let ords: Vec<_> = nt.templates.iter().map(|f| f.ord).collect(); + let changes = TemplateOrdChanges::new(ords, old_templates.len() as u32); + + if !changes.is_empty() { self.set_schema_modified()?; - let changes = TemplateOrdChanges::new(ords, previous_template_count as u32); - - // remove any cards where the template was deleted - if !changes.removed.is_empty() { - let ords = - SearchBuilder::any(changes.removed.into_iter().map(TemplateKind::Ordinal)); - self.search_cards_into_table(nt.id.and(ords), SortMode::NoOrder)?; - for card in self.storage.all_searched_cards()? { - self.remove_card_and_add_grave_undoable(card, usn)?; - } - self.storage.clear_searched_cards_table()?; - } - - // update ordinals for cards with a repositioned template - if !changes.moved.is_empty() { - let ords = - SearchBuilder::any(changes.moved.keys().cloned().map(TemplateKind::Ordinal)); - self.search_cards_into_table(nt.id.and(ords), SortMode::NoOrder)?; - for mut card in self.storage.all_searched_cards()? { - let original = card.clone(); - card.template_idx = *changes.moved.get(&card.template_idx).unwrap(); - self.update_card_inner(&mut card, original, usn)?; - } - self.storage.clear_searched_cards_table()?; - } } - let last_deck = self.get_last_deck_added_to_for_notetype(nt.id); - let ctx = CardGenContext::new(nt, last_deck, usn); - self.generate_cards_for_notetype(&ctx)?; + // remove any cards where the template was deleted + if !changes.removed.is_empty() { + let ords = + SearchBuilder::any(changes.removed.iter().cloned().map(TemplateKind::Ordinal)); + self.search_cards_into_table(nt.id.and(ords), SortMode::NoOrder)?; + for card in self.storage.all_searched_cards()? { + self.remove_card_and_add_grave_undoable(card, usn)?; + } + self.storage.clear_searched_cards_table()?; + } + // update ordinals for cards with a repositioned template + if !changes.moved.is_empty() { + let ords = SearchBuilder::any(changes.moved.keys().cloned().map(TemplateKind::Ordinal)); + self.search_cards_into_table(nt.id.and(ords), SortMode::NoOrder)?; + for mut card in self.storage.all_searched_cards()? { + let original = card.clone(); + card.template_idx = *changes.moved.get(&card.template_idx).unwrap(); + self.update_card_inner(&mut card, original, usn)?; + } + self.storage.clear_searched_cards_table()?; + } + + if should_generate_cards(&changes, nt, old_templates) { + let last_deck = self.get_last_deck_added_to_for_notetype(nt.id); + let ctx = CardGenContext::new(nt, last_deck, usn); + self.generate_cards_for_notetype(&ctx)?; + } Ok(()) } } +fn should_generate_cards( + changes: &TemplateOrdChanges, + nt: &Notetype, + old_templates: &[CardTemplate], +) -> bool { + // must regenerate if any front side has changed, but also in the (unlikely) + // case that a template has been replaced by one with an identical front + !(changes.added.is_empty() && nt.template_fronts_are_identical(old_templates)) +} + +impl Notetype { + fn template_fronts_are_identical(&self, other_templates: &[CardTemplate]) -> bool { + self.templates + .iter() + .map(|t| &t.config.q_format) + .eq(other_templates.iter().map(|t| &t.config.q_format)) + } +} + #[cfg(test)] mod test { use super::{ords_changed, TemplateOrdChanges};