mirror of
https://github.com/ankitects/anki.git
synced 2025-09-25 01:06:35 -04:00
show which side the template error occurred on
This commit is contained in:
parent
ed8c1ae9c5
commit
bd96c27096
5 changed files with 47 additions and 36 deletions
|
@ -52,6 +52,7 @@ message InvalidInputError {
|
||||||
|
|
||||||
message TemplateParseError {
|
message TemplateParseError {
|
||||||
string info = 1;
|
string info = 1;
|
||||||
|
bool q_side = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TemplateRequirementsIn {
|
message TemplateRequirementsIn {
|
||||||
|
|
|
@ -121,7 +121,14 @@ def render_card(
|
||||||
try:
|
try:
|
||||||
output = render_card_from_context(ctx)
|
output = render_card_from_context(ctx)
|
||||||
except anki.rsbackend.BackendException as e:
|
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(
|
output = TemplateRenderOutput(
|
||||||
question_text=errmsg,
|
question_text=errmsg,
|
||||||
answer_text=errmsg,
|
answer_text=errmsg,
|
||||||
|
|
|
@ -27,7 +27,9 @@ impl std::convert::From<AnkiError> for pt::BackendError {
|
||||||
use pt::backend_error::Value as V;
|
use pt::backend_error::Value as V;
|
||||||
let value = match err {
|
let value = match err {
|
||||||
AnkiError::InvalidInput { info } => V::InvalidInput(pt::InvalidInputError { info }),
|
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) }
|
pt::BackendError { value: Some(value) }
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub enum AnkiError {
|
||||||
InvalidInput { info: String },
|
InvalidInput { info: String },
|
||||||
|
|
||||||
#[fail(display = "invalid card template: {}", info)]
|
#[fail(display = "invalid card template: {}", info)]
|
||||||
TemplateError { info: String },
|
TemplateError { info: String, q_side: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
// error helpers
|
// error helpers
|
||||||
|
@ -34,33 +34,3 @@ pub enum TemplateError {
|
||||||
field: String,
|
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
|
|
||||||
),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// 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 crate::template_filters::apply_filters;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use nom;
|
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
|
// Legacy support
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
||||||
|
@ -438,12 +465,16 @@ pub fn render_card(
|
||||||
|
|
||||||
// question side
|
// question side
|
||||||
let qnorm = without_legacy_template_directives(qfmt);
|
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
|
// answer side
|
||||||
context.question_side = false;
|
context.question_side = false;
|
||||||
let anorm = without_legacy_template_directives(afmt);
|
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))
|
Ok((qnodes, anodes))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue