wip: make element printer more comprehensive
This commit is contained in:
1 parent
398cbc6534
commit
79b475798d
3 files changed
+228
-115
No files matched your search
@@ -84,10 +84,51 @@ fn format_block_basic() {
|
|||||||
h1 { "thing" }
|
h1 { "thing" }
|
||||||
h1 { "thing" }
|
h1 { "thing" }
|
||||||
h1 { "thing" }
|
h1 { "thing" }
|
||||||
|
h1 { "thing" "is whack" "but you're wacker" }
|
||||||
|
h1 { "thing" div {"special cases?" } }
|
||||||
|
div {
|
||||||
|
a: 123,
|
||||||
|
b: 456,
|
||||||
|
c: 789,
|
||||||
|
d: "hello",
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
a: 123,
|
||||||
|
b: 456,
|
||||||
|
c: 789,
|
||||||
|
d: "hello",
|
||||||
|
p {}
|
||||||
|
c {}
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 { class: "asdasd", "asdasd" }
|
||||||
|
h3 { class: "mx-large bg-gray-900 tall-md-400", div {
|
||||||
|
"classy"
|
||||||
|
}}
|
||||||
|
|
||||||
|
|
||||||
|
// Some comments explaining my genius
|
||||||
|
div {
|
||||||
|
"comment compression"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some comments explaining my genius
|
||||||
|
div {
|
||||||
|
// Some comments explaining my genius
|
||||||
|
a: 123,
|
||||||
|
|
||||||
|
// comment compression
|
||||||
|
b: 456,
|
||||||
|
|
||||||
|
// comments on attributes
|
||||||
|
c: 789,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
// div { class: "asdasd", p { "hello!" } }
|
||||||
|
|
||||||
let edits = get_format_blocks(block);
|
let edits = get_format_blocks(block);
|
||||||
|
|
||||||
println!("{}", edits[0].formatted);
|
println!("{}", edits[0].formatted);
|
||||||
|
|||||||
+186
-114
@@ -2,6 +2,14 @@ use crate::{util::*, write_ident};
|
|||||||
use dioxus_rsx::*;
|
use dioxus_rsx::*;
|
||||||
use std::{fmt, fmt::Write};
|
use std::{fmt, fmt::Write};
|
||||||
|
|
||||||
|
enum ShortOptimization {
|
||||||
|
// Special because we want to print the closing bracket immediately
|
||||||
|
Empty,
|
||||||
|
Oneliner,
|
||||||
|
PropsOnTop,
|
||||||
|
NoOpt,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write_element(
|
pub fn write_element(
|
||||||
Element {
|
Element {
|
||||||
name,
|
name,
|
||||||
@@ -16,145 +24,209 @@ pub fn write_element(
|
|||||||
indent: usize,
|
indent: usize,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
/*
|
/*
|
||||||
Write the tag
|
1. Write the tag
|
||||||
Write the key
|
2. Write the key
|
||||||
Write the attributes
|
3. Write the attributes
|
||||||
Write the children
|
4. Write the children
|
||||||
*/
|
*/
|
||||||
|
|
||||||
write!(buf, "{name} {{")?;
|
write!(buf, "{name} {{")?;
|
||||||
|
|
||||||
let total_attr_len = extract_attr_len(attributes);
|
// decide if we have any special optimizations
|
||||||
let is_long_attr_list = total_attr_len > 80;
|
// Default with none, opt the cases in one-by-one
|
||||||
|
let mut opt_level = ShortOptimization::NoOpt;
|
||||||
|
|
||||||
if let Some(key) = key.as_ref().map(|f| f.value()) {
|
// check if we have a lot of attributes
|
||||||
if is_long_attr_list {
|
let is_short_attr_list = is_short_attrs(attributes);
|
||||||
writeln!(buf)?;
|
let is_small_children = is_short_children(children);
|
||||||
write_tabs(buf, indent + 1)?;
|
|
||||||
} else {
|
// if we have few attributes and a lot of children, place the attrs on top
|
||||||
|
if is_short_attr_list && !is_small_children {
|
||||||
|
opt_level = ShortOptimization::PropsOnTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we have few children and few attributes, make it a one-liner
|
||||||
|
if is_short_attr_list && is_small_children {
|
||||||
|
opt_level = ShortOptimization::Oneliner;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's nothing at all, empty optimization
|
||||||
|
if attributes.is_empty() && children.is_empty() && key.is_none() {
|
||||||
|
opt_level = ShortOptimization::Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
match opt_level {
|
||||||
|
ShortOptimization::Empty => write!(buf, "}}")?,
|
||||||
|
ShortOptimization::Oneliner => {
|
||||||
write!(buf, " ")?;
|
write!(buf, " ")?;
|
||||||
}
|
write_attributes(buf, attributes, true, indent)?;
|
||||||
write!(buf, "key: \"{key}\"")?;
|
|
||||||
|
|
||||||
if !attributes.is_empty() {
|
if !children.is_empty() && !attributes.is_empty() {
|
||||||
write!(buf, ",")?;
|
write!(buf, ", ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the children
|
||||||
|
for child in children {
|
||||||
|
write_ident(buf, lines, child, indent + 1)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(buf, " }}")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortOptimization::PropsOnTop => {
|
||||||
|
write!(buf, " ")?;
|
||||||
|
write_attributes(buf, attributes, true, indent)?;
|
||||||
|
|
||||||
|
if !children.is_empty() && !attributes.is_empty() {
|
||||||
|
write!(buf, ",")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the children
|
||||||
|
for child in children {
|
||||||
|
writeln!(buf)?;
|
||||||
|
write_tabs(buf, indent + 1)?;
|
||||||
|
write_ident(buf, lines, child, indent + 1)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(buf)?;
|
||||||
|
write_tabs(buf, indent)?;
|
||||||
|
write!(buf, "}}")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortOptimization::NoOpt => {
|
||||||
|
// write the key
|
||||||
|
|
||||||
|
// write the attributes
|
||||||
|
write_attributes(buf, attributes, false, indent)?;
|
||||||
|
|
||||||
|
// write the children
|
||||||
|
for child in children {
|
||||||
|
writeln!(buf)?;
|
||||||
|
write_tabs(buf, indent + 1)?;
|
||||||
|
write_ident(buf, lines, child, indent + 1)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(buf)?;
|
||||||
|
write_tabs(buf, indent)?;
|
||||||
|
write!(buf, "}}")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_short_attrs(attrs: &[ElementAttrNamed]) -> bool {
|
||||||
|
let total_attr_len = extract_attr_len(attrs);
|
||||||
|
total_attr_len < 80
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the children are short enough to be on the same line
|
||||||
|
// We don't have the notion of current line depth - each line tries to be < 80 total
|
||||||
|
fn is_short_children(children: &[BodyNode]) -> bool {
|
||||||
|
if children.is_empty() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if children.len() == 1 {
|
||||||
|
if let BodyNode::Text(ref text) = &children[0] {
|
||||||
|
return text.value().len() < 80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_key() {
|
||||||
|
// if let Some(key) = key.as_ref().map(|f| f.value()) {
|
||||||
|
// if is_long_attr_list {
|
||||||
|
// writeln!(buf)?;
|
||||||
|
// write_tabs(buf, indent + 1)?;
|
||||||
|
// } else {
|
||||||
|
// write!(buf, " ")?;
|
||||||
|
// }
|
||||||
|
// write!(buf, "key: \"{key}\"")?;
|
||||||
|
|
||||||
|
// if !attributes.is_empty() {
|
||||||
|
// write!(buf, ",")?;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_attributes(
|
||||||
|
buf: &mut String,
|
||||||
|
attributes: &[ElementAttrNamed],
|
||||||
|
sameline: bool,
|
||||||
|
indent: usize,
|
||||||
|
) -> fmt::Result {
|
||||||
let mut attr_iter = attributes.iter().peekable();
|
let mut attr_iter = attributes.iter().peekable();
|
||||||
|
|
||||||
while let Some(attr) = attr_iter.next() {
|
while let Some(attr) = attr_iter.next() {
|
||||||
if is_long_attr_list {
|
write_attribute(buf, attr, indent)?;
|
||||||
writeln!(buf)?;
|
|
||||||
write_tabs(buf, indent + 1)?;
|
if attr_iter.peek().is_some() {
|
||||||
} else {
|
write!(buf, ",")?;
|
||||||
write!(buf, " ")?;
|
|
||||||
|
if sameline {
|
||||||
|
write!(buf, " ")?;
|
||||||
|
} else {
|
||||||
|
writeln!(buf)?;
|
||||||
|
write_tabs(buf, indent + 1)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_attribute(buf: &mut String, attr: &ElementAttrNamed, indent: usize) -> fmt::Result {
|
||||||
|
match &attr.attr {
|
||||||
|
ElementAttr::AttrText { name, value } => {
|
||||||
|
write!(buf, "{name}: \"{value}\"", value = value.value())?;
|
||||||
|
}
|
||||||
|
ElementAttr::AttrExpression { name, value } => {
|
||||||
|
let out = prettyplease::unparse_expr(value);
|
||||||
|
write!(buf, "{}: {}", name, out)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match &attr.attr {
|
ElementAttr::CustomAttrText { name, value } => {
|
||||||
ElementAttr::AttrText { name, value } => {
|
write!(
|
||||||
write!(buf, "{name}: \"{value}\"", value = value.value())?;
|
buf,
|
||||||
}
|
"\"{name}\": \"{value}\"",
|
||||||
ElementAttr::AttrExpression { name, value } => {
|
name = name.value(),
|
||||||
let out = prettyplease::unparse_expr(value);
|
value = value.value()
|
||||||
write!(buf, "{}: {}", name, out)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementAttr::CustomAttrText { name, value } => {
|
ElementAttr::CustomAttrExpression { name, value } => {
|
||||||
write!(
|
let out = prettyplease::unparse_expr(value);
|
||||||
buf,
|
write!(buf, "\"{}\": {}", name.value(), out)?;
|
||||||
"\"{name}\": \"{value}\"",
|
}
|
||||||
name = name.value(),
|
|
||||||
value = value.value()
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
ElementAttr::CustomAttrExpression { name, value } => {
|
ElementAttr::EventTokens { name, tokens } => {
|
||||||
let out = prettyplease::unparse_expr(value);
|
let out = prettyplease::unparse_expr(tokens);
|
||||||
write!(buf, "\"{}\": {}", name.value(), out)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
ElementAttr::EventTokens { name, tokens } => {
|
let mut lines = out.split('\n').peekable();
|
||||||
let out = prettyplease::unparse_expr(tokens);
|
let first = lines.next().unwrap();
|
||||||
|
|
||||||
let mut lines = out.split('\n').peekable();
|
// a one-liner for whatever reason
|
||||||
let first = lines.next().unwrap();
|
// Does not need a new line
|
||||||
|
if lines.peek().is_none() {
|
||||||
|
write!(buf, "{}: {}", name, first)?;
|
||||||
|
} else {
|
||||||
|
writeln!(buf, "{}: {}", name, first)?;
|
||||||
|
|
||||||
// a one-liner for whatever reason
|
while let Some(line) = lines.next() {
|
||||||
// Does not need a new line
|
write_tabs(buf, indent + 1)?;
|
||||||
if lines.peek().is_none() {
|
write!(buf, "{}", line)?;
|
||||||
write!(buf, "{}: {}", name, first)?;
|
if lines.peek().is_none() {
|
||||||
} else {
|
write!(buf, "")?;
|
||||||
writeln!(buf, "{}: {}", name, first)?;
|
} else {
|
||||||
|
writeln!(buf)?;
|
||||||
while let Some(line) = lines.next() {
|
|
||||||
write_tabs(buf, indent + 1)?;
|
|
||||||
write!(buf, "{}", line)?;
|
|
||||||
if lines.peek().is_none() {
|
|
||||||
write!(buf, "")?;
|
|
||||||
} else {
|
|
||||||
writeln!(buf)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if attr_iter.peek().is_some() || !children.is_empty() {
|
|
||||||
write!(buf, ",")?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the attr list is short, then we want to optimize for some cases
|
|
||||||
let is_child_optimized = match children.as_slice() {
|
|
||||||
// No children, just close the tag
|
|
||||||
[] => true,
|
|
||||||
|
|
||||||
// Only a text node, just write it out
|
|
||||||
[BodyNode::Text(_)] => true,
|
|
||||||
|
|
||||||
// If these have zero children and attributes, then we can just write out the tag
|
|
||||||
[BodyNode::Component(ref comp)] => comp.body.is_empty() && comp.children.is_empty(),
|
|
||||||
[BodyNode::Element(ref el)] => el.attributes.is_empty() && el.children.is_empty(),
|
|
||||||
|
|
||||||
// Nothing else is optimized
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if !is_long_attr_list && is_child_optimized {
|
|
||||||
write_ident(buf, lines, &children[0], indent)?;
|
|
||||||
} else {
|
|
||||||
for child in children {
|
|
||||||
writeln!(buf)?;
|
|
||||||
write_ident(buf, lines, child, indent + 1)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// let text_val = text.value();
|
|
||||||
// if total_attr_len + text_val.len() > 80 {
|
|
||||||
// writeln!(buf)?;
|
|
||||||
// write_tabs(buf, indent + 1)?;
|
|
||||||
// writeln!(buf, "\"{}\"", text.value())?;
|
|
||||||
// write_tabs(buf, indent)?;
|
|
||||||
// } else {
|
|
||||||
// write!(buf, " \"{}\" ", text.value())?;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if is_long_attr_list {
|
|
||||||
// writeln!(buf)?;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for child in children {
|
|
||||||
// write_ident(buf, lines, child, indent + 1)?;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if is_long_attr_list {
|
|
||||||
// write_tabs(buf, indent)?;
|
|
||||||
// } else {
|
|
||||||
// write!(buf, " ")?;
|
|
||||||
// }
|
|
||||||
|
|
||||||
writeln!(buf, "}}")?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@ pub fn extract_attr_len(attributes: &[ElementAttrNamed]) -> usize {
|
|||||||
ElementAttr::CustomAttrExpression { name, value } => 10,
|
ElementAttr::CustomAttrExpression { name, value } => 10,
|
||||||
ElementAttr::EventTokens { name, tokens } => 1000000,
|
ElementAttr::EventTokens { name, tokens } => 1000000,
|
||||||
})
|
})
|
||||||
.sum::<usize>()
|
.sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_tabs(f: &mut dyn Write, num: usize) -> std::fmt::Result {
|
pub fn write_tabs(f: &mut dyn Write, num: usize) -> std::fmt::Result {
|
||||||
|
|||||||
Reference in new issue
Block a user