Merge pull request #570 from DioxusLabs/jk/autofmt-fixues
chore: fixes to autoformat to prevent double rendering of expr line
This commit is contained in:
17 files changed
+336
-47
No files matched your search
@@ -15,3 +15,74 @@ Sorted roughly in order of what's possible
|
||||
- [ ] Format regular exprs
|
||||
- [ ] Fix prettyplease around chaining
|
||||
- [ ] Don't eat comments in prettyplease
|
||||
|
||||
|
||||
# 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
|
||||
- ‹›
|
||||
@@ -125,16 +125,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(())
|
||||
|
||||
@@ -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 {
|
||||
@@ -83,12 +84,15 @@ 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, ", ")?;
|
||||
}
|
||||
|
||||
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, " ")?;
|
||||
@@ -100,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, ",")?;
|
||||
}
|
||||
|
||||
@@ -113,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, ",")?;
|
||||
}
|
||||
|
||||
@@ -286,33 +290,66 @@ 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)] => {
|
||||
[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] {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.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!(),
|
||||
}
|
||||
}
|
||||
|
||||
Some(total_count)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_expr_length(expr: &Expr) -> Option<usize> {
|
||||
let span = expr.span();
|
||||
let (start, end) = (span.start(), span.end());
|
||||
if start.line == end.line {
|
||||
Some(end.column - start.column)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -16,16 +16,63 @@ 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;
|
||||
// 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;
|
||||
// }
|
||||
|
||||
let offset = num_spaces_real - num_spaces_desired;
|
||||
// offset += 1;
|
||||
// }
|
||||
// let had_comments = !queued_comments.is_empty();
|
||||
// for comment in queued_comments.into_iter().rev() {
|
||||
// writeln!(self.buf, "{}", comment)?;
|
||||
// }
|
||||
|
||||
for line in &self.src[start.line - 1..end.line] {
|
||||
// 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(());
|
||||
}
|
||||
|
||||
// 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,
|
||||
"{}",
|
||||
&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 +86,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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -23,3 +23,10 @@ twoway! ("complex" => complex);
|
||||
twoway! ("tiny" => tiny);
|
||||
|
||||
twoway! ("tinynoopt" => tinynoopt);
|
||||
|
||||
twoway! ("long" => long);
|
||||
|
||||
twoway! ("key" => key);
|
||||
|
||||
// Disabled because we can't handle comments on exprs yet
|
||||
twoway! ("multirsx" => multirsx);
|
||||
@@ -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 }
|
||||
}
|
||||
@@ -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}" }
|
||||
}
|
||||
}
|
||||
@@ -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 }
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
rsx! {
|
||||
|
||||
// hi
|
||||
div {}
|
||||
|
||||
// hi
|
||||
div { abcd, ball, s }
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
div { abcd, ball, s }
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
div {
|
||||
abcd,
|
||||
ball,
|
||||
s,
|
||||
|
||||
//
|
||||
"asdasd"
|
||||
}
|
||||
}
|
||||
@@ -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 {} }
|
||||
|
||||
@@ -14,3 +14,5 @@ macro_rules! twoway {
|
||||
twoway!("comments" => comments);
|
||||
|
||||
twoway!("multi" => multi);
|
||||
|
||||
twoway!("multiexpr" => multiexpr);
|
||||
@@ -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 }
|
||||
})
|
||||
@@ -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 }
|
||||
})
|
||||
@@ -0,0 +1 @@
|
||||
# The actual RSX language implemented using syn parsers.
|
||||
@@ -34,7 +34,7 @@ use syn::{
|
||||
};
|
||||
|
||||
/// Fundametnally, every CallBody is a template
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct CallBody {
|
||||
pub roots: Vec<BodyNode>,
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// use crate::{raw_expr::RawExprNode, text::TextNode};
|
||||
|
||||
use super::*;
|
||||
|
||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
@@ -29,7 +31,7 @@ pub enum BodyNode {
|
||||
|
||||
impl BodyNode {
|
||||
pub fn is_litstr(&self) -> bool {
|
||||
matches!(self, BodyNode::Text(_))
|
||||
matches!(self, BodyNode::Text { .. })
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
|
||||
Reference in new issue
Block a user