The value of @name is @value.
+//! +//! +//! ``` +//! +//! As seen above, string slices and integers can easily be outputed +//! in the template body, using `@name` where `name` is a parameter of +//! the template. +//! Actually, more complex expressions can be outputed in the same +//! way, as long as the resulting value implements [`ToHtml`]. +//! Rust types that implements [`Display`] automatically implements +//! [`ToHtml`] in such a way that contents are safely escaped for +//! html. +//! +//! ```html +//! @use any::rust::Type; +//! +//! @(name: &str, items: &[Type]) +//! +//! +//!There are no items.
+//! } else { +//!There are @items.len() items.
+//!The user @user.name has email @user.get_email().
+ //!A function result is @function(with, three, arguments).
+ //! ``` + //! + //! Standard function and macros can also be used, e.g. for specific + //! formatting needs: + //! + //! ```text + //!The value is @format!("{:.1}", float_value).
+ //! ``` + //! + //! If more complex expressions are needed, they can be put in + //! parenthesis. + //! + //! ```text + //!The sum @a+3 is @(a+3).
+ //! ``` + //! If `a` is 2, this exapands to: + //! ```text + //!The sum 2+3 is 5.
+ //! ``` + //! + //! Anything is allowed in parenthesis, as long as parenthesis, + //! brackets and string quotes are balanced. + //! Note that this also applies to the parenthesis of a function + //! call or the brackets of an index, so complex things like the + //! following are allowed: + //! + //! ```text + //!Index: @myvec[t.map(|s| s.length()).unwrap_or(0)].
+ //!Argument: @call(a + 3, |t| t.something()).
+ //! ``` + //! + //! An expression ends when parenthesis and brackets are matched + //! and it is followed by something not allowed in an expression. + //! This includes whitespace and e.g. the `<` and `@` characters. + //! If an expression starts with an open parenthesis, the + //! expression ends when that parentheis is closed. + //! That is usefull if an expression is to be emmediatley followed + //! by something that would be allowed in an expression. + //! + //! ```text + //!@arg
+ //!@arg.
+ //!@arg.@arg
+ //!@arg.len()
+ //!@(arg).len()
+ //!@((2_i8 - 3).abs())
@* Note extra parens needed here *@ + //! ``` + //! With `arg = "name"`, the above renders as: + //! ```text + //!name
+ //!name.
+ //!name.name
+ //!4
+ //!name.len()
+ //!1
+ //! ``` +} + +pub mod b_Loops { + //! A ructe `@for` loop works just as a rust `for` loop, + //! iterating over anything that implements `std::iter::IntoIterator`, + //! such as a `Vec` or a slice. + //! + //! # Loops + //! + //! Rust-like loops are supported like this: + //! + //! ```text + //!@n: @item
+ //! } + //! ``` + //! + //! It is also possible to loop over a literal array (which may be + //! an array of tuples), as long as you do it by reference: + //! + //! ```text + //! @for &(name, age) in &[("Rasmus", 44), ("Mike", 36)] { + //!@name is @age years old.
+ //! } + //! ``` +} + +pub mod c_Conditionals { + //! Both `@if` statements with boolean expressions, `@if let` guard + //! statements, and `@match` statements are supported. + //! + //! # Conditionals + //! + //! Rust-like conditionals are supported in a style similar to the loops: + //! + //! ```text + //! @if items.is_empty() { + //!There are no items.
+ //! } + //! ``` + //! + //! Pattern matching let expressions are also supported, as well as an + //! optional else part. + //! + //! ```text + //! @if let Some(foo) = foo { + //!Foo is @foo.
+ //! } else { + //!There is no foo.
+ //! } + //! ``` + //! + //! The condition or let expression should allow anything that would be + //! allowed in the same place in plain rust. + //! As with loops, the things in the curly brackets are ructe template + //! code. + //! + //! ## match + //! + //! Pattern matching using `match` statements are also supported. + //! + //! ```text + //! @match answer { + //! Ok(value) => { + //!The answer is @value.
+ //! } + //! Err(_) => { + //!I don't know the answer.
+ //! } + //! } + //! ``` + //! + //! The let expression and patterns should allow anything that would be + //! allowed in the same place in plain rust. + //! As above, the things in the curly brackets are ructe template code. +} + +pub mod d_Calling_other_templates { + //! The ability to call other templates for from a template makes + //! both "tag libraries" and "base templates" possible with the + //! same syntax. + //! + //! # Calling other templates + //! + //! While rust methods can be called as a simple expression, there is a + //! special syntax for calling other templates: + //! `@:template_name(template_arguments)`. + //! Also, before calling a template, it has to be imported by a `use` + //! statement. + //! Templates are declared in a `templates` module. + //! + //! So, given something like this in `header.rs.html`: + //! + //! ```text + //! @(title: &str) + //! + //! + //!page content ...
+ //! + //! + //! ``` + //! + //! It is also possible to send template blocks as parameters to templates. + //! A structure similar to the above can be created by having something like + //! this in `base_page.rs.html`: + //! + //! ```text + //! @(title: &str, body: Content) + //! + //! + //! + //!page content ...
+ //! }) + //! ``` +} diff --git a/ructe-0.17.0/src/expression.rs b/ructe-0.17.0/src/expression.rs new file mode 100644 index 0000000..a8f6a49 --- /dev/null +++ b/ructe-0.17.0/src/expression.rs @@ -0,0 +1,275 @@ +use crate::parseresult::PResult; +use nom::branch::alt; +use nom::bytes::complete::{escaped, is_a, is_not, tag}; +use nom::character::complete::{alpha1, char, digit1, none_of, one_of}; +use nom::combinator::{map, map_res, not, opt, recognize, value}; +use nom::error::context; //, VerboseError}; +use nom::multi::{fold_many0, many0, separated_list0}; +use nom::sequence::{delimited, pair, preceded, terminated, tuple}; +use std::str::{from_utf8, Utf8Error}; + +pub fn expression(input: &[u8]) -> PResult<&str> { + map_res( + recognize(context( + "Expected rust expression", + tuple(( + map_res(alt((tag("&"), tag("*"), tag(""))), input_to_str), + alt(( + rust_name, + map_res(digit1, input_to_str), + quoted_string, + expr_in_parens, + expr_in_brackets, + )), + fold_many0( + alt(( + preceded(context("separator", tag(".")), expression), + preceded(tag("::"), expression), + expr_in_parens, + expr_in_braces, + expr_in_brackets, + preceded(tag("!"), expr_in_parens), + preceded(tag("!"), expr_in_brackets), + )), + || (), + |_, _| (), + ), + )), + )), + input_to_str, + )(input) +} + +pub fn input_to_str(s: &[u8]) -> Result<&str, Utf8Error> { + from_utf8(s) +} + +pub fn comma_expressions(input: &[u8]) -> PResultThere are no items.
+//! } else { +//!There are @items.len() items.
+//!(&mut self, indir: P) -> Result<()>
+ where
+ P: AsRef (
+ &mut self,
+ path: P,
+ data: &[u8],
+ ) -> Result<&mut Self>
+ where
+ P: AsRef (&mut self, src: P) -> Result<&mut Self>
+ where
+ P: AsRef