July 25th, 2026
-
Replace
Engine::with_syntaxwithEngine::set_syntax. Custom syntax is now configured on an existing engine via a setter method instead of a separate constructor, for example:let mut engine = Engine::new(); engine.set_syntax(Syntax::builder().expr("<{", "}>").block("<[", "]>").build());
-
Allow the value function passed to
render_from_fnto beFnMut. Previously the closure had to implementFn, this relaxes the bound so stateful value functions can be used.
June 27th, 2025
-
Support
&Valueas second argument to functions. This allows you to register functions likeupon::Value::eq. -
Support access and optional access from scope. This extends the syntax for variable access in expressions to support the dot (
.) and optional dot (?.) prefixes for the first segment of paths.The following are equivalent:
{{ user }} {{ .user }}But now you can also use the following, which will return
Value::Noneifuseris not defined:{{ ?.user }} -
Add support for in-place function calls. Previously, function calls only supported the "filter" syntax, which always required at least one argument to be "piped" into the call. This change adds an additional name and parenthesized argument syntax including those without arguments. For example code like the following is now valid:
{{ now() }}{{ item.price | format: get_currency(user.id) }} -
Support parenthesized expressions. This allows you to use parentheses in inline expressions, such as:
{{ content | replace: "John Smith", (user.name | title) }} -
Rename "filters" to "functions". "Filter" now refers to the way the function is used, i.e. the pipe syntax
{{ value | function: arg1, arg2 }}. This change is in preparation for a new syntax for calling functions.
February 8th, 2025
-
Support list and map literals. List and map literals can now be used in templates. List literals are created using square brackets and map literals are created using curly braces. For example,
[1, 2, 3]is a list literal and{ "key": "value" }is a map literal. -
Fix bug with filters expecting a borrowed argument would error. If a filter expected a borrowed argument, but the argument was owned, the filter code would error. This is now fixed.
February 23rd, 2024
October 28th, 2023
-
Add
with_template_fntoRendererThis allows you to configure the way that included templates are resolved. -
Allow setting
max_include_depthat renderer level This allows you to configure the maximum include depth on a per-renderer basis.
July 23rd, 2023
- Add
.template(name)function to engine This function is a shorthand forget_templatethat panics if the template does not exist.
July 23rd, 2023
-
Redesign the render API This improvement allows us to add more configuration to the rendering process in the future. It also prevents the need for a proliferation of rendering functions. The new public
Rendererstruct is created using one of the three functions:render,render_from, orrender_from_fn. And then the renderer can be consumed using.to_string()or.to_writer(..). -
Allow values to be fetched lazily This allows you to provide the global context from an outside source during rendering.
-
Replace ValueCow::as_bool with truthiness function This change implements a truthiness function for evaluating conditionals.
None,false,0integer and0.0float, empty string, list, and map as falsy. Everything else is truthy.Contributed by @lunabunn
November 20th, 2022
- Expand supported filter argument types Adds the unit type, all
integer primitive types, and
f32.
- Fix bug in
value!macro - Use index implementation for looking up spans This removes all the unsafe code in this library. I think the decrease in performance (about 5-10%) is worth not having any unsafe code.
November 14th, 2022
- Add methods to remove templates and functions
remove_templateallows you to remove a template from the engine.remove_functionallows you to remove a formatter or filter from the engine.add_formatterandadd_filternow return the previous type of function if a function of the same name already existed in the engine. - Add some
FromandFromIteratorimpls forValue - Support and test on Rust 1.60
- Support Unicode identifiers
- Parse list indices in lexer This fixes a bug where a path like
lorem.123.ipsumwould not parse correctly because the lexer would return aToken::Numberfor the span "123.ipsum". This requires adding an additional state to the lexer so that it knows when it is lexing a path versus a float literal. - Refactor formatter and filter errors Move formatter types to new
module, add
fmt::Errortype. Add filter error trait and kind. - Add template name to error, update error format
October 3rd, 2022
- Make various filter traits public This allows you to refer to them if you want to be generic over filters.
- Support
else ifThis is simply desugared to a nestedifstatement in the parser. - Support scientific notation for float literals
- Use
Cow<str>for map keys and template sources This allows you to store template sources computed at runtime in the engine while preserving support for templates included in the binary.
- Fix bug with include statement scopes
- Restrict maximum include depth. This prevents infinite recursion
when including templates. This can be configured using the
set_max_include_depthmethod on anEngine. - Disallow configuring syntax using empty strings We now panic if
you pass an empty string to
SyntaxBuilder.