From bd96c270960a2682e15aabc5e4b51794b4c21870 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 8 Feb 2020 11:54:08 +1000 Subject: [PATCH] show which side the template error occurred on --- proto/backend.proto | 1 + pylib/anki/template.py | 9 ++++++++- rslib/src/backend.rs | 4 +++- rslib/src/err.rs | 32 +------------------------------- rslib/src/template.rs | 37 ++++++++++++++++++++++++++++++++++--- 5 files changed, 47 insertions(+), 36 deletions(-) diff --git a/proto/backend.proto b/proto/backend.proto index 71a68154c..8c240d5a3 100644 --- a/proto/backend.proto +++ b/proto/backend.proto @@ -52,6 +52,7 @@ message InvalidInputError { message TemplateParseError { string info = 1; + bool q_side = 2; } message TemplateRequirementsIn { diff --git a/pylib/anki/template.py b/pylib/anki/template.py index 894058242..cbd0d9226 100644 --- a/pylib/anki/template.py +++ b/pylib/anki/template.py @@ -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"
{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"
{e}" + errmsg += "
{}".format(_("More info")) output = TemplateRenderOutput( question_text=errmsg, answer_text=errmsg, diff --git a/rslib/src/backend.rs b/rslib/src/backend.rs index 04505055a..c0a318d7e 100644 --- a/rslib/src/backend.rs +++ b/rslib/src/backend.rs @@ -27,7 +27,9 @@ impl std::convert::From 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) } diff --git a/rslib/src/err.rs b/rslib/src/err.rs index 9b50a9d30..ceb9626bf 100644 --- a/rslib/src/err.rs +++ b/rslib/src/err.rs @@ -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 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 - ), - }, - } - } -} diff --git a/rslib/src/template.rs b/rslib/src/template.rs index cdf0b5995..739c771c6 100644 --- a/rslib/src/template.rs +++ b/rslib/src/template.rs @@ -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>>>( } } +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)) }