aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--askama_shared/src/generator.rs32
-rw-r--r--askama_shared/src/lib.rs21
-rw-r--r--askama_shared/src/parser.rs3
3 files changed, 49 insertions, 7 deletions
diff --git a/askama_shared/src/generator.rs b/askama_shared/src/generator.rs
index fc520d8..cae6389 100644
--- a/askama_shared/src/generator.rs
+++ b/askama_shared/src/generator.rs
@@ -60,8 +60,14 @@ fn build_template(ast: &syn::DeriveInput) -> Result<String, CompileError> {
eprintln!("{:?}", parsed[input.path.as_path()]);
}
- let code = Generator::new(&input, &contexts, heritage.as_ref(), MapChain::new())
- .build(&contexts[input.path.as_path()])?;
+ let code = Generator::new(
+ &input,
+ &contexts,
+ heritage.as_ref(),
+ MapChain::new(),
+ config.suppress_whitespace,
+ )
+ .build(&contexts[input.path.as_path()])?;
if input.print == Print::Code || input.print == Print::All {
eprintln!("{}", code);
}
@@ -129,6 +135,8 @@ struct Generator<'a, S: std::hash::BuildHasher> {
buf_writable: Vec<Writable<'a>>,
// Counter for write! hash named arguments
named: usize,
+ // If set to `true`, the whitespace characters will be removed by default unless `+` is used.
+ suppress_whitespace: bool,
}
impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
@@ -137,6 +145,7 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
contexts: &'n HashMap<&'n Path, Context<'n>, S>,
heritage: Option<&'n Heritage<'_>>,
locals: MapChain<'n, &'n str, LocalMeta>,
+ suppress_whitespace: bool,
) -> Generator<'n, S> {
Generator {
input,
@@ -148,12 +157,19 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
super_block: None,
buf_writable: vec![],
named: 0,
+ suppress_whitespace,
}
}
fn child(&mut self) -> Generator<'_, S> {
let locals = MapChain::with_parent(&self.locals);
- Self::new(self.input, self.contexts, self.heritage, locals)
+ Self::new(
+ self.input,
+ self.contexts,
+ self.heritage,
+ locals,
+ self.suppress_whitespace,
+ )
}
// Takes a Context and generates the relevant implementations.
@@ -1688,7 +1704,13 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
// prefix whitespace suppressor from the given argument, flush that whitespace.
// In either case, `next_ws` is reset to `None` (no trailing whitespace).
fn flush_ws(&mut self, ws: Ws) {
- if self.next_ws.is_some() && !ws.0 {
+ if self.next_ws.is_none() {
+ return;
+ }
+
+ // If `suppress_whitespace` is enabled, we keep the whitespace characters only if there is
+ // a `+` character.
+ if self.suppress_whitespace == ws.0 {
let val = self.next_ws.unwrap();
if !val.is_empty() {
self.buf_writable.push(Writable::Lit(val));
@@ -1701,7 +1723,7 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
// argument, to determine whether to suppress leading whitespace from the
// next literal.
fn prepare_ws(&mut self, ws: Ws) {
- self.skip_ws = ws.1;
+ self.skip_ws = self.suppress_whitespace != ws.1;
}
}
diff --git a/askama_shared/src/lib.rs b/askama_shared/src/lib.rs
index 5913eb3..2aa7114 100644
--- a/askama_shared/src/lib.rs
+++ b/askama_shared/src/lib.rs
@@ -118,6 +118,7 @@ struct Config<'a> {
syntaxes: BTreeMap<String, Syntax<'a>>,
default_syntax: &'a str,
escapers: Vec<(HashSet<String>, String)>,
+ suppress_whitespace: bool,
}
impl Config<'_> {
@@ -134,17 +135,19 @@ impl Config<'_> {
RawConfig::from_toml_str(s)?
};
- let (dirs, default_syntax) = match raw.general {
+ let (dirs, default_syntax, suppress_whitespace) = match raw.general {
Some(General {
dirs,
default_syntax,
+ suppress_whitespace,
}) => (
dirs.map_or(default_dirs, |v| {
v.into_iter().map(|dir| root.join(dir)).collect()
}),
default_syntax.unwrap_or(DEFAULT_SYNTAX_NAME),
+ suppress_whitespace.unwrap_or(false),
),
- None => (default_dirs, DEFAULT_SYNTAX_NAME),
+ None => (default_dirs, DEFAULT_SYNTAX_NAME, false),
};
if let Some(raw_syntaxes) = raw.syntax {
@@ -186,6 +189,7 @@ impl Config<'_> {
syntaxes,
default_syntax,
escapers,
+ suppress_whitespace,
})
}
@@ -303,6 +307,7 @@ struct General<'a> {
#[cfg_attr(feature = "serde", serde(borrow))]
dirs: Option<Vec<&'a str>>,
default_syntax: Option<&'a str>,
+ suppress_whitespace: Option<bool>,
}
#[cfg_attr(feature = "serde", derive(Deserialize))]
@@ -646,4 +651,16 @@ mod tests {
test.dyn_write_into(&mut vec).unwrap();
assert_eq!(vec, vec![b't', b'e', b's', b't']);
}
+
+ #[test]
+ fn test_suppress_whitespace_parsing() {
+ let config = Config::new(
+ r#"
+ [general]
+ suppress_whitespace = true
+ "#,
+ )
+ .unwrap();
+ assert!(config.suppress_whitespace);
+ }
}
diff --git a/askama_shared/src/parser.rs b/askama_shared/src/parser.rs
index 2a7f49f..eeca326 100644
--- a/askama_shared/src/parser.rs
+++ b/askama_shared/src/parser.rs
@@ -129,6 +129,9 @@ pub(crate) enum Target<'a> {
Path(Vec<&'a str>),
}
+/// First field is "minus sign was used on the left part of the item".
+///
+/// Second field is "minus/plus sign was used on the right part of the item".
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) struct Ws(pub(crate) bool, pub(crate) bool);