maghoff / bart Goto Github PK
View Code? Open in Web Editor NEWA compile time templating language for Rust inspired by Mustache
Home Page: https://crates.io/crates/bart
License: MIT License
A compile time templating language for Rust inspired by Mustache
Home Page: https://crates.io/crates/bart
License: MIT License
I'd like to be able to iterate over slices, such as &'a [i32]
. Right now, it is possible to iterate over Vec<i32>
, but not a slice.
For the template {{#list}}{{.}}{{/list}}
, the generated code is something like:
for _s1 in &self.list { ... }
If I remove the &
, iterating over slices starts to work, but iterating over Vec
s stops working.
Perhaps this can be solved generically by way of some AsRef or Borrow shenannigans?
tried to pass an option to a function
option width {{.width.to_htmode("VHT80")}}
thread 'rustc' panicked at 'called `Result::unwrap()` on an `Err` value: Mismatch', libcore/result.rs:945:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
1: std::sys_common::backtrace::_print
at libstd/sys_common/backtrace.rs:71
2: std::panicking::default_hook::{{closure}}
at libstd/sys_common/backtrace.rs:59
at libstd/panicking.rs:380
3: std::panicking::default_hook
at libstd/panicking.rs:396
4: std::panicking::rust_panic_with_hook
at libstd/panicking.rs:576
5: std::panicking::begin_panic
at libstd/panicking.rs:537
6: std::panicking::begin_panic_fmt
at libstd/panicking.rs:521
7: rust_begin_unwind
at libstd/panicking.rs:497
8: core::panicking::panic_fmt
at libcore/panicking.rs:71
9: core::result::unwrap_failed
at /checkout/src/libcore/macros.rs:23
10: <core::result::Result<T, E>>::unwrap
at /checkout/src/libcore/result.rs:782
11: bart_derive::parse_str
at /home/aep/.cargo/registry/src/github.com-1ecc6299db9ec823/bart_derive-0.1.4/src/lib.rs:44
12: bart_derive::bart_display
at /home/aep/.cargo/registry/src/github.com-1ecc6299db9ec823/bart_derive-0.1.4/src/lib.rs:108
13: std::panicking::try::do_call
14: __rust_maybe_catch_panic
at libpanic_unwind/lib.rs:102
15: <syntax_ext::deriving::custom::ProcMacroDerive as syntax::ext::base::MultiItemModifier>::expand
16: syntax::ext::expand::MacroExpander::expand_invoc
17: syntax::ext::expand::MacroExpander::expand
18: syntax::ext::expand::MacroExpander::expand_crate
19: rustc_driver::driver::phase_2_configure_and_expand_inner::{{closure}}
20: rustc_driver::driver::phase_2_configure_and_expand_inner
21: rustc_driver::driver::compile_input
22: rustc_driver::run_compiler
I found the https://github.com/maghoff/bart/blob/master/src/conditional.rs module through #10. Would it be possible to implement this for Option<T>
as well, e.g. Option<String>
?
Imagined syntax: {{^field}}
...{{/field}}
Standard usecase: Render a list, but show something different when that list is empty.
Other imagined usecase: An Option
can be iterated over for the Some(_)
case, it makes sense to have this syntax work for the None
case. Similarly for Result
.
When using a Result
in a negative section, maybe expose the Err(_)
value as {{.}}
?
some more complex examples would be helpful. I've been looking at the tests to understand how everything works. If you have an idea of what to do for an example, I wouldn't mind writing it.
I haven't been able to think of a good example without being application specific. Maybe the template system for a Pastebin clone or something along those lines?
Presently, a trait object can only expose functions. These are not renderable with Bart. It can be useful to render a heterogeneous list of things, which is most naturally expressed in Rust as an iterable of trait objects (eg &[&Trait]
).
Bart could support trait objects by somehow supporting rendering of functions. Maybe something like {{function_call()}}
, or maybe some shenanigans in Rust might let us allow {{function_call}}
directly?
Imagined syntax: {{>partialname}}
, possibly with an argument for the root scope in the partial: {{>partialname .var}}
I have no idea whether or not this is possible.
for now:
#[derive(BartDisplay)]
#[template = "hello_world.html"]
struct HelloWorld<'a> {
name: &'a str,
}
My suggestion is split renderer and input data type, something like this:
#[derive(BartDisplay)]
#[bart(template="hello_world.html", type_args="'a", input_type="HelloWorld<'a>")]
struct HelloWorldTemplate;
#[derive(BartDisplay)]
#[bart(template="hello_world.mob.html", type_args="'a", input_type="HelloWorld<'a>")]
struct HelloWorldTemplateForMobile;
struct HelloWorld<'a> {
name: &'a str,
}
fn handle_request(req: Request) -> String {
let data: HelloWorld<_> = req.get_data();
if req.is_mobile_browser() {
HelloWoldTemplateForMobile.render(data)
} else {
HelloWoldTemplate.render(data)
}
}
Bart currently fails to accept tags like {{0}}
and {{#a.1.}}
, making it impossible to use tuples for rendering. Specifically, this disallows newtypes, which could be a convenient wrapper in some cases.
HTML escaping fails when the source string ends with a char that should be escaped, for example <'
renders to <''
.
Have you considered running clippy? Right now if you run clippy on a project using bart you get a lot (a few hundred lines) of warnings originating with bart. I've fixed all but one of clippy's lints here, but I'm not sure what to do about the final lint. I don't think it can be fixed because it's with codegen.
I can submit a patch if you would like.
The parsing of variable names should have the same rules as Rust. Currently, variable names must be alphanumeric only. (Help! How does nom work?)
It would be ideal to implement Mustache's functionality here. {{=<% %>=}}
to switch to erb style tags, for example.
What are your thoughts on supporting enums in Bart? As an example, say that I have this setup:
enum Item {
Struct(String),
Enum(String),
Trait(String),
}
#[derive(BartDisplay)]
#[template = "doc.html"]
struct Tmpl {
items: Vec<Item>,
}
{{#items}}
<p class="{{TYPE}}">{{.0}}</p>
{{/items}}
I want the class to be different based on what variant of the enum I have. I saw that function call syntax was added, so would this be the best solution:
impl Item {
pub fn item_type(&self) -> &'static str {
match *self {
Item::Struct(_) => "struct",
Item::Enum(_) => "enum",
Item::Trait(_) => "trait",
}
}
}
{{#items}}
<p class="{{.item_type()}}">{{.0}}</p>
{{/items}}
Or would an enum-specific solution be better?
This is just a hypothetical right now, but it might be useful to think about.
To support rendering the same data structure with different templates. Something like template_root_element
in the below code:
struct HelloWorld<'a> {
name: &'a str,
}
#[derive(BartDisplay)]
#[template="hello_world.html"]
#[template_root_element="data"]
struct HelloWorldTemplate<'a> {
data: HelloWorld<'a>
}
#[derive(BartDisplay)]
#[template="hello_world.mob.html"]
#[template_root_element="data"]
struct HelloWorldTemplateForMobile<'a> {
data: HelloWorld<'a>
}
Combine with 1-tuple structs (issue #14) for even terser syntax:
struct HelloWorld<'a> {
name: &'a str,
}
#[derive(BartDisplay)]
#[template="hello_world.html"]
#[template_root_element="0"]
struct HelloWorldTemplate<'a>(HelloWorld<'a>)
#[derive(BartDisplay)]
#[template="hello_world.mob.html"]
#[template_root_element="0"]
struct HelloWorldTemplateForMobile<'a>(HelloWorld<'a>)
When I move modules around, I end up breaking Bart rendered components because of the path being relative to crate root. It might just be that I also happen to be using a lot of include_str!
which has me used to using paths relative to the file that invokes the macro, but I find relative paths to be a bit nicer. On the flip side, someone with all their templates in a root templates
dir would probably feel the opposite, so take this with a grain of salt. I wonder if you could use a prefix /
to indicate crate root.
(feel free to disregard/close.. just sharing feedback)
When encountering invalid input, bart currently produces invalid output instead of failing.
It'd be nice to be able to express at least basic boolean conditionals in templates.
{{#is_condition}}content{{/is_condition}
This actually works if if is_condition
is an Option<()>
(thanks to IntoIterator
), but not if it is a bool
.
Should be possible with proc_macro_diagnostics
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.