From a37458b9fa7f348b21bae70140cfc7cf731f278b Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 28 Sep 2022 16:47:10 -0700 Subject: [PATCH 1/7] chore: fixes to autoformat to prevent double rendering of expr line --- packages/autofmt/README.md | 3 + packages/autofmt/src/buffer.rs | 28 +++++--- packages/autofmt/src/element.rs | 62 ++++++++++++----- packages/autofmt/src/expr.rs | 66 +++++++++++++++++-- packages/autofmt/src/lib.rs | 2 +- packages/autofmt/tests/samples.rs | 2 + packages/autofmt/tests/samples/complex.rsx | 6 +- packages/autofmt/tests/samples/long.rsx | 38 +++++++++++ packages/autofmt/tests/samples/simple.rsx | 20 ++++-- packages/autofmt/tests/wrong.rs | 2 + packages/autofmt/tests/wrong/multiexpr.rsx | 3 + .../autofmt/tests/wrong/multiexpr.wrong.rsx | 3 + packages/rsx/src/component.rs | 6 +- packages/rsx/src/element.rs | 6 +- packages/rsx/src/lib.rs | 1 + packages/rsx/src/node.rs | 2 +- 16 files changed, 203 insertions(+), 47 deletions(-) create mode 100644 packages/autofmt/tests/samples/long.rsx create mode 100644 packages/autofmt/tests/wrong/multiexpr.rsx create mode 100644 packages/autofmt/tests/wrong/multiexpr.wrong.rsx diff --git a/packages/autofmt/README.md b/packages/autofmt/README.md index f1c425c56..bcacee982 100644 --- a/packages/autofmt/README.md +++ b/packages/autofmt/README.md @@ -15,3 +15,6 @@ Sorted roughly in order of what's possible - [ ] Format regular exprs - [ ] Fix prettyplease around chaining - [ ] Don't eat comments in prettyplease + + +# Technique diff --git a/packages/autofmt/src/buffer.rs b/packages/autofmt/src/buffer.rs index e7f82cd01..abf1ac623 100644 --- a/packages/autofmt/src/buffer.rs +++ b/packages/autofmt/src/buffer.rs @@ -124,16 +124,26 @@ impl Buffer { } pub fn write_body_no_indent(&mut self, children: &[BodyNode]) -> Result { - for child in children { - // Exprs handle their own indenting/line breaks - if !matches!(child, BodyNode::RawExpr(_)) { - if self.current_span_is_primary(child.span()) { - self.write_comments(child.span())?; - } - self.tabbed_line()?; - } + let last_child = children.len(); - self.write_ident(child)?; + for (idx, child) in children.iter().enumerate() { + match child { + // check if the expr is a short + BodyNode::RawExpr(_) => { + self.tabbed_line()?; + self.write_ident(child)?; + if idx != last_child - 1 { + write!(self.buf, ",")?; + } + } + _ => { + if self.current_span_is_primary(child.span()) { + self.write_comments(child.span())?; + } + self.tabbed_line()?; + self.write_ident(child)?; + } + } } Ok(()) diff --git a/packages/autofmt/src/element.rs b/packages/autofmt/src/element.rs index 697464300..39a58d801 100644 --- a/packages/autofmt/src/element.rs +++ b/packages/autofmt/src/element.rs @@ -2,6 +2,7 @@ use crate::Buffer; use dioxus_rsx::*; use proc_macro2::Span; use std::{fmt::Result, fmt::Write}; +use syn::{spanned::Spanned, Expr}; #[derive(Debug)] enum ShortOptimization { @@ -87,8 +88,11 @@ impl Buffer { write!(self.buf, ", ")?; } - for child in children { + for (id, child) in children.iter().enumerate() { self.write_ident(child)?; + if id != children.len() - 1 && children.len() > 1 { + write!(self.buf, ", ")?; + } } write!(self.buf, " ")?; @@ -283,28 +287,54 @@ impl Buffer { .map(|child_len| child_len + attr_len) } } - [BodyNode::RawExpr(ref _expr)] => { + [BodyNode::RawExpr(ref expr)] => { // TODO: let rawexprs to be inlined - // let span = syn::spanned::Spanned::span(&text); - // let (start, end) = (span.start(), span.end()); - // if start.line == end.line { - // Some(end.column - start.column) - // } else { - // None - // } - None + get_expr_length(expr) } [BodyNode::Element(ref el)] => { let attr_len = self.is_short_attrs(&el.attributes); - if attr_len > 80 { - None - } else { - self.is_short_children(&el.children) - .map(|child_len| child_len + attr_len) + if el.children.is_empty() && attr_len < 80 { + return Some(el.name.to_string().len()); } + + if el.children.len() == 1 { + if let BodyNode::Text(ref text) = el.children[0] { + if text.value().len() + el.name.to_string().len() + attr_len < 80 { + return Some(text.value().len() + el.name.to_string().len() + attr_len); + } + } + } + + None + } + // todo, allow non-elements to be on the same line + items => { + let mut total_count = 0; + + for item in items { + match item { + BodyNode::Component(_) | BodyNode::Element(_) => return None, + BodyNode::Text(text) => total_count += text.value().len(), + BodyNode::RawExpr(expr) => match get_expr_length(expr) { + Some(len) => total_count += len, + None => return None, + }, + } + } + + Some(total_count) } - _ => None, } } } + +fn get_expr_length(expr: &Expr) -> Option { + let span = expr.span(); + let (start, end) = (span.start(), span.end()); + if start.line == end.line { + Some(end.column - start.column) + } else { + None + } +} diff --git a/packages/autofmt/src/expr.rs b/packages/autofmt/src/expr.rs index d89a5cb39..55fa5ea60 100644 --- a/packages/autofmt/src/expr.rs +++ b/packages/autofmt/src/expr.rs @@ -16,16 +16,46 @@ impl Buffer { let placement = exp.span(); let start = placement.start(); let end = placement.end(); - let num_spaces_desired = (self.indent * 4) as isize; + // let num_spaces_desired = (self.indent * 4) as isize; - let first = &self.src[start.line - 1]; - let num_spaces_real = first.chars().take_while(|c| c.is_whitespace()).count() as isize; + // if the expr is on one line, just write it directly + if start.line == end.line { + write!( + self.buf, + "{}", + &self.src[start.line - 1][start.column - 1..end.column].trim() + )?; + return Ok(()); + } - let offset = num_spaces_real - num_spaces_desired; + // If the expr is multiline, we want to collect all of its lines together and write them out properly + // This involves unshifting the first line if it's aligned - for line in &self.src[start.line - 1..end.line] { + let first_line = &self.src[start.line - 1]; + write!( + self.buf, + "{}", + &first_line[start.column - 1..first_line.len()].trim() + )?; + + let first_prefix = &self.src[start.line - 1][..start.column]; + let offset = match first_prefix.trim() { + "" => 0, + _ => first_prefix + .chars() + .rev() + .take_while(|c| c.is_whitespace()) + .count() as isize, + }; + + for (id, line) in self.src[start.line..end.line].iter().enumerate() { writeln!(self.buf)?; // trim the leading whitespace + let line = match id { + x if x == (end.line - start.line) - 1 => &line[..end.column], + _ => line, + }; + if offset < 0 { for _ in 0..-offset { write!(self.buf, " ")?; @@ -39,6 +69,32 @@ impl Buffer { } } + // let first = &self.src[start.line - 1]; + // let num_spaces_real = first.chars().take_while(|c| c.is_whitespace()).count() as isize; + // let offset = num_spaces_real - num_spaces_desired; + + // for (row, line) in self.src[start.line - 1..end.line].iter().enumerate() { + // let line = match row { + // 0 => &line[start.column - 1..], + // a if a == (end.line - start.line) => &line[..end.column - 1], + // _ => line, + // }; + + // writeln!(self.buf)?; + // // trim the leading whitespace + // if offset < 0 { + // for _ in 0..-offset { + // write!(self.buf, " ")?; + // } + + // write!(self.buf, "{}", line)?; + // } else { + // let offset = offset as usize; + // let right = &line[offset..]; + // write!(self.buf, "{}", right)?; + // } + // } + Ok(()) } } diff --git a/packages/autofmt/src/lib.rs b/packages/autofmt/src/lib.rs index 7a14eae3e..aca9f64b0 100644 --- a/packages/autofmt/src/lib.rs +++ b/packages/autofmt/src/lib.rs @@ -124,7 +124,7 @@ pub fn apply_format(input: &str, block: FormattedBlock) -> String { let (left, _) = input.split_at(start); let (_, right) = input.split_at(end); - dbg!(&block.formatted); + // dbg!(&block.formatted); format!("{}{}{}", left, block.formatted, right) } diff --git a/packages/autofmt/tests/samples.rs b/packages/autofmt/tests/samples.rs index 29332b7da..98383522a 100644 --- a/packages/autofmt/tests/samples.rs +++ b/packages/autofmt/tests/samples.rs @@ -23,3 +23,5 @@ twoway! ("complex" => complex); twoway! ("tiny" => tiny); twoway! ("tinynoopt" => tinynoopt); + +twoway! ("long" => long); diff --git a/packages/autofmt/tests/samples/complex.rsx b/packages/autofmt/tests/samples/complex.rsx index d3e45c67b..598d08a82 100644 --- a/packages/autofmt/tests/samples/complex.rsx +++ b/packages/autofmt/tests/samples/complex.rsx @@ -27,9 +27,7 @@ rsx! { } }) } - div { class: "px-4", - is_current.then(|| rsx!{ children }) - } + div { class: "px-4", is_current.then(|| rsx!{ children }) } } // No nesting @@ -47,4 +45,6 @@ rsx! { let blah = 120; } } + + div { asdbascasdbasd, asbdasbdabsd, asbdabsdbasdbas } } diff --git a/packages/autofmt/tests/samples/long.rsx b/packages/autofmt/tests/samples/long.rsx new file mode 100644 index 000000000..2464a1905 --- /dev/null +++ b/packages/autofmt/tests/samples/long.rsx @@ -0,0 +1,38 @@ +use dioxus::prelude::*; + +#[inline_props] +pub fn Explainer<'a>( + cx: Scope<'a>, + invert: bool, + title: &'static str, + content: Element<'a>, + flasher: Element<'a>, +) -> Element { + // pt-5 sm:pt-24 lg:pt-24 + + let mut right = rsx! { + div { class: "relative w-1/2", flasher } + }; + + let align = match invert { + true => "mr-auto ml-16", + false => "ml-auto mr-16", + }; + + let mut left = rsx! { + div { class: "relative w-1/2 {align} max-w-md leading-8", + h2 { class: "mb-6 text-3xl leading-tight md:text-4xl md:leading-tight lg:text-3xl lg:leading-tight font-heading font-mono font-bold", + "{title}" + } + content + } + }; + + if *invert { + std::mem::swap(&mut left, &mut right); + } + + cx.render(rsx! { + div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light", left, right } + }) +} diff --git a/packages/autofmt/tests/samples/simple.rsx b/packages/autofmt/tests/samples/simple.rsx index a60d69f2a..54ff5f867 100644 --- a/packages/autofmt/tests/samples/simple.rsx +++ b/packages/autofmt/tests/samples/simple.rsx @@ -1,9 +1,6 @@ rsx! { div { "hello world!" } - div { - "hello world!" - "goodbye world!" - } + div { "hello world!", "goodbye world!" } // Simple div div { "hello world!" } @@ -15,7 +12,16 @@ rsx! { div { div { "nested" } } // Nested two level - div { div { h1 { "highly nested" } } } + div { + div { h1 { "highly nested" } } + } + + // Anti-Nested two level + div { + div { + div { h1 { "highly nested" } } + } + } // Compression h3 { class: "mb-2 text-xl font-bold", "Invite Member" } @@ -30,7 +36,9 @@ rsx! { img { class: "mb-6 mx-auto h-24", src: "artemis-assets/images/friends.png", alt: "" } // One level compression - div { a { class: "py-2 px-3 bg-indigo-500 hover:bg-indigo-600 rounded text-xs text-white", href: "#", "Send invitation" } } + div { + a { class: "py-2 px-3 bg-indigo-500 hover:bg-indigo-600 rounded text-xs text-white", href: "#", "Send invitation" } + } // Components Component { ..Props {} } diff --git a/packages/autofmt/tests/wrong.rs b/packages/autofmt/tests/wrong.rs index 4666da79c..acf930b40 100644 --- a/packages/autofmt/tests/wrong.rs +++ b/packages/autofmt/tests/wrong.rs @@ -14,3 +14,5 @@ macro_rules! twoway { twoway!("comments" => comments); twoway!("multi" => multi); + +twoway!("multiexpr" => multiexpr); diff --git a/packages/autofmt/tests/wrong/multiexpr.rsx b/packages/autofmt/tests/wrong/multiexpr.rsx new file mode 100644 index 000000000..1c3f38434 --- /dev/null +++ b/packages/autofmt/tests/wrong/multiexpr.rsx @@ -0,0 +1,3 @@ +cx.render(rsx! { + div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light", left, right } +}) diff --git a/packages/autofmt/tests/wrong/multiexpr.wrong.rsx b/packages/autofmt/tests/wrong/multiexpr.wrong.rsx new file mode 100644 index 000000000..1c3f38434 --- /dev/null +++ b/packages/autofmt/tests/wrong/multiexpr.wrong.rsx @@ -0,0 +1,3 @@ +cx.render(rsx! { + div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light", left, right } +}) diff --git a/packages/rsx/src/component.rs b/packages/rsx/src/component.rs index b4a6a4a93..685ea0124 100644 --- a/packages/rsx/src/component.rs +++ b/packages/rsx/src/component.rs @@ -23,7 +23,7 @@ use syn::{ Token, }; -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Debug)] pub struct Component { pub name: syn::Path, pub prop_gen_args: Option, @@ -193,13 +193,13 @@ impl ToTokens for Component { } // the struct's fields info -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Debug)] pub struct ComponentField { pub name: Ident, pub content: ContentField, } -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Debug)] pub enum ContentField { ManExpr(Expr), Formatted(LitStr), diff --git a/packages/rsx/src/element.rs b/packages/rsx/src/element.rs index 6d9ffd5db..50b8684b5 100644 --- a/packages/rsx/src/element.rs +++ b/packages/rsx/src/element.rs @@ -10,7 +10,7 @@ use syn::{ // ======================================= // Parse the VNode::Element type // ======================================= -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Debug)] pub struct Element { pub name: Ident, pub key: Option, @@ -190,7 +190,7 @@ impl ToTokens for Element { } } -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Debug)] pub enum ElementAttr { /// attribute: "valuee {}" AttrText { name: Ident, value: LitStr }, @@ -231,7 +231,7 @@ impl ElementAttr { } } -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Debug)] pub struct ElementAttrNamed { pub el_name: Ident, pub attr: ElementAttr, diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index 3cd649037..e0c502660 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -33,6 +33,7 @@ use syn::{ Result, Token, }; +#[derive(Debug)] pub struct CallBody { pub roots: Vec, } diff --git a/packages/rsx/src/node.rs b/packages/rsx/src/node.rs index e40a23283..e85329e6a 100644 --- a/packages/rsx/src/node.rs +++ b/packages/rsx/src/node.rs @@ -16,7 +16,7 @@ Parse -> "text {with_args}" -> (0..10).map(|f| rsx!("asd")), // <--- notice the comma - must be a complete expr */ -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Debug)] pub enum BodyNode { Element(Element), Component(Component), From 5313fc0cc6fd76e735d2c9f5fb1228efea7a8134 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 28 Sep 2022 17:06:11 -0700 Subject: [PATCH 2/7] fix: trailing commas with key --- packages/autofmt/src/element.rs | 11 ++++++----- packages/autofmt/tests/samples.rs | 2 ++ packages/autofmt/tests/samples/key.rsx | 9 +++++++++ 3 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 packages/autofmt/tests/samples/key.rsx diff --git a/packages/autofmt/src/element.rs b/packages/autofmt/src/element.rs index 39a58d801..e886bfca0 100644 --- a/packages/autofmt/src/element.rs +++ b/packages/autofmt/src/element.rs @@ -84,7 +84,7 @@ impl Buffer { self.write_attributes(attributes, key, true)?; - if !children.is_empty() && !attributes.is_empty() { + if !children.is_empty() && (!attributes.is_empty() || key.is_some()) { write!(self.buf, ", ")?; } @@ -104,7 +104,7 @@ impl Buffer { } self.write_attributes(attributes, key, true)?; - if !children.is_empty() && !attributes.is_empty() { + if !children.is_empty() && (!attributes.is_empty() || key.is_some()) { write!(self.buf, ",")?; } @@ -117,7 +117,7 @@ impl Buffer { ShortOptimization::NoOpt => { self.write_attributes(attributes, key, false)?; - if !children.is_empty() && !attributes.is_empty() { + if !children.is_empty() && (!attributes.is_empty() || key.is_some()) { write!(self.buf, ",")?; } @@ -282,9 +282,10 @@ impl Buffer { if attr_len > 80 { None + } else if comp.children.is_empty() { + Some(attr_len) } else { - self.is_short_children(&comp.children) - .map(|child_len| child_len + attr_len) + None } } [BodyNode::RawExpr(ref expr)] => { diff --git a/packages/autofmt/tests/samples.rs b/packages/autofmt/tests/samples.rs index 98383522a..954fa8201 100644 --- a/packages/autofmt/tests/samples.rs +++ b/packages/autofmt/tests/samples.rs @@ -25,3 +25,5 @@ twoway! ("tiny" => tiny); twoway! ("tinynoopt" => tinynoopt); twoway! ("long" => long); + +twoway! ("key" => key); diff --git a/packages/autofmt/tests/samples/key.rsx b/packages/autofmt/tests/samples/key.rsx new file mode 100644 index 000000000..c97b6db38 --- /dev/null +++ b/packages/autofmt/tests/samples/key.rsx @@ -0,0 +1,9 @@ +rsx! { + li { key: "{link}", + Link { class: "py-1 px-2 {hover} {hover_bg}", to: "{link}", "{name}" } + } + + li { key: "{link}", asd: "asd", + Link { class: "py-1 px-2 {hover} {hover_bg}", to: "{link}", "{name}" } + } +} From 181a51a63b577b34245440c140297aa3edfddb6c Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Fri, 30 Sep 2022 10:51:53 -0700 Subject: [PATCH 3/7] wip: add whitespace parsing to rsx --- packages/autofmt/README.md | 68 +++++++++++++++++++++ packages/autofmt/src/buffer.rs | 6 +- packages/autofmt/src/element.rs | 14 +++-- packages/autofmt/src/expr.rs | 19 +++++- packages/autofmt/tests/block.rs | 38 ++++++++++++ packages/autofmt/tests/samples.rs | 3 + packages/autofmt/tests/samples/multirsx.rsx | 30 +++++++++ packages/rsx/README.md | 3 + packages/rsx/src/component.rs | 8 +-- packages/rsx/src/lib.rs | 3 + packages/rsx/src/node.rs | 19 +++--- packages/rsx/src/raw_expr.rs | 41 +++++++++++++ packages/rsx/src/text.rs | 33 ++++++++++ packages/rsx/src/whitespace.rs | 17 ++++++ 14 files changed, 278 insertions(+), 24 deletions(-) create mode 100644 packages/autofmt/tests/block.rs create mode 100644 packages/autofmt/tests/samples/multirsx.rsx create mode 100644 packages/rsx/README.md create mode 100644 packages/rsx/src/raw_expr.rs create mode 100644 packages/rsx/src/text.rs create mode 100644 packages/rsx/src/whitespace.rs diff --git a/packages/autofmt/README.md b/packages/autofmt/README.md index bcacee982..eec3b590e 100644 --- a/packages/autofmt/README.md +++ b/packages/autofmt/README.md @@ -18,3 +18,71 @@ Sorted roughly in order of what's possible # Technique + + +div { + div {} + div {} +} + + +div + +possible line break +div +div + + + +string of possible items within a nesting +div { + attr_pair + expr + text + comment +} +a nesting is either a component or an element + +idea: +collect all items into a queue +q +```rust +section { + div { + h1 { p { "asdasd" } } + h1 { p { "asdasd" } } + } +} + +section {} +``` + + +// space +// space +// space + + +3 - section +3 - section div +3 - section div h1 +3 - section div h1 p +3 - section div h1 p text +3 - section +3 - section div +3 - section div h1 +3 - section div h1 p +3 - section div h1 p text + +block + +- when we hit the end of a trail, we can make a decision what needs to be hard breaked +- most nestings cannot be merged into a single one, so at some point we need to write the line break +- this is the scan section. we scan forward until it's obvious where to place a hard break +- when a line is finished, we can print it out by unloading our queued items +- never double nested + + +Terms +- break is a whitespace than can flex, dependent on the situation +- ‹⁠› diff --git a/packages/autofmt/src/buffer.rs b/packages/autofmt/src/buffer.rs index abf1ac623..efb4754c9 100644 --- a/packages/autofmt/src/buffer.rs +++ b/packages/autofmt/src/buffer.rs @@ -67,8 +67,8 @@ impl Buffer { match node { BodyNode::Element(el) => self.write_element(el), BodyNode::Component(component) => self.write_component(component), - BodyNode::Text(text) => self.write_text(text), - BodyNode::RawExpr(exp) => self.write_raw_expr(exp), + BodyNode::Text(text) => self.write_text(&text.text), + BodyNode::RawExpr(exp) => self.write_raw_expr(&exp.expr), } } @@ -129,7 +129,7 @@ impl Buffer { for (idx, child) in children.iter().enumerate() { match child { // check if the expr is a short - BodyNode::RawExpr(_) => { + BodyNode::RawExpr { .. } => { self.tabbed_line()?; self.write_ident(child)?; if idx != last_child - 1 { diff --git a/packages/autofmt/src/element.rs b/packages/autofmt/src/element.rs index e886bfca0..916545deb 100644 --- a/packages/autofmt/src/element.rs +++ b/packages/autofmt/src/element.rs @@ -276,7 +276,7 @@ impl Buffer { } match children { - [BodyNode::Text(ref text)] => Some(text.value().len()), + [BodyNode::Text(ref text)] => Some(text.text.value().len()), [BodyNode::Component(ref comp)] => { let attr_len = self.field_len(&comp.fields, &comp.manual_props); @@ -290,7 +290,7 @@ impl Buffer { } [BodyNode::RawExpr(ref expr)] => { // TODO: let rawexprs to be inlined - get_expr_length(expr) + get_expr_length(&expr.expr) } [BodyNode::Element(ref el)] => { let attr_len = self.is_short_attrs(&el.attributes); @@ -301,8 +301,10 @@ impl Buffer { if el.children.len() == 1 { if let BodyNode::Text(ref text) = el.children[0] { - if text.value().len() + el.name.to_string().len() + attr_len < 80 { - return Some(text.value().len() + el.name.to_string().len() + attr_len); + if text.text.value().len() + el.name.to_string().len() + attr_len < 80 { + return Some( + text.text.value().len() + el.name.to_string().len() + attr_len, + ); } } } @@ -316,8 +318,8 @@ impl Buffer { for item in items { match item { BodyNode::Component(_) | BodyNode::Element(_) => return None, - BodyNode::Text(text) => total_count += text.value().len(), - BodyNode::RawExpr(expr) => match get_expr_length(expr) { + BodyNode::Text(text) => total_count += text.text.value().len(), + BodyNode::RawExpr(expr) => match get_expr_length(&expr.expr) { Some(len) => total_count += len, None => return None, }, diff --git a/packages/autofmt/src/expr.rs b/packages/autofmt/src/expr.rs index 55fa5ea60..48ea6fcc7 100644 --- a/packages/autofmt/src/expr.rs +++ b/packages/autofmt/src/expr.rs @@ -18,6 +18,24 @@ impl Buffer { let end = placement.end(); // let num_spaces_desired = (self.indent * 4) as isize; + // print comments + // let mut queued_comments = vec![]; + // let mut offset = 2; + // loop { + // let line = &self.src[start.line - offset]; + // if line.trim_start().starts_with("//") { + // queued_comments.push(line); + // } else { + // break; + // } + + // offset += 1; + // } + // let had_comments = !queued_comments.is_empty(); + // for comment in queued_comments.into_iter().rev() { + // writeln!(self.buf, "{}", comment)?; + // } + // if the expr is on one line, just write it directly if start.line == end.line { write!( @@ -30,7 +48,6 @@ impl Buffer { // If the expr is multiline, we want to collect all of its lines together and write them out properly // This involves unshifting the first line if it's aligned - let first_line = &self.src[start.line - 1]; write!( self.buf, diff --git a/packages/autofmt/tests/block.rs b/packages/autofmt/tests/block.rs new file mode 100644 index 000000000..6b1298b57 --- /dev/null +++ b/packages/autofmt/tests/block.rs @@ -0,0 +1,38 @@ +use std::collections::VecDeque; + +use dioxus_rsx::{BodyNode, CallBody}; + +const LINE_WIDTH: usize = 80; + +pub struct Printer { + buf: String, + // queue: Vec, +} + +pub enum Break { + // Space flexes to line if need be + Space, + + // Line always forces a new line + // Comments are an example of this + Line, +} + +// enum Item { +// BreakBegin, +// BreakEnd, +// Text(Cow<'static, str>), +// } + +impl Printer { + fn doit(&mut self, body: CallBody) { + for node in body.roots {} + } + fn node(&mut self, node: BodyNode) {} +} + +#[test] +fn it_works() { + let src = r#"div {}"#; + let contents: CallBody = syn::parse_str(src).unwrap(); +} diff --git a/packages/autofmt/tests/samples.rs b/packages/autofmt/tests/samples.rs index 954fa8201..1f9c359c1 100644 --- a/packages/autofmt/tests/samples.rs +++ b/packages/autofmt/tests/samples.rs @@ -27,3 +27,6 @@ twoway! ("tinynoopt" => tinynoopt); twoway! ("long" => long); twoway! ("key" => key); + +// Disabled because we can't handle comments on exprs yet +twoway! ("multirsx" => multirsx); diff --git a/packages/autofmt/tests/samples/multirsx.rsx b/packages/autofmt/tests/samples/multirsx.rsx new file mode 100644 index 000000000..7c7afd646 --- /dev/null +++ b/packages/autofmt/tests/samples/multirsx.rsx @@ -0,0 +1,30 @@ +rsx! { + + // hi + div {} + + // hi + div { abcd, ball, s } + + // + // + // + div { abcd, ball, s } + + // + // + // + div { + // + abcd, + + // + ball, + + // + s, + + // + "asdasd" + } +} diff --git a/packages/rsx/README.md b/packages/rsx/README.md new file mode 100644 index 000000000..d1a21bba3 --- /dev/null +++ b/packages/rsx/README.md @@ -0,0 +1,3 @@ +# The actual RSX language implemented using syn parsers. + +Unlike many macros, actually respects whitespace. diff --git a/packages/rsx/src/component.rs b/packages/rsx/src/component.rs index 685ea0124..ae00926dd 100644 --- a/packages/rsx/src/component.rs +++ b/packages/rsx/src/component.rs @@ -238,11 +238,9 @@ impl Parse for ComponentField { let forked = input.fork(); let t: LitStr = forked.parse()?; // the string literal must either be the end of the input or a followed by a comma - if forked.is_empty() || forked.peek(Token![,]) { - if is_literal_foramtted(&t) { - let content = ContentField::Formatted(input.parse()?); - return Ok(Self { name, content }); - } + if (forked.is_empty() || forked.peek(Token![,])) && is_literal_foramtted(&t) { + let content = ContentField::Formatted(input.parse()?); + return Ok(Self { name, content }); } } diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index e0c502660..85638f3a7 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -18,6 +18,9 @@ mod component; mod element; mod ifmt; mod node; +mod whitespace; +mod raw_expr; +mod text; // Re-export the namespaces into each other pub use component::*; diff --git a/packages/rsx/src/node.rs b/packages/rsx/src/node.rs index e85329e6a..34d26e2a2 100644 --- a/packages/rsx/src/node.rs +++ b/packages/rsx/src/node.rs @@ -1,3 +1,5 @@ +use crate::{raw_expr::RawExprNode, text::TextNode}; + use super::*; use proc_macro2::{Span, TokenStream as TokenStream2}; @@ -5,7 +7,7 @@ use quote::{quote, ToTokens, TokenStreamExt}; use syn::{ parse::{Parse, ParseStream}, spanned::Spanned, - token, Expr, LitStr, Result, + token, LitStr, Result, }; /* @@ -16,17 +18,17 @@ Parse -> "text {with_args}" -> (0..10).map(|f| rsx!("asd")), // <--- notice the comma - must be a complete expr */ -#[derive(PartialEq, Eq, Debug)] +#[derive(Debug, PartialEq, Eq)] pub enum BodyNode { Element(Element), Component(Component), - Text(LitStr), - RawExpr(Expr), + Text(TextNode), + RawExpr(RawExprNode), } impl BodyNode { pub fn is_litstr(&self) -> bool { - matches!(self, BodyNode::Text(_)) + matches!(self, BodyNode::Text { .. }) } pub fn span(&self) -> Span { @@ -83,12 +85,11 @@ impl Parse for BodyNode { // crate::Input:: {} if body_stream.peek(token::Brace) { Component::validate_component_path(&path)?; - return Ok(BodyNode::Component(stream.parse()?)); } } - Ok(BodyNode::RawExpr(stream.parse::()?)) + Ok(BodyNode::RawExpr(stream.parse()?)) } } @@ -97,8 +98,8 @@ impl ToTokens for BodyNode { match &self { BodyNode::Element(el) => el.to_tokens(tokens), BodyNode::Component(comp) => comp.to_tokens(tokens), - BodyNode::Text(txt) => tokens.append_all(quote! { - __cx.text(format_args_f!(#txt)) + BodyNode::Text(text) => tokens.append_all(quote! { + __cx.text(format_args_f!(#text)) }), BodyNode::RawExpr(exp) => tokens.append_all(quote! { __cx.fragment_from_iter(#exp) diff --git a/packages/rsx/src/raw_expr.rs b/packages/rsx/src/raw_expr.rs new file mode 100644 index 000000000..1a0b48ce6 --- /dev/null +++ b/packages/rsx/src/raw_expr.rs @@ -0,0 +1,41 @@ +use proc_macro2::{Span, TokenStream as TokenStream2}; +use quote::{ToTokens, TokenStreamExt}; +use syn::{parse::Parse, spanned::Spanned, Expr}; + +use crate::whitespace::Whitespace; + +#[derive(Debug, PartialEq, Eq)] +pub struct RawExprNode { + pub ws: Whitespace, + pub expr: Expr, +} + +impl RawExprNode { + pub fn span(&self) -> Span { + self.expr.span() + } +} + +impl Parse for RawExprNode { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let before_cursor = input.cursor(); + + let expr = input.parse()?; + + let after = input.cursor(); + + dbg!(before_cursor.span().start(), after.span().end()); + + Ok(Self { + ws: Whitespace::default(), + expr, + }) + } +} + +impl ToTokens for RawExprNode { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let expr = &self.expr; + tokens.append_all(quote::quote! { #expr }); + } +} diff --git a/packages/rsx/src/text.rs b/packages/rsx/src/text.rs new file mode 100644 index 000000000..2be647394 --- /dev/null +++ b/packages/rsx/src/text.rs @@ -0,0 +1,33 @@ +use proc_macro2::{Span, TokenStream as TokenStream2}; +use quote::{quote, ToTokens, TokenStreamExt}; +use syn::{parse::Parse, LitStr}; + +use crate::whitespace::Whitespace; + +#[derive(Debug, PartialEq, Eq)] +pub struct TextNode { + pub ws: Whitespace, + pub text: LitStr, +} + +impl TextNode { + pub fn span(&self) -> Span { + self.text.span() + } +} + +impl Parse for TextNode { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + Ok(Self { + ws: Whitespace::default(), + text: input.parse()?, + }) + } +} + +impl ToTokens for TextNode { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let text = &self.text; + tokens.append_all(quote! { #text }); + } +} diff --git a/packages/rsx/src/whitespace.rs b/packages/rsx/src/whitespace.rs new file mode 100644 index 000000000..c409c8880 --- /dev/null +++ b/packages/rsx/src/whitespace.rs @@ -0,0 +1,17 @@ +#![allow(dead_code)] + +use proc_macro2::Span; + +#[derive(Debug, Default)] +pub struct Whitespace { + span_start: Option, + span_end: Option, +} + +// right now we dont care if whitespace is different, sorry +impl Eq for Whitespace {} +impl PartialEq for Whitespace { + fn eq(&self, _other: &Self) -> bool { + true + } +} From 3fd08ef49e908dd67f42b6a46eb02b4bffc7a80b Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 19 Dec 2022 16:12:15 -0800 Subject: [PATCH 4/7] chore: remove unneeded files --- packages/rsx/src/lib.rs | 3 --- packages/rsx/src/node.rs | 2 +- packages/rsx/src/raw_expr.rs | 41 ---------------------------------- packages/rsx/src/text.rs | 33 --------------------------- packages/rsx/src/whitespace.rs | 17 -------------- 5 files changed, 1 insertion(+), 95 deletions(-) delete mode 100644 packages/rsx/src/raw_expr.rs delete mode 100644 packages/rsx/src/text.rs delete mode 100644 packages/rsx/src/whitespace.rs diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index af21f95b4..a3e93fe95 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -17,10 +17,7 @@ mod component; mod element; mod ifmt; mod node; -mod raw_expr; mod template; -mod text; -mod whitespace; // Re-export the namespaces into each other pub use component::*; diff --git a/packages/rsx/src/node.rs b/packages/rsx/src/node.rs index 89eac05d3..29f18fa31 100644 --- a/packages/rsx/src/node.rs +++ b/packages/rsx/src/node.rs @@ -1,4 +1,4 @@ -use crate::{raw_expr::RawExprNode, text::TextNode}; +// use crate::{raw_expr::RawExprNode, text::TextNode}; use super::*; diff --git a/packages/rsx/src/raw_expr.rs b/packages/rsx/src/raw_expr.rs deleted file mode 100644 index 1a0b48ce6..000000000 --- a/packages/rsx/src/raw_expr.rs +++ /dev/null @@ -1,41 +0,0 @@ -use proc_macro2::{Span, TokenStream as TokenStream2}; -use quote::{ToTokens, TokenStreamExt}; -use syn::{parse::Parse, spanned::Spanned, Expr}; - -use crate::whitespace::Whitespace; - -#[derive(Debug, PartialEq, Eq)] -pub struct RawExprNode { - pub ws: Whitespace, - pub expr: Expr, -} - -impl RawExprNode { - pub fn span(&self) -> Span { - self.expr.span() - } -} - -impl Parse for RawExprNode { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let before_cursor = input.cursor(); - - let expr = input.parse()?; - - let after = input.cursor(); - - dbg!(before_cursor.span().start(), after.span().end()); - - Ok(Self { - ws: Whitespace::default(), - expr, - }) - } -} - -impl ToTokens for RawExprNode { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let expr = &self.expr; - tokens.append_all(quote::quote! { #expr }); - } -} diff --git a/packages/rsx/src/text.rs b/packages/rsx/src/text.rs deleted file mode 100644 index 2be647394..000000000 --- a/packages/rsx/src/text.rs +++ /dev/null @@ -1,33 +0,0 @@ -use proc_macro2::{Span, TokenStream as TokenStream2}; -use quote::{quote, ToTokens, TokenStreamExt}; -use syn::{parse::Parse, LitStr}; - -use crate::whitespace::Whitespace; - -#[derive(Debug, PartialEq, Eq)] -pub struct TextNode { - pub ws: Whitespace, - pub text: LitStr, -} - -impl TextNode { - pub fn span(&self) -> Span { - self.text.span() - } -} - -impl Parse for TextNode { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - Ok(Self { - ws: Whitespace::default(), - text: input.parse()?, - }) - } -} - -impl ToTokens for TextNode { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let text = &self.text; - tokens.append_all(quote! { #text }); - } -} diff --git a/packages/rsx/src/whitespace.rs b/packages/rsx/src/whitespace.rs deleted file mode 100644 index c409c8880..000000000 --- a/packages/rsx/src/whitespace.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![allow(dead_code)] - -use proc_macro2::Span; - -#[derive(Debug, Default)] -pub struct Whitespace { - span_start: Option, - span_end: Option, -} - -// right now we dont care if whitespace is different, sorry -impl Eq for Whitespace {} -impl PartialEq for Whitespace { - fn eq(&self, _other: &Self) -> bool { - true - } -} From 4313dea351d616bcee0bf517b72ac69f20b35eb7 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 19 Dec 2022 16:12:51 -0800 Subject: [PATCH 5/7] chore: clear readme --- packages/rsx/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/rsx/README.md b/packages/rsx/README.md index d1a21bba3..920fcd88c 100644 --- a/packages/rsx/README.md +++ b/packages/rsx/README.md @@ -1,3 +1 @@ # The actual RSX language implemented using syn parsers. - -Unlike many macros, actually respects whitespace. From 182f11d0f371830751d8cc31ffa6a4c8e39c7d39 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 19 Dec 2022 16:17:59 -0800 Subject: [PATCH 6/7] chore: update with master --- packages/autofmt/src/element.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/autofmt/src/element.rs b/packages/autofmt/src/element.rs index 16b4d8a68..f17aac462 100644 --- a/packages/autofmt/src/element.rs +++ b/packages/autofmt/src/element.rs @@ -298,7 +298,7 @@ impl Buffer { } [BodyNode::RawExpr(ref expr)] => { // TODO: let rawexprs to be inlined - get_expr_length(&expr.expr) + get_expr_length(expr) } [BodyNode::Element(ref el)] => { let attr_len = self.is_short_attrs(&el.attributes); @@ -309,10 +309,10 @@ impl Buffer { if el.children.len() == 1 { if let BodyNode::Text(ref text) = el.children[0] { - if text.text.value().len() + el.name.to_string().len() + attr_len < 80 { - return Some( - text.text.value().len() + el.name.to_string().len() + attr_len, - ); + let value = text.source.as_ref().unwrap().value(); + + if value.len() + el.name.to_string().len() + attr_len < 80 { + return Some(value.len() + el.name.to_string().len() + attr_len); } } } @@ -326,11 +326,15 @@ impl Buffer { for item in items { match item { BodyNode::Component(_) | BodyNode::Element(_) => return None, - BodyNode::Text(text) => total_count += text.text.value().len(), - BodyNode::RawExpr(expr) => match get_expr_length(&expr.expr) { + BodyNode::Text(text) => { + total_count += text.source.as_ref().unwrap().value().len() + } + BodyNode::RawExpr(expr) => match get_expr_length(expr) { Some(len) => total_count += len, None => return None, }, + BodyNode::ForLoop(_) => todo!(), + BodyNode::IfChain(_) => todo!(), } } From 4e330bc1ec939eaf2a519b0578980e7bfe9805f1 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 19 Dec 2022 16:20:02 -0800 Subject: [PATCH 7/7] chore: fix rsx printer --- packages/autofmt/tests/block.rs | 38 --------------------- packages/autofmt/tests/samples/multirsx.rsx | 5 --- 2 files changed, 43 deletions(-) delete mode 100644 packages/autofmt/tests/block.rs diff --git a/packages/autofmt/tests/block.rs b/packages/autofmt/tests/block.rs deleted file mode 100644 index 6b1298b57..000000000 --- a/packages/autofmt/tests/block.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::collections::VecDeque; - -use dioxus_rsx::{BodyNode, CallBody}; - -const LINE_WIDTH: usize = 80; - -pub struct Printer { - buf: String, - // queue: Vec, -} - -pub enum Break { - // Space flexes to line if need be - Space, - - // Line always forces a new line - // Comments are an example of this - Line, -} - -// enum Item { -// BreakBegin, -// BreakEnd, -// Text(Cow<'static, str>), -// } - -impl Printer { - fn doit(&mut self, body: CallBody) { - for node in body.roots {} - } - fn node(&mut self, node: BodyNode) {} -} - -#[test] -fn it_works() { - let src = r#"div {}"#; - let contents: CallBody = syn::parse_str(src).unwrap(); -} diff --git a/packages/autofmt/tests/samples/multirsx.rsx b/packages/autofmt/tests/samples/multirsx.rsx index 7c7afd646..380ef3487 100644 --- a/packages/autofmt/tests/samples/multirsx.rsx +++ b/packages/autofmt/tests/samples/multirsx.rsx @@ -15,13 +15,8 @@ rsx! { // // div { - // abcd, - - // ball, - - // s, //