From 683bbda6ad0f52990c24b4aea3a2c2fd66242639 Mon Sep 17 00:00:00 2001 From: Chinedu Francis Nwafili Date: Wed, 6 Mar 2019 07:36:19 -0500 Subject: [PATCH] Start cleaning up html macro --- book/src/html-macro/text/README.md | 22 +++++--- crates/html-macro-test/src/lib.rs | 3 +- crates/html-macro/src/lib.rs | 4 ++ crates/html-macro/src/parser/braced.rs | 70 ++++++++++---------------- crates/html-macro/src/parser/mod.rs | 20 +++++++- crates/virtual-dom-rs/CHANGELOG.md | 2 +- crates/virtual-dom-rs/Cargo.toml | 2 +- 7 files changed, 70 insertions(+), 53 deletions(-) diff --git a/book/src/html-macro/text/README.md b/book/src/html-macro/text/README.md index 1c632e0d..1e6e3107 100644 --- a/book/src/html-macro/text/README.md +++ b/book/src/html-macro/text/README.md @@ -1,25 +1,33 @@ # Working with Text -Rather than needing you to wrap your text in `"` quotation marks, -the `html-macro` will work with raw unquoted text. +One of the most popular types of nodes in the DOM is the [Text] node, and the `html! macro +focuses heavily on making them as easy to create as possible. + +You can just type unquoted text into the `html!` macro and neighboring text will get combined into a single `Text` node, much +like the way that web browsers handle text from html documents. ```rust fn main () { - let interpolated_var = "interpolate text variables."; + let interpolated_text = "interpolate text variables."; let example = html! {
Text can be typed directly into your HTML. -
Or you can also {interpolated_var}
+
Or you can also {interpolated_text}
}; } ``` -You should always get the same spacing (or lack there of) between text and/or elements as you would +## Preserving Space Between Blocks + +You should always get the same spacing (or lack there of) between text and other elements as you would if you were working in a regular old `.html` file. -When it comes to interpolated variables, we base spacing on the spacing outside of the brackets. +When it comes to interpolated variables, we base spacing on the spacing outside of the braces, not the +inside. + +Let's illustrate: ```rust fn main () { @@ -46,3 +54,5 @@ text nodes / variables / elements. {{ #include ../../../../crates/html-macro-test/src/text.rs }} ``` + +[Text]: https://developer.mozilla.org/en-US/docs/Web/API/Text diff --git a/crates/html-macro-test/src/lib.rs b/crates/html-macro-test/src/lib.rs index 35f2c377..3f43e55d 100644 --- a/crates/html-macro-test/src/lib.rs +++ b/crates/html-macro-test/src/lib.rs @@ -177,7 +177,8 @@ fn text_next_to_block() { .test(); } -/// Ensure that we maintain the correct spacing around punctuation tokens +/// Ensure that we maintain the correct spacing around punctuation tokens, since +/// they resolve into a separate TokenStream during parsing. #[test] fn punctuation_token() { let text = "Hello, World"; diff --git a/crates/html-macro/src/lib.rs b/crates/html-macro/src/lib.rs index 79d10669..d24374ad 100644 --- a/crates/html-macro/src/lib.rs +++ b/crates/html-macro/src/lib.rs @@ -19,6 +19,10 @@ pub fn html(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let parsed_tags_len = parsed.tags.len(); + // Iterate over all of our parsed tags and push them into our HtmlParser one by one. + // + // As we go out HtmlParser will maintain some heuristics about what we've done so far + // since that will sometimes inform how to parse the next token. for (idx, tag) in parsed.tags.iter().enumerate() { let mut next_tag = None; diff --git a/crates/html-macro/src/parser/braced.rs b/crates/html-macro/src/parser/braced.rs index 50a8696f..16d8b46c 100644 --- a/crates/html-macro/src/parser/braced.rs +++ b/crates/html-macro/src/parser/braced.rs @@ -13,6 +13,33 @@ impl HtmlParser { brace_span: &Span, next_tag: Option<&Tag>, ) { + // If + // 1. The next tag is a closing bracket or another brace + // 2. There is space between this brace and that next tag + // + // Then + // We'll insert some spacing after this brace. + // + // This ensures that we properly maintain spacing between two neighboring braced + // text nodes + // + // html! {
{ This Brace } { Space WILL be inserted }
+ // ->
This Brace Space WILL be inserted
+ // + // html! {
{ This Brace }{ Space WILL NOT be inserted }
+ // ->
This BraceSpace WILL NOT be inserted
+ let should_insert_space_after = match next_tag { + Some(Tag::Close { + first_angle_bracket_span, + .. + }) => self.separated_by_whitespace(brace_span, &first_angle_bracket_span), + Some(Tag::Braced { + brace_span: next_brace_span, + .. + }) => self.separated_by_whitespace(brace_span, &next_brace_span), + _ => false, + }; + let node_idx = &mut self.current_node_idx; let parent_to_children = &mut self.parent_to_children; let parent_stack = &mut self.parent_stack; @@ -24,49 +51,6 @@ impl HtmlParser { None => None, }; - let mut should_insert_space_after = false; - - // FIXME: Move into function - if let Some(next_tag) = next_tag { - if let Tag::Close { - first_angle_bracket_span, - .. - } = next_tag - { - let spans_on_different_lines = - first_angle_bracket_span.start().line != brace_span.end().line; - - if spans_on_different_lines { - should_insert_space_after = true; - } else { - let space_between_spans = - first_angle_bracket_span.start().column - brace_span.end().column > 0; - if space_between_spans { - should_insert_space_after = true; - } - } - } - - if let Tag::Braced { - brace_span: next_brace_span, - .. - } = next_tag - { - let spans_on_different_lines = - next_brace_span.start().line != brace_span.end().line; - - if spans_on_different_lines { - should_insert_space_after = true; - } else { - let space_between_spans = - next_brace_span.start().column - brace_span.end().column > 0; - if space_between_spans { - should_insert_space_after = true; - } - } - } - }; - // We ignore this check if the last tag kind was text since the text // parser will already handle inserting spaces before and after text. let last_tag_kind_was_text = self.last_tag_kind == Some(TagKind::Text); diff --git a/crates/html-macro/src/parser/mod.rs b/crates/html-macro/src/parser/mod.rs index 5756ed2c..34f51547 100644 --- a/crates/html-macro/src/parser/mod.rs +++ b/crates/html-macro/src/parser/mod.rs @@ -11,7 +11,9 @@ mod close_tag; mod open_tag; mod text; -/// Iterate over Tag's that we've parsed and build a tree of VirtualNode's +/// Used to parse [Tag]'s that we've parsed and build a tree of VirtualNode's +/// +/// [Tag]: enum.Tag.html pub struct HtmlParser { /// As we parse our macro tokens we'll generate new tokens to return back into the compiler /// when we're done. @@ -156,6 +158,22 @@ impl HtmlParser { self.recent_span_locations.most_recent_block_start = Some(span.start()); self.recent_span_locations.most_recent_block_end = Some(span.end()); } + + /// Determine whether or not there is any space between the end of the first + /// span and the beginning of the second span. + /// + /// There is space if they are on separate lines or if they have different columns. + /// + /// html! {
Hello
} <--- no space between end of div and Hello + /// + /// html! {
Hello
} <--- space between end of div and Hello + fn separated_by_whitespace(&self, first_span: &Span, second_span: &Span) -> bool { + if first_span.end().line != second_span.end().line { + return true; + } + + second_span.start().column - first_span.end().column > 0 + } } /// Keep track of the locations of different kinds of tokens that we encounter. diff --git a/crates/virtual-dom-rs/CHANGELOG.md b/crates/virtual-dom-rs/CHANGELOG.md index 7ac3ffa7..2673cb7d 100644 --- a/crates/virtual-dom-rs/CHANGELOG.md +++ b/crates/virtual-dom-rs/CHANGELOG.md @@ -13,7 +13,7 @@ Types of changes: _Here we list notable things that have been merged into the master branch but have not been released yet._ -- ... +- [fixed] Proper spacing in between text nodes and elements in all cases [PR](TODO: Link here) ## 0.6.5 - Mar 4, 2019 diff --git a/crates/virtual-dom-rs/Cargo.toml b/crates/virtual-dom-rs/Cargo.toml index 5c77d59f..1c2d0017 100644 --- a/crates/virtual-dom-rs/Cargo.toml +++ b/crates/virtual-dom-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "virtual-dom-rs" -version = "0.6.5" +version = "0.6.6" authors = ["Chinedu Francis Nwafili "] description = "A standalone Virtual DOM creation, diffing and patching implementation" keywords = ["virtual", "dom", "wasm", "assembly", "webassembly"]