Check for clozes when saving notetype

Error if:
- Cloze notetype lacks a cloze field on either template side.
- Non-cloze notetype has a cloze field on any template.
This commit is contained in:
RumovZ 2021-05-27 12:01:05 +02:00
parent 6fae0ea21f
commit 3dfa1de68b
3 changed files with 61 additions and 1 deletions

View File

@ -22,6 +22,8 @@ card-templates-add-mobile-class = Add Mobile Class
card-templates-preview-settings = Options
card-templates-invalid-template-number = Card template { $number } in notetype '{ $notetype }' has a problem.
card-templates-identical-front = Its front side is identical with the one of card template { $number }.
card-templates-missing-cloze = The 'cloze' filter must be used on both sides of a cloze template.
card-templates-extraneous-cloze = The 'cloze' filter can only be used on cloze templates.
card-templates-see-preview = See the render preview for more information.
card-templates-changes-saved = Changes saved.
card-templates-discard-changes = Discard changes?

View File

@ -67,6 +67,10 @@ impl AnkiError {
let details = match err.details {
TemplateSaveErrorDetails::TemplateError => tr.card_templates_see_preview(),
TemplateSaveErrorDetails::Duplicate(i) => tr.card_templates_identical_front(i),
TemplateSaveErrorDetails::MissingCloze => tr.card_templates_missing_cloze(),
TemplateSaveErrorDetails::ExtraneousCloze => {
tr.card_templates_extraneous_cloze()
}
};
format!("{}<br>{}", header, details)
}
@ -146,6 +150,8 @@ pub struct TemplateSaveError {
#[derive(Debug, PartialEq)]
pub enum TemplateSaveErrorDetails {
Duplicate(usize),
TemplateError,
Duplicate(usize),
MissingCloze,
ExtraneousCloze,
}

View File

@ -287,6 +287,28 @@ impl Notetype {
Ok(())
}
fn ensure_cloze_if_and_only_if_cloze_notetype(
&self,
parsed_templates: &[(Option<ParsedTemplate>, Option<ParsedTemplate>)],
) -> Result<()> {
if self.is_cloze() {
if missing_cloze_filter(parsed_templates) {
return Err(AnkiError::TemplateSaveError(TemplateSaveError {
notetype: self.name.clone(),
ordinal: 0,
details: TemplateSaveErrorDetails::MissingCloze,
}));
}
} else if let Some(i) = find_cloze_filter(parsed_templates) {
return Err(AnkiError::TemplateSaveError(TemplateSaveError {
notetype: self.name.clone(),
ordinal: i,
details: TemplateSaveErrorDetails::ExtraneousCloze,
}));
}
Ok(())
}
pub(crate) fn normalize_names(&mut self) {
ensure_string_in_nfc(&mut self.name);
for f in &mut self.fields {
@ -349,6 +371,7 @@ impl Notetype {
details: TemplateSaveErrorDetails::TemplateError,
}));
}
self.ensure_cloze_if_and_only_if_cloze_notetype(&parsed_templates)?;
let reqs = self.updated_requirements(&parsed_templates);
// handle renamed+deleted fields
@ -448,6 +471,35 @@ impl Notetype {
}
}
/// True if the slice is empty or either template of the first tuple doesn't have a cloze field.
fn missing_cloze_filter(
parsed_templates: &[(Option<ParsedTemplate>, Option<ParsedTemplate>)],
) -> bool {
parsed_templates
.get(0)
.map_or(true, |t| !has_cloze(&t.0) || !has_cloze(&t.1))
}
/// Return the index of the first tuple with a cloze field on either template.
fn find_cloze_filter(
parsed_templates: &[(Option<ParsedTemplate>, Option<ParsedTemplate>)],
) -> Option<usize> {
parsed_templates.iter().enumerate().find_map(|(i, t)| {
if has_cloze(&t.0) || has_cloze(&t.1) {
Some(i)
} else {
None
}
})
}
/// True if the template is non-empty and has a cloze field.
fn has_cloze(template: &Option<ParsedTemplate>) -> bool {
template
.as_ref()
.map_or(false, |t| !t.cloze_fields().is_empty())
}
impl From<Notetype> for NotetypeProto {
fn from(nt: Notetype) -> Self {
NotetypeProto {