show which side the template error occurred on

This commit is contained in:
Damien Elmes 2020-02-08 11:54:08 +10:00
parent ed8c1ae9c5
commit bd96c27096
5 changed files with 47 additions and 36 deletions

View file

@ -52,6 +52,7 @@ message InvalidInputError {
message TemplateParseError {
string info = 1;
bool q_side = 2;
}
message TemplateRequirementsIn {

View file

@ -121,7 +121,14 @@ def render_card(
try:
output = render_card_from_context(ctx)
except anki.rsbackend.BackendException as e:
errmsg = _("Card template has a problem:") + f"<br>{e}"
# fixme: specific exception in 2.1.21
err = e.args[0].template_parse
if err.q_side:
side = _("Front")
else:
side = _("Back")
errmsg = _("{} template has a problem:").format(side) + f"<br>{e}"
errmsg += "<br><a href=https://anki.tenderapp.com/kb/problems/card-template-has-a-problem>{}</a>".format(_("More info"))
output = TemplateRenderOutput(
question_text=errmsg,
answer_text=errmsg,

View file

@ -27,7 +27,9 @@ impl std::convert::From<AnkiError> for pt::BackendError {
use pt::backend_error::Value as V;
let value = match err {
AnkiError::InvalidInput { info } => V::InvalidInput(pt::InvalidInputError { info }),
AnkiError::TemplateError { info } => V::TemplateParse(pt::TemplateParseError { info }),
AnkiError::TemplateError { info, q_side } => {
V::TemplateParse(pt::TemplateParseError { info, q_side })
}
};
pt::BackendError { value: Some(value) }

View file

@ -11,7 +11,7 @@ pub enum AnkiError {
InvalidInput { info: String },
#[fail(display = "invalid card template: {}", info)]
TemplateError { info: String },
TemplateError { info: String, q_side: bool },
}
// error helpers
@ -34,33 +34,3 @@ pub enum TemplateError {
field: String,
},
}
impl From<TemplateError> for AnkiError {
fn from(terr: TemplateError) -> Self {
AnkiError::TemplateError {
info: match terr {
TemplateError::NoClosingBrackets(context) => {
format!("missing '}}}}' in '{}'", context)
}
TemplateError::ConditionalNotClosed(tag) => format!("missing '{{{{/{}}}}}'", tag),
TemplateError::ConditionalNotOpen {
closed,
currently_open,
} => {
if let Some(open) = currently_open {
format!("Found {{{{/{}}}}}, but expected {{{{/{}}}}}", closed, open)
} else {
format!(
"Found {{{{/{}}}}}, but missing '{{{{#{}}}}}' or '{{{{^{}}}}}'",
closed, closed, closed
)
}
}
TemplateError::FieldNotFound { field, filters } => format!(
"found '{{{{{}{}}}}}', but there is no field called '{}'",
filters, field, field
),
},
}
}
}

View file

@ -1,7 +1,7 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use crate::err::{Result, TemplateError};
use crate::err::{AnkiError, Result, TemplateError};
use crate::template_filters::apply_filters;
use lazy_static::lazy_static;
use nom;
@ -189,6 +189,33 @@ fn parse_inner<'a, I: Iterator<Item = TemplateResult<Token<'a>>>>(
}
}
fn template_error_to_anki_error(err: TemplateError, q_side: bool) -> AnkiError {
AnkiError::TemplateError {
info: match err {
TemplateError::NoClosingBrackets(context) => format!("Missing '}}}}' in '{}'", context),
TemplateError::ConditionalNotClosed(tag) => format!("Missing '{{{{/{}}}}}'", tag),
TemplateError::ConditionalNotOpen {
closed,
currently_open,
} => {
if let Some(open) = currently_open {
format!("Found {{{{/{}}}}}, but expected {{{{/{}}}}}", closed, open)
} else {
format!(
"Found {{{{/{}}}}}, but missing '{{{{#{}}}}}' or '{{{{^{}}}}}'",
closed, closed, closed
)
}
}
TemplateError::FieldNotFound { field, filters } => format!(
"Found '{{{{{}{}}}}}', but there is no field called '{}'",
filters, field, field
),
},
q_side,
}
}
// Legacy support
//----------------------------------------
@ -438,12 +465,16 @@ pub fn render_card(
// question side
let qnorm = without_legacy_template_directives(qfmt);
let qnodes = ParsedTemplate::from_text(qnorm.as_ref())?.render(&context)?;
let qnodes = ParsedTemplate::from_text(qnorm.as_ref())
.and_then(|tmpl| tmpl.render(&context))
.map_err(|e| template_error_to_anki_error(e, true))?;
// answer side
context.question_side = false;
let anorm = without_legacy_template_directives(afmt);
let anodes = ParsedTemplate::from_text(anorm.as_ref())?.render(&context)?;
let anodes = ParsedTemplate::from_text(anorm.as_ref())
.and_then(|tmpl| tmpl.render(&context))
.map_err(|e| template_error_to_anki_error(e, false))?;
Ok((qnodes, anodes))
}