Răsfoiți Sursa

feat: ensure parsing works with right indicies

Jonathan Kelley 3 ani în urmă
părinte
comite
4fa909e864
4 a modificat fișierele cu 128 adăugiri și 1 ștergeri
  1. 1 0
      Cargo.toml
  2. 2 0
      packages/autofmt/Cargo.toml
  3. 87 1
      packages/autofmt/src/lib.rs
  4. 38 0
      packages/autofmt/tests/sink.rs

+ 1 - 0
Cargo.toml

@@ -60,6 +60,7 @@ members = [
     "packages/tui",
     "packages/liveview",
     "packages/rsx",
+    "packages/autofmt",
 ]
 
 [dev-dependencies]

+ 2 - 0
packages/autofmt/Cargo.toml

@@ -10,3 +10,5 @@ proc-macro2 = { version = "1.0.6" }
 quote = "1.0"
 syn = { version = "1.0.11", features = ["full", "extra-traits"] }
 dioxus-rsx = { path = "../rsx" }
+triple_accel = "0.4.0"
+serde = { version = "1.0.136", features = ["derive"] }

+ 87 - 1
packages/autofmt/src/lib.rs

@@ -1,9 +1,74 @@
 //! pretty printer for rsx!
 use dioxus_rsx::*;
+use proc_macro2::TokenStream as TokenStream2;
 use quote::ToTokens;
-use std::fmt::{self, Write};
+use std::{
+    fmt::{self, Write},
+    ptr::NonNull,
+};
+use syn::{
+    buffer::TokenBuffer,
+    parse::{ParseBuffer, ParseStream},
+};
+use triple_accel::{levenshtein_search, Match};
+
 mod prettyplease;
 
+#[derive(serde::Deserialize, serde::Serialize, Clone, Debug, PartialEq, Hash)]
+pub struct ForamttedBlock {
+    pub formatted: String,
+    pub start: usize,
+    pub end: usize,
+}
+
+/*
+TODO: nested rsx! calls
+
+*/
+pub fn formmat_document(contents: &str) -> Vec<ForamttedBlock> {
+    let mut matches = levenshtein_search(b"rsx! {", contents.as_bytes()).peekable();
+
+    let mut cur_match: Option<Match> = None;
+
+    let mut formatted_blocks = Vec::new();
+
+    while let Some(item) = matches.next() {
+        let Match { start, end, k } = item;
+
+        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) {
+            let sub_string = &contents[end..bracket_end + end - 1];
+
+            if let Some(new) = fmt_block(sub_string) {
+                if !new.is_empty() {
+                    formatted_blocks.push(ForamttedBlock {
+                        formatted: new,
+                        start: end,
+                        end: end + bracket_end - 1,
+                    });
+                }
+            }
+        }
+    }
+
+    formatted_blocks
+}
+
 pub fn fmt_block(block: &str) -> Option<String> {
     let parsed: CallBody = syn::parse_str(block).ok()?;
 
@@ -175,3 +240,24 @@ pub fn write_tabs(f: &mut dyn Write, num: usize) -> std::fmt::Result {
     }
     Ok(())
 }
+
+fn find_bracket_end(contents: &str) -> Option<usize> {
+    let mut depth = 0;
+    let mut i = 0;
+
+    for c in contents.chars() {
+        if c == '{' {
+            depth += 1;
+        } else if c == '}' {
+            depth -= 1;
+        }
+
+        if depth == 0 {
+            return Some(i);
+        }
+
+        i += 1;
+    }
+
+    None
+}

+ 38 - 0
packages/autofmt/tests/sink.rs

@@ -93,3 +93,41 @@ fn formats_component_man_props() {
 
     print!("{formatted}");
 }
+
+#[test]
+fn formats_document() {
+    let block = r#"
+rsx!{
+    Component {
+        adsasd: "asd", // this is a comment
+        onclick: move |_| {
+            let blah = 120;
+        },
+    }
+}
+
+
+"#;
+
+    let formatted = formmat_document(block);
+
+    print!("{formatted:?}");
+}
+
+#[test]
+fn formats_valid_rust_src() {
+    let src = r#"
+//
+rsx! {
+    div {}
+    div {
+        h3 {"asd"
+        }
+    }
+}
+"#;
+
+    let formatted = formmat_document(src);
+
+    println!("{formatted:?}");
+}