From 1785071f1b17daff032c8a21095b23b3db6f73f8 Mon Sep 17 00:00:00 2001 From: Chris Wong <lambda.fairy@gmail.com> Date: Sun, 30 Jul 2017 15:25:07 +1200 Subject: [PATCH] Allow terminating void elements with semicolons (;) When Rust and HTML syntax differ, Maud tends to side with Rust syntax. This can be seen with string literals, for example, where we use backslash escapes instead of HTML entities. Using `;` to terminate void elements is consistent with this idea. Moreover, this reduces confusion around the generated code. Maud does not insert an extra slash into the HTML output (as per the spec) but the syntax may imply otherwise. This confusion may have been the cause of a [bug I found in the wild][1], where the code omitted the trailing slash on an `input` element. I suspect that this is because the author thought that a trailing slash in the Maud template would lead to one in the HTML output. Switching to semicolons would prevent this misconception. [1]: https://github.com/anowell/quasar/pull/3 --- CHANGELOG.md | 2 ++ maud/tests/basic_syntax.rs | 20 +++++++++++++------- maud_macros/src/parse.rs | 1 + 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7620c26..915f1aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +- [Added] Allow terminating void elements with semicolons (`;`) + [#96](https://github.com/lfairy/maud/pull/96) - [Changed] Update to Rocket 0.3 [#94](https://github.com/lfairy/maud/pull/94) - [Changed] Port to new proc macro interface diff --git a/maud/tests/basic_syntax.rs b/maud/tests/basic_syntax.rs index dd40a83..009177f 100644 --- a/maud/tests/basic_syntax.rs +++ b/maud/tests/basic_syntax.rs @@ -54,14 +54,20 @@ fn nesting_elements() { #[test] fn empty_elements() { - let s = html!("pinkie" br/ "pie").into_string(); + let s = html!("pinkie" br; "pie").into_string(); + assert_eq!(s, "pinkie<br>pie"); +} + +#[test] +fn empty_elements_slash() { + let s = html!("pinkie" br / "pie").into_string(); assert_eq!(s, "pinkie<br>pie"); } #[test] fn simple_attributes() { let s = html! { - link rel="stylesheet" href="styles.css"/ + link rel="stylesheet" href="styles.css"; section id="midriff" { p class="hotpink" "Hello!" } @@ -73,7 +79,7 @@ fn simple_attributes() { #[test] fn empty_attributes() { - let s = html!(div readonly? input type="checkbox" checked? /).into_string(); + let s = html!(div readonly? input type="checkbox" checked?;).into_string(); assert_eq!(s, r#"<div readonly><input type="checkbox" checked></div>"#); } @@ -81,10 +87,10 @@ fn empty_attributes() { fn toggle_empty_attributes() { let rocks = true; let s = html!({ - input checked?[true] / - input checked?[false] / - input checked?[rocks] / - input checked?[!rocks] / + input checked?[true]; + input checked?[false]; + input checked?[rocks]; + input checked?[!rocks]; }).into_string(); assert_eq!(s, concat!( r#"<input checked>"#, diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs index 0357b04..950aa4c 100644 --- a/maud_macros/src/parse.rs +++ b/maud_macros/src/parse.rs @@ -378,6 +378,7 @@ impl Parser { self.attrs(render)?; render.element_open_end(); match self.peek() { + Some(TokenTree { kind: TokenNode::Op(';', _), .. }) | Some(TokenTree { kind: TokenNode::Op('/', _), .. }) => { // Void element self.advance();