From fe5d350f50ebc73300456c618dd265cc43a8f05a Mon Sep 17 00:00:00 2001 From: RenΓ© Kijewski Date: Mon, 3 Apr 2023 18:34:33 +0200 Subject: Allow delimiters with arbitrary length --- askama_derive/src/config.rs | 110 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 94 insertions(+), 16 deletions(-) (limited to 'askama_derive') diff --git a/askama_derive/src/config.rs b/askama_derive/src/config.rs index cf22a72..f01bd65 100644 --- a/askama_derive/src/config.rs +++ b/askama_derive/src/config.rs @@ -168,24 +168,34 @@ impl<'a> TryFrom> for Syntax<'a> { comment_end: raw.comment_end.unwrap_or(default.comment_end), }; - if syntax.block_start.len() != 2 - || syntax.block_end.len() != 2 - || syntax.expr_start.len() != 2 - || syntax.expr_end.len() != 2 - || syntax.comment_start.len() != 2 - || syntax.comment_end.len() != 2 - { - return Err("length of delimiters must be two".into()); + for s in [ + syntax.block_start, + syntax.block_end, + syntax.expr_start, + syntax.expr_end, + syntax.comment_start, + syntax.comment_end, + ] { + if s.len() < 2 { + return Err( + format!("delimiters must be at least two characters long: {s:?}").into(), + ); + } else if s.chars().any(|c| c.is_whitespace()) { + return Err(format!("delimiters may not contain white spaces: {s:?}").into()); + } } - let bs = syntax.block_start.as_bytes()[0]; - let be = syntax.block_start.as_bytes()[1]; - let cs = syntax.comment_start.as_bytes()[0]; - let ce = syntax.comment_start.as_bytes()[1]; - let es = syntax.expr_start.as_bytes()[0]; - let ee = syntax.expr_start.as_bytes()[1]; - if !((bs == cs && bs == es) || (be == ce && be == ee)) { - return Err(format!("bad delimiters block_start: {}, comment_start: {}, expr_start: {}, needs one of the two characters in common", syntax.block_start, syntax.comment_start, syntax.expr_start).into()); + for (s1, s2) in [ + (syntax.block_start, syntax.expr_start), + (syntax.block_start, syntax.comment_start), + (syntax.expr_start, syntax.comment_start), + ] { + if s1.starts_with(s2) || s2.starts_with(s1) { + return Err(format!( + "a delimiter may not be the prefix of another delimiter: {s1:?} vs {s2:?}", + ) + .into()); + } } Ok(syntax) @@ -452,6 +462,74 @@ mod tests { assert_eq!(bar.comment_end, default_syntax.comment_end); } + #[cfg(feature = "config")] + #[test] + fn longer_delimiters() { + let raw_config = r#" + [[syntax]] + name = "emoji" + block_start = "πŸ‘‰πŸ™‚πŸ‘‰" + block_end = "πŸ‘ˆπŸ™ƒπŸ‘ˆ" + expr_start = "🀜🀜" + expr_end = "πŸ€›πŸ€›" + comment_start = "πŸ‘Ž_(ツ)_πŸ‘Ž" + comment_end = "πŸ‘:DπŸ‘" + + [general] + default_syntax = "emoji" + "#; + + let config = Config::new(raw_config, None).unwrap(); + assert_eq!(config.default_syntax, "emoji"); + + let foo = config.syntaxes.get("emoji").unwrap(); + assert_eq!(foo.block_start, "πŸ‘‰πŸ™‚πŸ‘‰"); + assert_eq!(foo.block_end, "πŸ‘ˆπŸ™ƒπŸ‘ˆ"); + assert_eq!(foo.expr_start, "🀜🀜"); + assert_eq!(foo.expr_end, "πŸ€›πŸ€›"); + assert_eq!(foo.comment_start, "πŸ‘Ž_(ツ)_πŸ‘Ž"); + assert_eq!(foo.comment_end, "πŸ‘:DπŸ‘"); + } + + #[cfg(feature = "config")] + #[test] + fn illegal_delimiters() { + let raw_config = r#" + [[syntax]] + name = "too_short" + block_start = "<" + "#; + let config = Config::new(raw_config, None); + assert_eq!( + config.unwrap_err().msg, + r#"delimiters must be at least two characters long: "<""#, + ); + + let raw_config = r#" + [[syntax]] + name = "contains_ws" + block_start = " {{ " + "#; + let config = Config::new(raw_config, None); + assert_eq!( + config.unwrap_err().msg, + r#"delimiters may not contain white spaces: " {{ ""#, + ); + + let raw_config = r#" + [[syntax]] + name = "is_prefix" + block_start = "{{" + expr_start = "{{$" + comment_start = "{{#" + "#; + let config = Config::new(raw_config, None); + assert_eq!( + config.unwrap_err().msg, + r#"a delimiter may not be the prefix of another delimiter: "{{" vs "{{$""#, + ); + } + #[cfg(feature = "toml")] #[should_panic] #[test] -- cgit