lambda-fairy / maud Goto Github PK
View Code? Open in Web Editor NEW:pencil: Compile-time HTML templates for Rust
Home Page: https://maud.lambda.xyz
License: Apache License 2.0
:pencil: Compile-time HTML templates for Rust
Home Page: https://maud.lambda.xyz
License: Apache License 2.0
I have a usecase that I believe would be rather awesome if it were implemented: Having a struct take content. It would be something like that:
html!(buffer, {
!Column::new() {
!Column::width_and_margin(10, 1) {
h1 { "Hello World" }
}
}
});
Output:
<div class="column-12">
<div class="column-10 push-1">
<h1>Hello World</h1>
</div>
</div>
Where as Column would implement a trait that would emit a String or so, and get as an argument a reader which represents the content inside, something akin to:
pub trait Wrapper {
fn wrap(&self, content: &Read) -> impl Write;
}
I have seen that you have pushed something the past weeks that seems similar to that, if yes then it would be awesome to know how to use it and when it might be released.
Would it be possible to write something like this:
html! {
.this-is-a-class#and_id {
"Hello"
}
}
Which would be a div with the class 'this-is-a-class' and the id 'and_id'. It would make writing a bit more ergonomic.
So I'm on latest nightly rust, but maud_macros fails to build with this: Full log
Fresh encoding_index_tests v0.1.4
Fresh winapi v0.2.5
Fresh libc v0.2.7
Fresh winapi-build v0.1.1
Fresh encoding-index-simpchinese v1.20141219.5
Fresh encoding-index-korean v1.20141219.5
Fresh rand v0.3.14
Fresh matches v0.1.2
Fresh chunked_transfer v0.3.1
Fresh encoding-index-japanese v1.20141219.5
Fresh ascii v0.5.4
Fresh num v0.1.31
Fresh encoding-index-singlebyte v1.20141219.5
Fresh maud v0.7.4
Fresh rustc-serialize v0.3.18
Fresh encoding-index-tradchinese v1.20141219.5
Compiling maud_macros v0.7.4
Running `rustc /home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/lib.rs --crate-name maud_macros --crate-type dylib -C prefer-dynamic -g -C metadata=dc22172e4b120c65 -C extra-filename=-dc22172e4b120c65 --out-dir /home/kamal/rust/stdweb/target/debug/deps --emit=dep-info,link -L dependency=/home/kamal/rust/stdweb/target/debug/deps -L dependency=/home/kamal/rust/stdweb/target/debug/deps --extern maud=/home/kamal/rust/stdweb/target/debug/deps/libmaud-836982335beffc9c.rlib --cap-lints allow`
Fresh uuid v0.1.18
Fresh encoding v0.2.32
Fresh kernel32-sys v0.2.1
Fresh url v0.2.38
Fresh time v0.1.34
Fresh chrono v0.2.19
Fresh tiny_http v0.5.1
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:2:25: 2:34 error: unresolved import `syntax::ast::ExprParen`. There is no `ExprParen` in `syntax::ast` [E0432]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:2 use syntax::ast::{Expr, ExprParen, Lit, Stmt, TokenTree};
^~~~~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:2:25: 2:34 help: run `rustc --explain E0432` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:439:9: 439:30 error: unresolved import `syntax::ast::Lit_::*`. Could not find `Lit_` in `syntax::ast` [E0432]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:439 use syntax::ast::Lit_::*;
^~~~~~~~~~~~~~~~~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:439:9: 439:30 help: run `rustc --explain E0432` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:440:22: 440:33 error: unresolved name `String::new` [E0425]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:440 let mut result = String::new();
^~~~~~~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:440:22: 440:33 help: run `rustc --explain E0425` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:445:9: 445:15 error: unresolved enum variant, struct or const `LitStr` [E0419]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:445 LitStr(s, _) => result.push_str(&s),
^~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:445:9: 445:15 help: run `rustc --explain E0419` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:446:9: 446:19 error: unresolved enum variant, struct or const `LitByteStr` [E0419]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:446 LitByteStr(..) | LitByte(..) => {
^~~~~~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:446:9: 446:19 help: run `rustc --explain E0419` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:446:26: 446:33 error: unresolved enum variant, struct or const `LitByte` [E0419]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:446 LitByteStr(..) | LitByte(..) => {
^~~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:446:26: 446:33 help: run `rustc --explain E0419` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:19:16: 19:19 error: unresolved name `Err` [E0425]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:19 return Err(::syntax::errors::FatalError);
^~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:447:13: 447:63 note: in this expansion of error! (defined in /home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs)
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:19:16: 19:19 help: run `rustc --explain E0425` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:449:9: 449:16 error: unresolved enum variant, struct or const `LitChar` [E0419]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:449 LitChar(c) => result.push(c),
^~~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:449:9: 449:16 help: run `rustc --explain E0419` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:450:9: 450:15 error: unresolved enum variant, struct or const `LitInt` [E0419]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:450 LitInt(x, _) => result.push_str(&x.to_string()),
^~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:450:9: 450:15 help: run `rustc --explain E0419` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:451:9: 451:17 error: unresolved enum variant, struct or const `LitFloat` [E0419]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:451 LitFloat(s, _) | LitFloatUnsuffixed(s) => result.push_str(&s),
^~~~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:451:9: 451:17 help: run `rustc --explain E0419` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:451:26: 451:44 error: unresolved enum variant, struct or const `LitFloatUnsuffixed` [E0419]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:451 LitFloat(s, _) | LitFloatUnsuffixed(s) => result.push_str(&s),
^~~~~~~~~~~~~~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:451:26: 451:44 help: run `rustc --explain E0419` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:452:9: 452:16 error: unresolved enum variant, struct or const `LitBool` [E0419]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:452 LitBool(b) => result.push_str(if b { "true" } else { "false" }),
^~~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:452:9: 452:16 help: run `rustc --explain E0419` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:454:5: 454:7 error: unresolved name `Ok` [E0425]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:454 Ok(result)
^~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:454:5: 454:7 help: run `rustc --explain E0425` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:460:22: 460:31 error: `ExprParen` is not an enum variant, struct or const [E0418]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:460 Expr { node: ExprParen(inner), .. } => inner,
^~~~~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:442:9: 442:25 error: the type of this value must be known in this context
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/parse.rs:442 result.push('-');
^~~~~~~~~~~~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:72:25: 72:31 error: no method named `to_tokens` found for type `collections::vec::Vec<syntax::ptr::P<syntax::codemap::Spanned<syntax::ast::StmtKind>>>` in the current scope
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:72 $stmts
^~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:64:9: 78:11 note: in this expansion of quote_expr!
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:72:25: 72:31 note: the method `to_tokens` exists but the following trait bounds were not satisfied: `syntax::ptr::P<syntax::codemap::Spanned<syntax::ast::StmtKind>> : syntax::ext::quote::rt::ToTokens`
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:102:9: 110:24 error: mismatched types:
expected `syntax::ptr::P<syntax::codemap::Spanned<syntax::ast::StmtKind>>`,
found `syntax::codemap::Spanned<syntax::ast::StmtKind>`
(expected struct `syntax::ptr::P`,
found struct `syntax::codemap::Spanned`) [E0308]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:102 quote_stmt!(
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:103 self.cx,
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:104 match $expr {
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:105 Ok(()) => {},
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:106 Err(e) => {
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:107 $result = Err(e);
...
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:102:9: 110:24 help: run `rustc --explain E0308` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:163:56: 163:64 error: no method named `to_tokens` found for type `collections::vec::Vec<syntax::ptr::P<syntax::codemap::Spanned<syntax::ast::StmtKind>>>` in the current scope
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:163 None => quote_stmt!(self.cx, if $if_cond { $if_body }),
^~~~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:163:21: 163:67 note: in this expansion of quote_stmt!
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:163:56: 163:64 note: the method `to_tokens` exists but the following trait bounds were not satisfied: `syntax::ptr::P<syntax::codemap::Spanned<syntax::ast::StmtKind>> : syntax::ext::quote::rt::ToTokens`
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:165:52: 165:60 error: no method named `to_tokens` found for type `collections::vec::Vec<syntax::ptr::P<syntax::codemap::Spanned<syntax::ast::StmtKind>>>` in the current scope
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:165 quote_stmt!(self.cx, if $if_cond { $if_body } else { $else_body }),
^~~~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:165:17: 165:83 note: in this expansion of quote_stmt!
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:165:52: 165:60 note: the method `to_tokens` exists but the following trait bounds were not satisfied: `syntax::ptr::P<syntax::codemap::Spanned<syntax::ast::StmtKind>> : syntax::ext::quote::rt::ToTokens`
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:165:70: 165:80 error: no method named `to_tokens` found for type `collections::vec::Vec<syntax::ptr::P<syntax::codemap::Spanned<syntax::ast::StmtKind>>>` in the current scope
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:165 quote_stmt!(self.cx, if $if_cond { $if_body } else { $else_body }),
^~~~~~~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:165:17: 165:83 note: in this expansion of quote_stmt!
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:165:70: 165:80 note: the method `to_tokens` exists but the following trait bounds were not satisfied: `syntax::ptr::P<syntax::codemap::Spanned<syntax::ast::StmtKind>> : syntax::ext::quote::rt::ToTokens`
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:167:19: 167:23 error: mismatched types:
expected `syntax::ptr::P<syntax::codemap::Spanned<syntax::ast::StmtKind>>`,
found `syntax::codemap::Spanned<syntax::ast::StmtKind>`
(expected struct `syntax::ptr::P`,
found struct `syntax::codemap::Spanned`) [E0308]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:167 self.push(stmt);
^~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:167:19: 167:23 help: run `rustc --explain E0308` to see a detailed explanation
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:171:69: 171:74 error: no method named `to_tokens` found for type `collections::vec::Vec<syntax::ptr::P<syntax::codemap::Spanned<syntax::ast::StmtKind>>>` in the current scope
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:171 let stmt = quote_stmt!(self.cx, for $pattern in $iterable { $body }).unwrap();
^~~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:171:20: 171:77 note: in this expansion of quote_stmt!
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:171:69: 171:74 note: the method `to_tokens` exists but the following trait bounds were not satisfied: `syntax::ptr::P<syntax::codemap::Spanned<syntax::ast::StmtKind>> : syntax::ext::quote::rt::ToTokens`
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:172:19: 172:23 error: mismatched types:
expected `syntax::ptr::P<syntax::codemap::Spanned<syntax::ast::StmtKind>>`,
found `syntax::codemap::Spanned<syntax::ast::StmtKind>`
(expected struct `syntax::ptr::P`,
found struct `syntax::codemap::Spanned`) [E0308]
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:172 self.push(stmt);
^~~~
/home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/render.rs:172:19: 172:23 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to 9 previous errors
Could not compile `maud_macros`.
Caused by:
Process didn't exit successfully: `rustc /home/kamal/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.4/src/lib.rs --crate-name maud_macros --crate-type dylib -C prefer-dynamic -g -C metadata=dc22172e4b120c65 -C extra-filename=-dc22172e4b120c65 --out-dir /home/kamal/rust/stdweb/target/debug/deps --emit=dep-info,link -L dependency=/home/kamal/rust/stdweb/target/debug/deps -L dependency=/home/kamal/rust/stdweb/target/debug/deps --extern maud=/home/kamal/rust/stdweb/target/debug/deps/libmaud-836982335beffc9c.rlib --cap-lints allow` (exit code: 101)
rust version:
rustc 1.8.0-nightly (c894ff6b1 2016-02-20)
cargo:
cargo 0.9.0-nightly (34269d0 2016-02-18)
The existing section talks about streaming and moving things, but these traits can be used for more than that.
In particular, we should cover difference between Display
(plain text representation) and Render
(HTML representation), and how in general PreEscaped(Display)
is an anti-pattern.
http://www.rubydoc.info/gems/slim/frames#Boolean_attributes
We'll probably need a dedicated AttributeValue
trait for this:
pub trait AttributeValue: fmt::Display {
fn render_as_attribute(&self, sink: &mut MarkupSink, name: &str) {
sink.write_str(" ");
sink.write_str(name);
sink.write_str("=\"");
sink.as_escaped().write_fmt(format_args!("{}", self));
sink.write_str("\"");
}
}
impl AttributeValue for bool {
fn render_as_attribute(&self, sink: &mut MarkupSink, name: &str) {
if *self {
sink.write_str(" ");
sink.write_str(name);
}
}
}
impl AttributeValue for str {}
impl AttributeValue for i32 {}
// ...
Depends on #3.
This code:
#[test]
fn foo() {
macro_rules! to_string {
($($x:tt)*) => {{
let mut s = String::new();
html!(s, $($x)*).unwrap();
s
}}
}
let name = "Lyra";
let s = to_string!(p { "Hi, " $name "!" });
assert_eq!(s, "<p>Hi, Lyra!</p>");
}
fails to compile with the following error:
tests/tests.rs:309:35: 309:40 error: invalid syntax
tests/tests.rs:309 let s = to_string!(p { "Hi, " $name "!" });
This is because when macro_rules!
encounters a $
followed by an identifier, it combines these two tokens into a single SubstNt
token. Maud does not know about this special token, and so displays the error shown.
The solution would be to expand this SubstNt
back into its two original tokens.
h1#(foo)
should set the id
attribute of h1
to the value of foo
. Similarly for h1.(foo)
.
We'll have to think a bit about how to deal when foo
is an iterable. Automatically add spaces between the elements?
Right now the renderer emits code like this:
w.write_str("<p");
w.write_str(" ");
w.write_str("id");
w.write_str("=\");
// ...
when it can do this instead:
w.write_str("<p id=\"scootaloo\">Rainbow Dash!</p>");
The compiler doesn't seem to do this optimization itself, so we'll need to do it in the renderer.
I believe
@while let ...
isn't supported currently (0.12.0). If not, it would be a welcome addition besides @for
and @if let
.
The test suite is getting kind of hairy. Might be worth splitting it into separate files.
https://github.com/laumann/compiletest-rs might be good too.
I just saw your update here and wondered, because it already compiled for me since some time. Now I saw that the github version has 0.1.1 in toml but the cargo.io version is 0.1.2 since 30. january :)
What is going on here? Time machine?
This doesn't work:
macro_rules! greet {
() => ({
let mut result = String::new();
let name = "Pinkie Pie";
html!(result, p { "Hello, " $name "!" });
result
})
}
That's because macro_rules!
tries to expand $name
itself, when it should be handled by Maud instead.
We can probably work around that by adding a new #splice
magic operator. So the code above would look like this:
// ...
html!(result, p { "Hello, " #splice name "!" });
// ...
This works because it doesn't have a $
in it.
The FAQ page in the book has a broken link to "horrowshow". From a quick Googling I think this may have moved to horrowshow-rs?
Happy to PR, but you'll need to point me at the sources for the book as I couldn't find them :)
In theory the existing signatures of Render
/RenderOnce
allow for more efficient code. But in practice we often end up just invoking html!
and pushing that to the buffer. If this is the more common use case, then we should have these trait methods return Markup
directly instead.
Something like this:
trait Render {
fn render(&self) -> Markup;
// what .render() used to be
fn render_to(&self, buffer: &mut String) {
buffer.push_str(&self.render());
}
}
// similarly for RenderOnce
Note that we still need .render_to()
to optimize the blanket impl for T: Display
, because write!(s, "{}", x)
is much faster than x.to_string()
.
Example:
// shorthand for linking to a stylesheet
struct Stylesheet<S>(pub S);
impl<S: AsRef<str>> Render for Stylesheet<S> {
fn render(&self) -> Markup {
html! {
link rel="stylesheet" type="text/css" href=(self.0.as_ref()) /
}
}
}
tests/tests.rs:1:1: 1:1 warning: label name `__maud_loop_label` shadows a label name that is already in scope
tests/tests.rs:1 #![feature(plugin)]
^
tests/tests.rs:450:5: 450:17 note: in this expansion of html! (defined in tests/tests.rs)
tests/tests.rs:1:1: 1:1 note: shadowed label `__maud_loop_label` declared here
tests/tests.rs:1 #![feature(plugin)]
^
tests/tests.rs:449:5: 449:17 note: in this expansion of html! (defined in tests/tests.rs)
tests/tests.rs:1:1: 1:1 warning: label name `__maud_loop_label` shadows a label name that is already in scope
tests/tests.rs:1 #![feature(plugin)]
^
tests/tests.rs:483:5: 483:20 note: in this expansion of html! (defined in tests/tests.rs)
tests/tests.rs:1:1: 1:1 note: shadowed label `__maud_loop_label` declared here
tests/tests.rs:1 #![feature(plugin)]
^
tests/tests.rs:482:5: 482:20 note: in this expansion of html! (defined in tests/tests.rs)
Probably related to rust-lang/rust#21633
The existing benchmarks are okay, but a bit simplistic. I'd love to have code that reflects the kind of use cases we see in the real world.
Since std::fmt::Write
is marked as unstable, anyone who uses Maud would get unstable warnings in their code.
We can initially make MarkupSink
a newtype around &mut fmt::Write
. It should expose .write_str()
and .write_fmt()
which forward directly to the inner Write
, as well as .as_escaped()
which creates an Escaper
wrapper.
Horrorshow uses this technique, and it works pretty well.
Currently, html!
wraps its generated code in a closure. While this design adds flexibility in theory, it causes confusing lifetime issues in practice. (See #14)
I'd like to switch to a write!
-style macro instead, where the writer is passed in directly:
write_html!(io::stdout(), {
p "Hello, world!"
}).unwrap();
As well as being easier to understand, this change is also in line with Maud's principle of adding as little abstraction as possible.
let name = "Pinkie Pie";
let doova = "Rarity";
let lacky = false;
html! {
p { "Hello, " (name) "!" }
input data-foo=(doova) disabled?(lacky) /
}
This doesn't work:
html! {
$(format!("{:x}", 42))
}
I (@lambda-fairy) am adopting the top comment to summarize the unstable features used in Maud. The original text can be found at the bottom of this comment.
Summary of unstable features:
proc_macro_hygiene
(rust-lang/rust#54727)proc_macro_diagnostic
(rust-lang/rust#54140)proc_macro_span
(rust-lang/rust#54725)specialization
(rust-lang/rust#31844)proc_macro_def_site
(rust-lang/rust#54724)proc_macro_quote
(rust-lang/rust#54722)Original comment by Hoverbear:
Hey! You might be able to get this to work on stable with Syntex.
I'm having problems with inline expressions inside attributes.
What I want:
script src=$ASSETS_PATH/"js/epiceditor.min.js" {}
is not working.
Maud is failing to compile with latest Rust nightly I think because of the rename of the std::io
to std::old_io
:
/home/travis/.cargo/registry/src/github.com-1ecc6299db9ec823/maud-0.1.1/src/lib.rs:160:15: 160:22 error: unresolved import `std::io::IoError`. Could not find `io` in `std`
/home/travis/.cargo/registry/src/github.com-1ecc6299db9ec823/maud-0.1.1/src/lib.rs:160 use std::io::{IoError, IoErrorKind, IoResult};
^~~~~~~
/home/travis/.cargo/registry/src/github.com-1ecc6299db9ec823/maud-0.1.1/src/lib.rs:160:24: 160:35 error: unresolved import `std::io::IoErrorKind`. Could not find `io` in `std`
/home/travis/.cargo/registry/src/github.com-1ecc6299db9ec823/maud-0.1.1/src/lib.rs:160 use std::io::{IoError, IoErrorKind, IoResult};
^~~~~~~~~~~
/home/travis/.cargo/registry/src/github.com-1ecc6299db9ec823/maud-0.1.1/src/lib.rs:160:37: 160:45 error: unresolved import `std::io::IoResult`. Could not find `io` in `std`
/home/travis/.cargo/registry/src/github.com-1ecc6299db9ec823/maud-0.1.1/src/lib.rs:160 use std::io::{IoError, IoErrorKind, IoResult};
^~~~~~~~
Can I use external html files with maud?
Can I inherit one html file from another, that is "master-layout" page -> child?
$ cargo run
unused manifest key: bin.src
Updating registry `https://github.com/rust-lang/crates.io-index`
Compiling modifier v0.1.0
Compiling typeable v0.1.2
Compiling gcc v0.3.21
Compiling traitobject v0.0.1
Compiling encoding-index-tradchinese v1.20141219.5
Compiling encoding-index-singlebyte v1.20141219.5
Compiling encoding-index-korean v1.20141219.5
Compiling encoding-index-japanese v1.20141219.5
Compiling rustc_version v0.1.4
Compiling rustc-serialize v0.3.16
Compiling unicode-xid v0.0.3
Compiling kernel32-sys v0.2.1
Compiling ws2_32-sys v0.2.1
Compiling advapi32-sys v0.1.2
Compiling unsafe-any v0.4.1
Compiling error v0.1.9
Compiling encoding-index-simpchinese v1.20141219.5
Compiling typemap v0.3.3
Compiling pkg-config v0.3.6
Compiling rand v0.3.13
Compiling net2 v0.2.20
Compiling time v0.1.34
Compiling plugin v0.2.6
Compiling num_cpus v0.2.10
Compiling unicase v1.1.1
Compiling log v0.3.5
Compiling maud_macros v0.7.3
Compiling term v0.2.14
Compiling encoding v0.2.32
Compiling hpack v0.2.0
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/parse.rs:66:8: 66:24 error: wrong number of lifetime parameters: expected 1, found 0 [E0107]
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/parse.rs:66 -> PResult<P<Expr>>
^~~~~~~~~~~~~~~~
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/parse.rs:66:8: 66:24 help: run `rustc --explain E0107` to see a detailed explanation
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/parse.rs:79:8: 79:51 error: wrong number of lifetime parameters: expected 1, found 0 [E0107]
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/parse.rs:79 -> PResult<(&'a [TokenTree], &'a [TokenTree])>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/parse.rs:79:8: 79:51 help: run `rustc --explain E0107` to see a detailed explanation
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/parse.rs:437:58: 437:73 error: wrong number of lifetime parameters: expected 1, found 0 [E0107]
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/parse.rs:437 fn lit_to_string(cx: &ExtCtxt, lit: Lit, minus: bool) -> PResult<String> {
^~~~~~~~~~~~~~~
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/parse.rs:437:58: 437:73 help: run `rustc --explain E0107` to see a detailed explanation
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/lib.rs:21:76: 21:92 error: wrong number of lifetime parameters: expected 1, found 0 [E0107]
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/lib.rs:21 fn html(cx: &mut ExtCtxt, sp: Span, mac_name: &str, args: &[TokenTree]) -> PResult<P<Expr>> {
^~~~~~~~~~~~~~~~
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/lib.rs:21:76: 21:92 help: run `rustc --explain E0107` to see a detailed explanation
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/lib.rs:26:81: 26:97 error: wrong number of lifetime parameters: expected 1, found 0 [E0107]
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/lib.rs:26 fn html_utf8(cx: &mut ExtCtxt, sp: Span, mac_name: &str, args: &[TokenTree]) -> PResult<P<Expr>> {
^~~~~~~~~~~~~~~~
/Users/jaden/.multirust/toolchains/nightly/cargo/registry/src/github.com-88ac128001ac3a9a/maud_macros-0.7.3/src/lib.rs:26:81: 26:97 help: run `rustc --explain E0107` to see a detailed explanation
error: aborting due to 5 previous errors
Compiling openssl-sys v0.7.4
Build failed, waiting for other jobs to finish...
Could not compile `maud_macros`.
I am using
$ rustc --version
rustc 1.7.0-nightly (2bd875d3d 2016-01-19)
The following iteration works:
let vec: Vec<()> = vec!();
html! {
$for _ in &vec {
}
};
However, iterating over vec.iter()
fails to compile:
let vec: Vec<()> = vec!();
let iter = vec.iter();
html! {
$for _ in &iter {
}
};
This fails with:
error: the trait `core::iter::Iterator` is not implemented for the type `&core::slice::Iter<'_, ()>` [E0277]
Iterating over vec.into_iter()
fails to compile with a similar error.
This may lead to better spans/diagnostics.
After writing #44 (comment), I realized the same argument applies to the empty attribute syntax.
That is, given the tokens div contenteditable ? (foo)
, it's ambiguous whether foo
toggles the contenteditable
attribute, or is the body of the div
.
One possible fix is to swap the tokens around: div contenteditable(foo)?
. This reminds me of Rust's ?
operator, which is nice. On the other hand this new syntax doesn't look much like an attribute.
macro_rules! parse_error {
($self:expr, $sp:expr, $msg:expr) => ({
$self.render.cx.span_err($sp, $msg);
return Err(::syntax::diagnostic::FatalError);
})
}
See https://manishearth.github.io/rust-internals-docs/syntax/parse/type.PResult.html
I'm thinking, it would be nice to be able to put any random rust expression inside html!
Eg:
html! {
p {
$(match id {
Some(id) => id,
None => 0,
})
}
}
This could replace $if
$else
etc. It seems it is more flexible to just get whole $( ... )
block and stuff it into lambda, rather then having only some types of expressions supported.
Is this already possible? Did I missed anything in the docs?
This is not working for me:
#![feature(plugin)]
#![plugin(maud_macros)]
extern crate maud;
use std::io;
fn main() {
let template1 = html! {
span {
"This is the inner content"
}
};
let html1 = template1.to_string();
let template2 = html! {
html {
div {
$$html1
}
}
};
template2.render(&mut io::stdout()).unwrap();
}
I get
<quote expansion>:2:64: 2:80 error: cannot move out of captured outer variable in an `Fn` closure
<quote expansion>:2 name_71,ctxt_9)
^~~~~~~~~~~~~~~~
src/main.rs:1:1: 25:1 note: in expansion of html!
src/main.rs:16:21: 22:6 note: expansion site
error: aborting due to previous error
Is there some other way to have templates include other templates?
I tried to compile the example from the docs and get:
Compiling maud v0.0.1 (file:///...../maud)
main.rs:9:18: 11:7 error: borrowed value does not live long enough
main.rs:9 let markup = html! {
main.rs:10 p { "Hi, " $name "!" }
main.rs:11 };
main.rs:1:1: 14:1 note: in expansion of html!
main.rs:9:18: 11:7 note: expansion site
main.rs:7:11: 14:2 note: reference must be valid for the block at 7:10...
(Additionally I can't use rustc --pretty expanded
as it seems that is gone in current nightly 2015-01-24?)
Just encountered a bug very similar to #23, just using $(expr)
inside the html instead.
#[test]
fn foo() {
macro_rules! to_string {
($($x:tt)*) => {{
let mut s = String::new();
html!(s, $($x)*).unwrap();
s
}}
}
let name = "Lyra";
let s = to_string!(p { "Hi, " $(name) "!" });
assert_eq!(s, "<p>Hi, Lyra!</p>");
}
gives
tests/tests.rs:324:47: 324:48 error: expected `*` or `+`
tests/tests.rs:324 let s = to_string!(p { "Hi, " $(name) "!" });
Some tags have boolean attributes (like <option>
and it's selected
attribute) right now one has to use an @if
to set it.
A possible syntax I thought of could be something akin to:
html!(
option selected=?(val == opt.some_val) (opt.label)
)
This would be needed for feature completeness.
I know that the introduction clearly states that
You'll need to install the Nightly version of Rust to use it.
But it would be nice if there was a hint at what compiler APIs are required and when they are going to be stable.
Hello!
There seem to be an issue using class names with double dashes (--) when using the class shorthand:
button.mdl-button--colored "Button"
Results in:
src/main.rs:110:34: 110:35 error: invalid syntax
src/main.rs:110 button.mdl-button--colored "Button"
^
I'm playing around with material design lite, and double dashes are frequently used in the CSS. See for example https://getmdl.io/started/index.html.
For example:
@{ let a = bit.source.unwrap(); }
html! {
ul @for pony in &["Rarity", "Fluttershy", "Pinkie Pie"] {
li.pink(pony == "Pinkie Pie") { (pony) }
}
}
It can often be useful to toggle a class based on a boolean flag. Need to be careful with multiple classes.
Using Display
here seems wrong, because semantically Display
gives a plain text representation, not an HTML representation. So in effect, PreEscaped<T: Display>
is a claim that the plain text and HTML representations of a type are the same, which doesn't really make sense in general.
We can change the constraint to T: AsRef<str>
instead. This covers what I think is the primary use case (including HTML output from an external source) without bringing in that semantic baggage. It doesn't cover fancy data structures like ropes, but I don't think they'll come up in a web app.
This change will also drive users toward implementing the Render
trait, which is the idiomatic way to customize HTML output (see #53).
My question is: Are there any existing use cases of PreEscaped
which are not either...
PreEscaped("<!DOCTYPE html>")
Render
trait instead... ?
If not, then we can go ahead on this change.
pub trait ToMarkup {
fn to_markup(&self, &mut fmt::Write) -> fmt::Result;
}
// let name = "Pinkie Pie";
// html! { $name }
impl<T: fmt::Display + ?Sized> ToMarkup for T {
default fn to_markup(&self, w: &mut fmt::Write) -> fmt::Result {
write!(Escaper::new(w), "{}", self)
}
}
// fn subtemplate(...) -> ... { ... }
// html! { $subtemplate }
impl<F: Fn(&mut fmt::Write) -> fmt::Result + ?Sized> ToMarkup for F {
default fn to_markup(&self, w: &mut fmt::Write) -> fmt::Result {
(*self)(w)
}
}
pub struct PreEscaped<T: ?Sized>(pub T);
// let blog_post = "<h1>My Awesome Article</h1> ... ";
// html! { $PreEscaped(blog_post) }
impl<T: fmt::Display + ?Sized> ToMarkup for PreEscaped<T> {
default fn to_markup(&self, w: &mut fmt::Write) -> fmt::Result {
write!(w, "{}", self.0)
}
}
With the PreEscaped
type, we can remove the $$expr
operator since $PreEscaped(expr)
does the same thing.
Depends on rust-lang/rfcs#1210.
Since Render
takes itself by reference anything that implements it needs to support re-rendering multiple times. While working on supporting modified event streams in (second example at maud-pulldown-cmark
) I found this limiting as pulldown_cmark::Parser
isn't reusable, requiring me to wrap stuff up in closures to allow re-creating the parser when necessary. In most cases it's very unlikely that these structs would be kept around, so I was wondering if it were possible to have fn render(self, w: &mut Write) -> fmt::Result
and provide implementations for references where needed.
With all the attention this is getting, now is a good time to spell out my ideas about where this project should go.
Write
over allocating a String
(efficient).The following fails:
button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-
target="#navbar" aria-expanded="false" aria-controls="navbar" {
...
}
How do I handle dash signs in attribute names?
let surprise = Some("Boo!");
html! {
p title?=(surprise) "Hover over me"
}
Like Alternative 1, but with the syntax title=?(surprise)
instead.
Use the same syntax as normal splices, title=(surprise)
, but use trait magic to omit the attribute when surprise.is_none()
.
Implementation: Add a method, fn is_present(&self) -> bool
, to the Render
trait. This method returns true
for all types except Option<T>
, which returns self.is_some()
. Then at run time, the code will call surprise.is_present()
to decide whether or not to emit the attribute.
Not sure how this composes -- what does title={ "I say: " (surprise) }
mean?
Example:
html! {
$if friends.empty() {
p "You have no friends :("
} $else {
ul $for name in friends {
li $name
}
}
}
$maybe
syntax, for handling optional values. if let
.{}
can be omitted after elements, but for control structures they're mandatory. While not without reason, the inconsistency feels a bit icky.$match
as well? How would that work?I'd love to see some benchmarks against other template engines. I don't want to claim that Maud is fast without hard data.
Ideally we'd focus on real-world use cases, such as the docs.rs front page. In this case docs.rs uses Handlebars already, so that's half of the work done.
Cannot access the doc.
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.