Skip to content

Commit

Permalink
Merge pull request #97 from chinedufn/text-space
Browse files Browse the repository at this point in the history
Preserve spacing around text nodes and braces
  • Loading branch information
chinedufn authored Mar 7, 2019
2 parents 877ab50 + 95a53a8 commit 8ac5e30
Show file tree
Hide file tree
Showing 18 changed files with 643 additions and 223 deletions.
16 changes: 8 additions & 8 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ jobs:
keys:
# Checksum ensures that when we update versions for our `html-macro` dependencies we clear our cache, otherwise
# compiletest-rs can error when the target directory has multiple versions of a crate.
- v4-cargo-cache-test-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
- v4-cargo-cache-test-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
- v5-cargo-cache-test-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
- v5-cargo-cache-test-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}

# Install nightly & wasm
- run:
Expand Down Expand Up @@ -65,12 +65,12 @@ jobs:

# Save cache
- save_cache:
key: v4-cargo-cache-test-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
key: v5-cargo-cache-test-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
paths:
- target
- /usr/local/cargo
- save_cache:
key: v4-cargo-cache-test-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
key: v5-cargo-cache-test-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
paths:
- target
- /usr/local/cargo
Expand All @@ -84,8 +84,8 @@ jobs:
# Multiple caches are used to increase the chance of a cache hit.
- restore_cache:
keys:
- v4-cargo-cache-docs-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
- v4-cargo-cache-docs-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
- v5-cargo-cache-docs-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
- v5-cargo-cache-docs-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}

# Install nightly
- run:
Expand Down Expand Up @@ -120,12 +120,12 @@ jobs:

# Save cache
- save_cache:
key: v4-cargo-cache-docs-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
key: v5-cargo-cache-docs-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
paths:
- target
- /usr/local/cargo
- save_cache:
key: v4-cargo-cache-docs-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
key: v5-cargo-cache-docs-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
paths:
- target
- /usr/local/cargo
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,11 @@ pub fn start() {

let mut dom_updater = DomUpdater::new_append_to_mount(start_view, &body);

let greetings = "Hello, World!";

let end_view = html! {
<div class="big blue">
<strong>Hello, World!</strong>
<strong>{ greetings }</strong>

<button
class=MY_COMPONENT_CSS
Expand All @@ -119,7 +121,6 @@ pub fn start() {
</div>
};


dom_updater.update(end_view);
}

Expand Down
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- [Writing html!](./html-macro/README.md)
- [Writing html!](./html-macro/html-macro.md)
- [Compile Time Errors](./html-macro/compile-time-errors.md)
- [Working with Text](./html-macro/text/README.md)
- [Virtual DOM](./virtual-dom/README.md)
- [Unit Testing your Views](./virtual-dom/unit-testing-views.md)
- [Server Side Rendering (SSR)](./views/server-side-rendering/README.md)
Expand Down
49 changes: 49 additions & 0 deletions book/src/html-macro/text/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Working with 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_text = "interpolate text variables.";

let example = html! {
<div>
Text can be typed directly into your HTML.
<div>Or you can also {interpolated_text}</div>
</div>
};
}
```

## 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.

We'll preserve newline characters so that `white-space: pre-wrap` etc will work as expected.

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 () {
let text = "hello";

html! { <div>{ hello }</div> }; // <div>hello</div>
html! { <div>{hello}</div> }; // <div>hello</div>

html! { <div> { hello } </div> }; // <div> hello </div>
html! { <div> {hello} </div> }; // <div> hello </div>

html! { <div>{hello} </div> }; // <div>hello </div>
html! { <div> {hello}</div> }; // <div> hello</div>
}
```

[Text]: https://developer.mozilla.org/en-US/docs/Web/API/Text
135 changes: 23 additions & 112 deletions crates/html-macro-test/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#![feature(proc_macro_hygiene)]
#![cfg(test)]

use html_macro::html;
use std::collections::HashMap;
use virtual_node::{IterableNodes, VElement, VirtualNode};

mod text;

struct HtmlMacroTest<'a> {
desc: &'a str,
generated: VirtualNode,
Expand All @@ -14,7 +15,7 @@ struct HtmlMacroTest<'a> {
impl<'a> HtmlMacroTest<'a> {
/// Ensure that the generated and the expected virtual node are equal.
fn test(self) {
assert_eq!(self.generated, self.expected, "{}", self.desc);
assert_eq!(self.expected, self.generated, "{}", self.desc);
}
}

Expand Down Expand Up @@ -115,7 +116,13 @@ fn nested_macro() {
let child_2 = html! { <b></b> };

let mut expected = VElement::new("div");
expected.children = vec![VirtualNode::element("span"), VirtualNode::element("b")];
expected.children = vec![
VirtualNode::text(" "),
VirtualNode::element("span"),
VirtualNode::text(" "),
VirtualNode::element("b"),
VirtualNode::text(" "),
];

HtmlMacroTest {
desc: "Nested macros",
Expand Down Expand Up @@ -152,8 +159,9 @@ fn text_next_to_block() {

let mut expected = VElement::new("div");
expected.children = vec![
VirtualNode::text("A bit of text"),
VirtualNode::text(" A bit of text "),
VirtualNode::element("ul"),
VirtualNode::text(" "),
];

HtmlMacroTest {
Expand All @@ -169,37 +177,15 @@ fn text_next_to_block() {
.test();
}

/// Ensure that we maintain the correct spacing around punctuation tokens, since
/// they resolve into a separate TokenStream during parsing.
#[test]
fn punctuation_comma() {
fn punctuation_token() {
let text = "Hello, World";

HtmlMacroTest {
desc: "Comma",
generated: html! { Hello, World},
expected: VirtualNode::text(text),
}
.test()
}

#[test]
fn punctuation_exclamation() {
let text = "Hello World!";

HtmlMacroTest {
desc: "Exclamation point",
generated: html! { Hello World! },
expected: VirtualNode::text(text),
}
.test()
}

#[test]
fn punctuation_period() {
let text = "Hello.";

HtmlMacroTest {
desc: "Period",
generated: html! { Hello. },
desc: "Punctuation token spacing",
generated: html! { Hello, World },
expected: VirtualNode::text(text),
}
.test()
Expand All @@ -210,7 +196,12 @@ fn vec_of_nodes() {
let children = vec![html! { <div> </div>}, html! { <strong> </strong>}];

let mut expected = VElement::new("div");
expected.children = vec![VirtualNode::element("div"), VirtualNode::element("strong")];
expected.children = vec![
VirtualNode::text(" "),
VirtualNode::element("div"),
VirtualNode::element("strong"),
VirtualNode::text(" "),
];

HtmlMacroTest {
desc: "Vec of nodes",
Expand All @@ -220,92 +211,12 @@ fn vec_of_nodes() {
.test();
}

#[test]
fn text_root_node() {
HtmlMacroTest {
desc: "Text as root node",
generated: html! { some text },
expected: VirtualNode::text("some text"),
}
.test()
}

/// Just make sure that this compiles since type is a keyword
#[test]
fn type_attribute() {
html! { <link rel="stylesheet" type="text/css" href="/app.css" /> };
}

#[test]
fn text_variable_root() {
let text = "hello world";

HtmlMacroTest {
desc: "Text variable root",
generated: html! { { text } },
expected: VirtualNode::text("hello world"),
}
.test()
}

#[test]
fn text_variable_child() {
let text = "world";

HtmlMacroTest {
desc: "Text variable child",
generated: html! { <div> { text } </div> },
expected: html! { <div> world </div> },
}
.test()
}

//#[test]
//fn text_space_after_start_tag () {
// assert_eq!(
// &html! { <div> Hello</div> }.to_string(),
// "<div> Hello</div>"
// )
//}
//
//#[test]
//fn text_space_beore_end_tag () {
// assert_eq!(
// &html! { <div>Hello </div> }.to_string(),
// "<div>Hello </div>"
// )
//}
//
//#[test]
//fn text_space_before_block() {
// let text = "Hello";
//
// assert_eq!(
// &html! { <div> {text}</div> }.to_string(),
// "<div>Hello </div>"
// )
//}
//
//#[test]
//fn text_space_after_block() {
// let text = "Hello";
//
// assert_eq!(
// &html! { <div>{text} </div> }.to_string(),
// "<div> Hello</div>"
// )
//}
//
//#[test]
//fn text_space_in_block_ignored() {
// let text = "Hello";
//
// assert_eq!(
// &html! { <div>{ text }</div> }.to_string(),
// "<div>Hello</div>"
// )
//}

// Verify that all of our self closing tags work as both.
// Self closing tags can be written as either <tag> and <tag />
#[test]
Expand Down
Loading

0 comments on commit 8ac5e30

Please sign in to comment.