Przeglądaj źródła

feat: more tests and spans

Jonathan Kelley 3 lat temu
rodzic
commit
284860f470

+ 1 - 1
packages/autofmt/Cargo.toml

@@ -6,7 +6,7 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-proc-macro2 = { version = "1.0.6" }
+proc-macro2 = { version = "1.0.6", features = ["span-locations"] }
 quote = "1.0"
 syn = { version = "1.0.11", features = ["full", "extra-traits"] }
 dioxus-rsx = { path = "../rsx" }

+ 85 - 29
packages/autofmt/src/lib.rs

@@ -41,20 +41,6 @@ pub fn get_format_blocks(contents: &str) -> Vec<FormattedBlock> {
             continue;
         }
 
-        // match cur_match {
-        //     Some(ref this_match) => {
-        //         // abort nested matches - these get handled automatically
-        //         if start < this_match.end {
-        //             continue;
-        //         } else {
-        //             cur_match = Some(item);
-        //         }
-        //     }
-        //     None => {
-        //         cur_match = Some(item);
-        //     }
-        // }
-
         let remaining = &contents[end - 1..];
 
         if let Some(bracket_end) = find_bracket_end(remaining) {
@@ -67,6 +53,14 @@ pub fn get_format_blocks(contents: &str) -> Vec<FormattedBlock> {
 
             if let Some(new) = fmt_block(sub_string) {
                 if !new.is_empty() {
+                    println!("{}", &contents[end + 1..bracket_end + end - 1]);
+                    println!("{}", new);
+
+                    let stripped = &contents[end + 1..bracket_end + end - 1];
+                    if stripped == new {
+                        println!("no changes necessary");
+                    }
+
                     // if we have code to push, we want the code to end up on the right lines with the right indentation
 
                     let mut output = String::new();
@@ -94,18 +88,25 @@ pub fn get_format_blocks(contents: &str) -> Vec<FormattedBlock> {
 }
 
 pub fn fmt_block(block: &str) -> Option<String> {
+    let mut raw_lines = block.split('\n').collect::<Vec<_>>();
+
     let parsed: CallBody = syn::parse_str(block).ok()?;
 
     let mut buf = String::new();
 
     for node in parsed.roots.iter() {
-        write_ident(&mut buf, node, 0).ok()?;
+        write_ident(&mut buf, &raw_lines, node, 0).ok()?;
     }
 
     Some(buf)
 }
 
-pub fn write_ident(buf: &mut String, node: &BodyNode, indent: usize) -> fmt::Result {
+pub fn write_ident(
+    buf: &mut String,
+    lines: &[&str],
+    node: &BodyNode,
+    indent: usize,
+) -> fmt::Result {
     match node {
         BodyNode::Element(el) => {
             let Element {
@@ -168,7 +169,7 @@ pub fn write_ident(buf: &mut String, node: &BodyNode, indent: usize) -> fmt::Res
                     ElementAttr::CustomAttrText { name, value } => {
                         write!(
                             buf,
-                            "{name}: \"{value}\"",
+                            "\"{name}\": \"{value}\"",
                             name = name.value(),
                             value = value.value()
                         )?;
@@ -176,22 +177,32 @@ pub fn write_ident(buf: &mut String, node: &BodyNode, indent: usize) -> fmt::Res
 
                     ElementAttr::CustomAttrExpression { name, value } => {
                         let out = prettyplease::unparse_expr(value);
-                        write!(buf, "{}: {}", name.value(), out)?;
+                        write!(buf, "\"{}\": {}", name.value(), out)?;
                     }
 
                     ElementAttr::EventTokens { name, tokens } => {
                         let out = prettyplease::unparse_expr(tokens);
 
+                        dbg!(&out);
+
                         let mut lines = out.split('\n').peekable();
                         let first = lines.next().unwrap();
-                        write!(buf, "{}: {}", name, first)?;
 
-                        while let Some(line) = lines.next() {
-                            write_tabs(buf, indent + 1)?;
-                            write!(buf, "{}", line)?;
-                            // write!(buf, "{}", line)?;
-                            if lines.peek().is_none() {
-                                write!(buf, "")?;
+                        // a one-liner for whatever reason
+                        // Does not need a new line
+                        if lines.peek().is_none() {
+                            write!(buf, "{}: {}", name, first)?;
+                        } else {
+                            writeln!(buf, "{}: {}", name, first)?;
+
+                            while let Some(line) = lines.next() {
+                                write_tabs(buf, indent + 1)?;
+                                write!(buf, "{}", line)?;
+                                if lines.peek().is_none() {
+                                    write!(buf, "")?;
+                                } else {
+                                    writeln!(buf)?;
+                                }
                             }
                         }
                     }
@@ -221,7 +232,7 @@ pub fn write_ident(buf: &mut String, node: &BodyNode, indent: usize) -> fmt::Res
                 }
 
                 for child in children {
-                    write_ident(buf, child, indent + 1)?;
+                    write_ident(buf, lines, child, indent + 1)?;
                 }
 
                 if is_long_attr_list || !children.is_empty() {
@@ -260,7 +271,7 @@ pub fn write_ident(buf: &mut String, node: &BodyNode, indent: usize) -> fmt::Res
                         writeln!(buf, "{}: {},", name, out)?;
                     }
                     ContentField::Formatted(s) => {
-                        writeln!(buf, "{}: {},", name, s.value())?;
+                        writeln!(buf, "{}: \"{}\",", name, s.value())?;
                     }
                     ContentField::OnHandlerRaw(exp) => {
                         let out = prettyplease::unparse_expr(exp);
@@ -292,7 +303,7 @@ pub fn write_ident(buf: &mut String, node: &BodyNode, indent: usize) -> fmt::Res
             }
 
             for child in children {
-                write_ident(buf, child, indent + 1)?;
+                write_ident(buf, lines, child, indent + 1)?;
             }
 
             if !body.is_empty() || !children.is_empty() {
@@ -310,7 +321,52 @@ pub fn write_ident(buf: &mut String, node: &BodyNode, indent: usize) -> fmt::Res
             write_tabs(buf, indent)?;
             writeln!(buf, "\"{}\"", t.value())?;
         }
-        BodyNode::RawExpr(_) => {
+        BodyNode::RawExpr(exp) => {
+            use syn::spanned::Spanned;
+
+            let placement = exp.span();
+
+            let start = placement.start();
+            let end = placement.end();
+
+            let num_spaces_desired = (indent * 4) as isize;
+            let first = lines[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 line_id in start.line - 1..end.line {
+                let line = lines[line_id];
+
+                // trim the leading whitespace
+
+                if offset < 0 {
+                    for _ in 0..-offset {
+                        write!(buf, " ")?;
+                    }
+
+                    writeln!(buf, "{}", line)?;
+                } else {
+                    let offset = offset as usize;
+
+                    let right = &line[offset..];
+                    writeln!(buf, "{}", right)?;
+                }
+            }
+
+            // let toks = exp.to_token_stream();
+
+            // let out = prettyplease::unparse_expr(exp);
+            // let mut lines = out.split('\n').peekable();
+            // for line in lines {
+            //     write_tabs(buf, indent)?;
+            //     writeln!(buf, "{}", line)?;
+            //     // writeln!(buf)?;
+            // }
+            // write_tabs(buf, indent)?;
+            // let first = lines.next().unwrap();
+            // write!(buf, "{}", name, first)?;
+            // writeln!(buf)?;
+
             //
             // write!(buf, "{}", " ".repeat(ident))
         }

+ 108 - 1
packages/autofmt/tests/sink.rs

@@ -203,6 +203,98 @@ fn formats_component_tiny() {
     print!("{formatted}");
 }
 
+#[test]
+fn formats_exprs() {
+    let block = r#"
+    ul {
+        (0..10).map(|f| rsx!{
+            li {
+                "hi"
+            }
+        })
+    }
+"#;
+
+    let formatted = fmt_block(block).unwrap();
+
+    print!("{formatted}");
+}
+
+#[test]
+fn formats_exprs_neg_indent() {
+    let block = r#"
+            ul {
+        (0..10).map(|f| rsx!{
+            li {
+                "hi"
+            }
+        })
+    }
+"#;
+
+    let formatted = fmt_block(block).unwrap();
+
+    print!("{formatted}");
+}
+
+#[test]
+fn formats_exprs_handlers() {
+    let block = r#"
+            button {
+                class: "flex items-center pl-3 py-3 pr-2 text-gray-500 hover:bg-indigo-50 rounded",
+                onclick: move |evt| {
+                    show_user_menu.set(!show_user_menu.get());            evt.cancel_bubble();        },
+
+                onclick: move |evt|
+
+                show_user_menu.set(!show_user_menu.get()),
+                span { class: "inline-block mr-4",
+                    icons::icon_14 {}
+                }
+                span { "Settings" }
+            }
+"#;
+
+    let formatted = fmt_block(block).unwrap();
+
+    print!("{formatted}");
+}
+
+#[test]
+fn formats_complex() {
+    let block = r#"
+        li {
+            Link {
+                class: "flex items-center pl-3 py-3 pr-4 {active_class} rounded",
+                to: "{to}",
+                span { class: "inline-block mr-3",
+                    icons::icon_0 {}
+                }
+                span { "{name}" }
+                children.is_some().then(|| rsx!{
+                    span {
+                        class: "inline-block ml-auto hover:bg-gray-500",
+                        onclick: move |evt| {
+                            // open.set(!open.get());
+                            evt.cancel_bubble();
+                        },
+                        icons::icon_8 {}
+                    }
+                })
+            }
+            div {
+                class: "px-4",
+                is_current.then(|| rsx!{ children })
+                // open.then(|| rsx!{ children })
+            }
+        }
+"#;
+
+    let formatted = fmt_block(block).unwrap();
+
+    print!("{formatted}");
+}
+
 #[test]
 fn formats_document() {
     let block = r#"
@@ -321,7 +413,6 @@ fn NavItem<'a>(cx: Scope, to: &'static str, children: Element<'a>, icon: Shape)
         }
     }
 }
-
 #[inline_props]
 fn NavItem<'a>(cx: Scope, to: &'static str, children: Element<'a>, icon: Shape) -> Element {
     const ICON_SIZE: u32 = 36;
@@ -362,3 +453,19 @@ fn NavItem<'a>(cx: Scope, to: &'static str, children: Element<'a>, icon: Shape)
         &format!("{{ {}    }}", &block.formatted),
     );
 }
+
+#[test]
+fn empty_blocks() {
+    let mut src = r###"
+pub fn Alert(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div { }
+    })
+}
+"###
+    .to_string();
+
+    let formatted = get_format_blocks(&src);
+
+    dbg!(&formatted);
+}