diff --git a/proto/anki/card_rendering.proto b/proto/anki/card_rendering.proto index 4035ae68b..0ca8e5fde 100644 --- a/proto/anki/card_rendering.proto +++ b/proto/anki/card_rendering.proto @@ -127,6 +127,7 @@ message RenderCardResponse { repeated RenderedTemplateNode answer_nodes = 2; string css = 3; bool latex_svg = 4; + bool is_empty = 5; } message RenderedTemplateNode { diff --git a/pylib/anki/template.py b/pylib/anki/template.py index 3e993b9ea..3cc8afaf8 100644 --- a/pylib/anki/template.py +++ b/pylib/anki/template.py @@ -60,6 +60,7 @@ class PartiallyRenderedCard: anodes: TemplateReplacementList css: str latex_svg: bool + is_empty: bool @classmethod def from_proto( @@ -68,7 +69,9 @@ class PartiallyRenderedCard: qnodes = cls.nodes_from_proto(out.question_nodes) anodes = cls.nodes_from_proto(out.answer_nodes) - return PartiallyRenderedCard(qnodes, anodes, out.css, out.latex_svg) + return PartiallyRenderedCard( + qnodes, anodes, out.css, out.latex_svg, out.is_empty + ) @staticmethod def nodes_from_proto( diff --git a/rslib/src/card_rendering/service.rs b/rslib/src/card_rendering/service.rs index 8d1585725..73f8302ca 100644 --- a/rslib/src/card_rendering/service.rs +++ b/rslib/src/card_rendering/service.rs @@ -219,6 +219,7 @@ impl From for anki_proto::card_rendering::RenderCardResponse { answer_nodes: rendered_nodes_to_proto(o.anodes), css: o.css, latex_svg: o.latex_svg, + is_empty: o.is_empty, } } } diff --git a/rslib/src/notetype/render.rs b/rslib/src/notetype/render.rs index ffbd5eb5c..8f686b0a5 100644 --- a/rslib/src/notetype/render.rs +++ b/rslib/src/notetype/render.rs @@ -20,6 +20,7 @@ pub struct RenderCardOutput { pub anodes: Vec, pub css: String, pub latex_svg: bool, + pub is_empty: bool, } impl RenderCardOutput { @@ -136,7 +137,7 @@ impl Collection { ) }; - let (qnodes, anodes) = render_card(RenderCardRequest { + let response = render_card(RenderCardRequest { qfmt, afmt, field_map: &field_map, @@ -147,10 +148,11 @@ impl Collection { partial_render, })?; Ok(RenderCardOutput { - qnodes, - anodes, + qnodes: response.qnodes, + anodes: response.anodes, css: nt.config.css.clone(), latex_svg: nt.config.latex_svg, + is_empty: response.is_empty, }) } diff --git a/rslib/src/template.rs b/rslib/src/template.rs index a24ffec5f..8d353070e 100644 --- a/rslib/src/template.rs +++ b/rslib/src/template.rs @@ -592,6 +592,13 @@ pub struct RenderCardRequest<'a> { pub partial_render: bool, } +pub struct RenderCardResponse { + pub qnodes: Vec, + pub anodes: Vec, + pub is_empty: bool, +} + +/// Returns `(qnodes, anodes, is_empty)` pub fn render_card( RenderCardRequest { qfmt, @@ -603,7 +610,7 @@ pub fn render_card( tr, partial_render: partial_for_python, }: RenderCardRequest<'_>, -) -> Result<(Vec, Vec)> { +) -> Result { // prepare context let mut context = RenderContext { fields: field_map, @@ -638,7 +645,11 @@ pub fn render_card( }; if let Some(text) = empty_message { qnodes.push(RenderedNode::Text { text: text.clone() }); - return Ok((qnodes, vec![RenderedNode::Text { text }])); + return Ok(RenderCardResponse { + qnodes, + anodes: vec![RenderedNode::Text { text }], + is_empty: true, + }); } // answer side @@ -654,7 +665,11 @@ pub fn render_card( .and_then(|tmpl| tmpl.render(&context, tr)) .map_err(|e| template_error_to_anki_error(e, false, browser, tr))?; - Ok((qnodes, anodes)) + Ok(RenderCardResponse { + qnodes, + anodes, + is_empty: false, + }) } fn cloze_is_empty(field_map: &HashMap<&str, Cow>, card_ord: u16) -> bool { @@ -1338,14 +1353,15 @@ mod test { tr: &tr, partial_render: true, }; - let qnodes = super::render_card(req.clone()).unwrap().0; + let response = super::render_card(req.clone()).unwrap(); assert_eq!( - qnodes[0], + response.qnodes[0], FN::Text { text: "test".into() } ); - if let FN::Text { ref text } = qnodes[1] { + assert!(response.is_empty); + if let FN::Text { ref text } = response.qnodes[1] { assert!(text.contains("card is blank")); } else { unreachable!(); @@ -1354,9 +1370,9 @@ mod test { // a popular card template expects {{FrontSide}} to resolve to an empty // string on the front side :-( req.qfmt = "{{FrontSide}}{{N}}"; - let qnodes = super::render_card(req.clone()).unwrap().0; + let response = super::render_card(req.clone()).unwrap(); assert_eq!( - &qnodes, + &response.qnodes, &[ FN::Replacement { field_name: "FrontSide".into(), @@ -1366,8 +1382,10 @@ mod test { FN::Text { text: "N".into() } ] ); + assert!(!response.is_empty); req.partial_render = false; - let qnodes = super::render_card(req.clone()).unwrap().0; - assert_eq!(&qnodes, &[FN::Text { text: "N".into() }]); + let response = super::render_card(req.clone()).unwrap(); + assert_eq!(&response.qnodes, &[FN::Text { text: "N".into() }]); + assert!(!response.is_empty); } }