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),