handle <% %> template syntax

This commit is contained in:
Damien Elmes 2019-12-30 08:12:44 +10:00
parent 62481ddc1a
commit fbfb7861a2
2 changed files with 41 additions and 3 deletions

View file

@ -2,7 +2,9 @@ use crate::backend_proto as pt;
use crate::backend_proto::backend_input::Value; use crate::backend_proto::backend_input::Value;
use crate::err::{AnkiError, Result}; use crate::err::{AnkiError, Result};
use crate::sched::sched_timing_today; use crate::sched::sched_timing_today;
use crate::template::{FieldMap, FieldRequirements, ParsedTemplate}; use crate::template::{
without_legacy_template_directives, FieldMap, FieldRequirements, ParsedTemplate,
};
use prost::Message; use prost::Message;
use std::collections::HashSet; use std::collections::HashSet;
use std::path::PathBuf; use std::path::PathBuf;
@ -110,7 +112,8 @@ impl Backend {
.template_front .template_front
.into_iter() .into_iter()
.map(|template| { .map(|template| {
if let Ok(tmpl) = ParsedTemplate::from_text(&template) { let normalized = without_legacy_template_directives(&template);
if let Ok(tmpl) = ParsedTemplate::from_text(normalized.as_ref()) {
// convert the rust structure into a protobuf one // convert the rust structure into a protobuf one
let val = match tmpl.requirements(&map) { let val = match tmpl.requirements(&map) {
FieldRequirements::Any(ords) => Value::Any(pt::TemplateRequirementAny { FieldRequirements::Any(ords) => Value::Any(pt::TemplateRequirementAny {

View file

@ -4,6 +4,7 @@ use nom::branch::alt;
use nom::bytes::complete::tag; use nom::bytes::complete::tag;
use nom::error::ErrorKind; use nom::error::ErrorKind;
use nom::sequence::delimited; use nom::sequence::delimited;
use std::borrow::Cow;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
pub type FieldMap<'a> = HashMap<&'a str, u16>; pub type FieldMap<'a> = HashMap<&'a str, u16>;
@ -107,7 +108,26 @@ enum ParsedNode<'a> {
#[derive(Debug)] #[derive(Debug)]
pub struct ParsedTemplate<'a>(Vec<ParsedNode<'a>>); pub struct ParsedTemplate<'a>(Vec<ParsedNode<'a>>);
static ALT_HANDLEBAR_DIRECTIVE: &str = "{{=<% %>=}}";
/// Convert legacy alternate syntax to standard syntax.
pub fn without_legacy_template_directives(text: &str) -> Cow<str> {
if text.trim_start().starts_with(ALT_HANDLEBAR_DIRECTIVE) {
text.trim_start()
.trim_start_matches(ALT_HANDLEBAR_DIRECTIVE)
.replace("<%", "{{")
.replace("%>", "}}")
.into()
} else {
text.into()
}
}
impl ParsedTemplate<'_> { impl ParsedTemplate<'_> {
/// Create a template from the provided text.
///
/// The legacy alternate syntax is not supported, so the provided text
/// should be run through without_legacy_template_directives() first.
pub fn from_text(template: &str) -> Result<ParsedTemplate> { pub fn from_text(template: &str) -> Result<ParsedTemplate> {
let mut iter = tokens(template); let mut iter = tokens(template);
Ok(Self(parse_inner(&mut iter, None)?)) Ok(Self(parse_inner(&mut iter, None)?))
@ -260,7 +280,7 @@ impl ParsedTemplate<'_> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::{FieldMap, ParsedNode::*, ParsedTemplate as PT}; use super::{FieldMap, ParsedNode::*, ParsedTemplate as PT};
use crate::template::FieldRequirements; use crate::template::{without_legacy_template_directives, FieldRequirements};
use std::collections::HashSet; use std::collections::HashSet;
use std::iter::FromIterator; use std::iter::FromIterator;
@ -357,4 +377,19 @@ mod test {
FieldRequirements::Any(HashSet::from_iter(vec![0].into_iter())) FieldRequirements::Any(HashSet::from_iter(vec![0].into_iter()))
); );
} }
#[test]
fn test_alt_syntax() {
let input = "
{{=<% %>=}}
<%Front%>
<% #Back %>
<%/Back%>";
let output = "
{{Front}}
{{ #Back }}
{{/Back}}";
assert_eq!(without_legacy_template_directives(input), output);
}
} }