Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve whitespace before and after text tokens #98

Closed
chinedufn opened this issue Mar 7, 2019 · 1 comment
Closed

Preserve whitespace before and after text tokens #98

chinedufn opened this issue Mar 7, 2019 · 1 comment

Comments

@chinedufn
Copy link
Owner

in a comment in #97 @dbrgn pointed out that we're assuming that preserving whitespace and newlines doesn't matter when it actually does. The current implementation will break for white-space: pre-wrap among other scenarios.


Here's how we need to handle braces

/// FIXME: Stop doing this! Instead of inserting text nodes just check how much white space
/// is between the block and the tag before it as well as the block and the tag after it.
/// Then, insert quote! tokens that take a mutable reference to the first element in the
/// iterable nodes and adds spacing / new lines before it if it is a VText variant.
/// Then take a mutable reference to the last element in the iterable nodes and add
/// spacing after it if it is a VText variant. Add methods to IterableNodes to easily
/// get an optional reference to the first or last element.


Notably, handling braces by injecting quote'd tokens that will mutate the real text nodes allows us to stop doing this hack of injecting text nodes when we're unsure if a brace will contain a text node. We can just handle this at runtime by injecting quote'd tokens.

VirtualNode::text(" "),


And for text tokens we can preserve whitespace by finding the line / column differences between neighboring text token trees here

let current_span_start = tt.span().start();
let most_recent_span_end = most_recent_span.end();
let spans_on_different_lines = current_span_start.line != most_recent_span_end.line;
// Spans are on different lines, insert space
if spans_on_different_lines {
text += " ";
break;
} else if current_span_start.column - most_recent_span_end.column > 0 {
text += " ";
}


Then later when parsing text we can look at the tag that comes before and after the text to determine how much more space to put around it

https://github.com/chinedufn/percy/blob/edd4122ccee157566e5118e4c3e74d210eb3a091/crates/html-macro/src/parser/text.rs#L5-L4


As always... unit testing will be paramount here. Need to add cases one by one and make them pass.

https://github.com/chinedufn/percy/blob/e124a87e2c119d760e2e1cfdd3ace0e64945ba93/crates/html-macro-test/src/text.rs#L2-L1


Hi person reading this! If you run into this issue and need this done let me know and I'll prioritize it! Otherwise I'll get to it whenever I get to it (aka when it becomes a problem for me).

@chinedufn
Copy link
Owner Author

Anyone using rustfmt wouldn't be able to benefit from this unless they set up special rustfmt rules

see rust-lang/rustfmt#3434


Given that - going to instead just require that in the rare cases that someone wants to preserve exact sequences of whitespace (instead of the usual collapsing into one whitespace) they can just use text variable interpolation.

fn main () {
    let text = r#"This needs
it's whitespace perfectly
      preserved"#;

    html! { <span style="white-space: pre-wrap">{ text }</span> };
}

So going to add documentation on this then close this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant