Merge pull request #726 from DioxusLabs/jk/fix-comments-on-exprs
fix: comments being eaten in autofmt
This commit is contained in:
10 files changed
+404
-332
No files matched your search
+14
-175
@@ -1,33 +1,18 @@
|
|||||||
use std::{
|
//! The output buffer that supports some helpful methods
|
||||||
collections::{HashMap, VecDeque},
|
//! These are separate from the input so we can lend references between the two
|
||||||
fmt::{Result, Write},
|
//!
|
||||||
};
|
//!
|
||||||
|
//!
|
||||||
|
|
||||||
use dioxus_rsx::{BodyNode, ElementAttr, ElementAttrNamed, IfmtInput};
|
use std::fmt::{Result, Write};
|
||||||
use proc_macro2::{LineColumn, Span};
|
|
||||||
use syn::{spanned::Spanned, Expr};
|
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
use dioxus_rsx::IfmtInput;
|
||||||
|
|
||||||
|
/// The output buffer that tracks indent and string
|
||||||
|
#[derive(Debug, Default)]
|
||||||
pub struct Buffer {
|
pub struct Buffer {
|
||||||
pub src: Vec<String>,
|
|
||||||
pub cached_formats: HashMap<Location, String>,
|
|
||||||
pub buf: String,
|
pub buf: String,
|
||||||
pub indent: usize,
|
pub indent: usize,
|
||||||
pub comments: VecDeque<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
|
|
||||||
pub struct Location {
|
|
||||||
pub line: usize,
|
|
||||||
pub col: usize,
|
|
||||||
}
|
|
||||||
impl Location {
|
|
||||||
pub fn new(start: LineColumn) -> Self {
|
|
||||||
Self {
|
|
||||||
line: start.line,
|
|
||||||
col: start.column,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Buffer {
|
impl Buffer {
|
||||||
@@ -62,160 +47,14 @@ impl Buffer {
|
|||||||
writeln!(self.buf)
|
writeln!(self.buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expects to be written directly into place
|
|
||||||
pub fn write_ident(&mut self, node: &BodyNode) -> Result {
|
|
||||||
match node {
|
|
||||||
BodyNode::Element(el) => self.write_element(el),
|
|
||||||
BodyNode::Component(component) => self.write_component(component),
|
|
||||||
BodyNode::Text(text) => self.write_text(text),
|
|
||||||
BodyNode::RawExpr(exp) => self.write_raw_expr(exp),
|
|
||||||
_ => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_text(&mut self, text: &IfmtInput) -> Result {
|
pub fn write_text(&mut self, text: &IfmtInput) -> Result {
|
||||||
write!(self.buf, "\"{}\"", text.source.as_ref().unwrap().value())
|
write!(self.buf, "\"{}\"", text.source.as_ref().unwrap().value())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn consume(self) -> Option<String> {
|
|
||||||
Some(self.buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_comments(&mut self, child: Span) -> Result {
|
|
||||||
// collect all comments upwards
|
|
||||||
let start = child.start();
|
|
||||||
let line_start = start.line - 1;
|
|
||||||
|
|
||||||
for (id, line) in self.src[..line_start].iter().enumerate().rev() {
|
|
||||||
if line.trim().starts_with("//") || line.is_empty() {
|
|
||||||
if id != 0 {
|
|
||||||
self.comments.push_front(id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut last_was_empty = false;
|
|
||||||
while let Some(comment_line) = self.comments.pop_front() {
|
|
||||||
let line = &self.src[comment_line];
|
|
||||||
if line.is_empty() {
|
|
||||||
if !last_was_empty {
|
|
||||||
self.new_line()?;
|
|
||||||
}
|
|
||||||
last_was_empty = true;
|
|
||||||
} else {
|
|
||||||
last_was_empty = false;
|
|
||||||
self.tabbed_line()?;
|
|
||||||
write!(self.buf, "{}", self.src[comment_line].trim())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push out the indent level and write each component, line by line
|
|
||||||
pub fn write_body_indented(&mut self, children: &[BodyNode]) -> Result {
|
|
||||||
self.indent += 1;
|
|
||||||
|
|
||||||
self.write_body_no_indent(children)?;
|
|
||||||
|
|
||||||
self.indent -= 1;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_body_no_indent(&mut self, children: &[BodyNode]) -> Result {
|
|
||||||
let last_child = children.len();
|
|
||||||
|
|
||||||
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(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn is_short_attrs(&mut self, attributes: &[ElementAttrNamed]) -> usize {
|
|
||||||
let mut total = 0;
|
|
||||||
|
|
||||||
for attr in attributes {
|
|
||||||
if self.current_span_is_primary(attr.attr.start()) {
|
|
||||||
'line: for line in self.src[..attr.attr.start().start().line - 1].iter().rev() {
|
|
||||||
match (line.trim().starts_with("//"), line.is_empty()) {
|
|
||||||
(true, _) => return 100000,
|
|
||||||
(_, true) => continue 'line,
|
|
||||||
_ => break 'line,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
total += match &attr.attr {
|
|
||||||
ElementAttr::AttrText { value, name } => {
|
|
||||||
value.source.as_ref().unwrap().value().len() + name.span().line_length() + 3
|
|
||||||
}
|
|
||||||
ElementAttr::AttrExpression { name, value } => {
|
|
||||||
value.span().line_length() + name.span().line_length() + 3
|
|
||||||
}
|
|
||||||
ElementAttr::CustomAttrText { value, name } => {
|
|
||||||
value.source.as_ref().unwrap().value().len() + name.value().len() + 3
|
|
||||||
}
|
|
||||||
ElementAttr::CustomAttrExpression { name, value } => {
|
|
||||||
name.value().len() + value.span().line_length() + 3
|
|
||||||
}
|
|
||||||
ElementAttr::EventTokens { tokens, name } => {
|
|
||||||
let location = Location::new(tokens.span().start());
|
|
||||||
|
|
||||||
let len = if let std::collections::hash_map::Entry::Vacant(e) =
|
|
||||||
self.cached_formats.entry(location)
|
|
||||||
{
|
|
||||||
let formatted = prettyplease::unparse_expr(tokens);
|
|
||||||
let len = if formatted.contains('\n') {
|
|
||||||
10000
|
|
||||||
} else {
|
|
||||||
formatted.len()
|
|
||||||
};
|
|
||||||
e.insert(formatted);
|
|
||||||
len
|
|
||||||
} else {
|
|
||||||
self.cached_formats[&location].len()
|
|
||||||
};
|
|
||||||
|
|
||||||
len + name.span().line_length() + 3
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
total
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn retrieve_formatted_expr(&mut self, expr: &Expr) -> &str {
|
|
||||||
self.cached_formats
|
|
||||||
.entry(Location::new(expr.span().start()))
|
|
||||||
.or_insert_with(|| prettyplease::unparse_expr(expr))
|
|
||||||
.as_str()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trait SpanLength {
|
impl std::fmt::Write for Buffer {
|
||||||
fn line_length(&self) -> usize;
|
fn write_str(&mut self, s: &str) -> std::fmt::Result {
|
||||||
}
|
self.buf.push_str(s);
|
||||||
impl SpanLength for Span {
|
Ok(())
|
||||||
fn line_length(&self) -> usize {
|
|
||||||
self.end().line - self.start().line
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{buffer::Location, Buffer};
|
use crate::{writer::Location, Writer};
|
||||||
use dioxus_rsx::*;
|
use dioxus_rsx::*;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use std::fmt::{Result, Write};
|
use std::fmt::{Result, Write};
|
||||||
@@ -19,7 +19,7 @@ enum ShortOptimization {
|
|||||||
NoOpt,
|
NoOpt,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Buffer {
|
impl Writer {
|
||||||
pub fn write_component(
|
pub fn write_component(
|
||||||
&mut self,
|
&mut self,
|
||||||
Component {
|
Component {
|
||||||
@@ -28,6 +28,7 @@ impl Buffer {
|
|||||||
children,
|
children,
|
||||||
manual_props,
|
manual_props,
|
||||||
prop_gen_args,
|
prop_gen_args,
|
||||||
|
..
|
||||||
}: &Component,
|
}: &Component,
|
||||||
) -> Result {
|
) -> Result {
|
||||||
self.write_component_name(name, prop_gen_args)?;
|
self.write_component_name(name, prop_gen_args)?;
|
||||||
@@ -82,46 +83,46 @@ impl Buffer {
|
|||||||
match opt_level {
|
match opt_level {
|
||||||
ShortOptimization::Empty => {}
|
ShortOptimization::Empty => {}
|
||||||
ShortOptimization::Oneliner => {
|
ShortOptimization::Oneliner => {
|
||||||
write!(self.buf, " ")?;
|
write!(self.out, " ")?;
|
||||||
|
|
||||||
self.write_component_fields(fields, manual_props, true)?;
|
self.write_component_fields(fields, manual_props, true)?;
|
||||||
|
|
||||||
if !children.is_empty() && !fields.is_empty() {
|
if !children.is_empty() && !fields.is_empty() {
|
||||||
write!(self.buf, ", ")?;
|
write!(self.out, ", ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for child in children {
|
for child in children {
|
||||||
self.write_ident(child)?;
|
self.write_ident(child)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(self.buf, " ")?;
|
write!(self.out, " ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShortOptimization::PropsOnTop => {
|
ShortOptimization::PropsOnTop => {
|
||||||
write!(self.buf, " ")?;
|
write!(self.out, " ")?;
|
||||||
self.write_component_fields(fields, manual_props, true)?;
|
self.write_component_fields(fields, manual_props, true)?;
|
||||||
|
|
||||||
if !children.is_empty() && !fields.is_empty() {
|
if !children.is_empty() && !fields.is_empty() {
|
||||||
write!(self.buf, ",")?;
|
write!(self.out, ",")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.write_body_indented(children)?;
|
self.write_body_indented(children)?;
|
||||||
self.tabbed_line()?;
|
self.out.tabbed_line()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShortOptimization::NoOpt => {
|
ShortOptimization::NoOpt => {
|
||||||
self.write_component_fields(fields, manual_props, false)?;
|
self.write_component_fields(fields, manual_props, false)?;
|
||||||
|
|
||||||
if !children.is_empty() && !fields.is_empty() {
|
if !children.is_empty() && !fields.is_empty() {
|
||||||
write!(self.buf, ",")?;
|
write!(self.out, ",")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.write_body_indented(children)?;
|
self.write_body_indented(children)?;
|
||||||
self.tabbed_line()?;
|
self.out.tabbed_line()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(self.buf, "}}")?;
|
write!(self.out, "}}")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,16 +134,16 @@ impl Buffer {
|
|||||||
let mut name = name.to_token_stream().to_string();
|
let mut name = name.to_token_stream().to_string();
|
||||||
name.retain(|c| !c.is_whitespace());
|
name.retain(|c| !c.is_whitespace());
|
||||||
|
|
||||||
write!(self.buf, "{name}")?;
|
write!(self.out, "{name}")?;
|
||||||
|
|
||||||
if let Some(generics) = generics {
|
if let Some(generics) = generics {
|
||||||
let mut written = generics.to_token_stream().to_string();
|
let mut written = generics.to_token_stream().to_string();
|
||||||
written.retain(|c| !c.is_whitespace());
|
written.retain(|c| !c.is_whitespace());
|
||||||
|
|
||||||
write!(self.buf, "{}", written)?;
|
write!(self.out, "{}", written)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(self.buf, " {{")?;
|
write!(self.out, " {{")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -157,18 +158,18 @@ impl Buffer {
|
|||||||
|
|
||||||
while let Some(field) = field_iter.next() {
|
while let Some(field) = field_iter.next() {
|
||||||
if !sameline {
|
if !sameline {
|
||||||
self.indented_tabbed_line()?;
|
self.out.indented_tabbed_line()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = &field.name;
|
let name = &field.name;
|
||||||
match &field.content {
|
match &field.content {
|
||||||
ContentField::ManExpr(exp) => {
|
ContentField::ManExpr(exp) => {
|
||||||
let out = prettyplease::unparse_expr(exp);
|
let out = prettyplease::unparse_expr(exp);
|
||||||
write!(self.buf, "{}: {}", name, out)?;
|
write!(self.out, "{}: {}", name, out)?;
|
||||||
}
|
}
|
||||||
ContentField::Formatted(s) => {
|
ContentField::Formatted(s) => {
|
||||||
write!(
|
write!(
|
||||||
self.buf,
|
self.out,
|
||||||
"{}: \"{}\"",
|
"{}: \"{}\"",
|
||||||
name,
|
name,
|
||||||
s.source.as_ref().unwrap().value()
|
s.source.as_ref().unwrap().value()
|
||||||
@@ -178,27 +179,27 @@ impl Buffer {
|
|||||||
let out = prettyplease::unparse_expr(exp);
|
let out = prettyplease::unparse_expr(exp);
|
||||||
let mut lines = out.split('\n').peekable();
|
let mut lines = out.split('\n').peekable();
|
||||||
let first = lines.next().unwrap();
|
let first = lines.next().unwrap();
|
||||||
write!(self.buf, "{}: {}", name, first)?;
|
write!(self.out, "{}: {}", name, first)?;
|
||||||
for line in lines {
|
for line in lines {
|
||||||
self.new_line()?;
|
self.out.new_line()?;
|
||||||
self.indented_tab()?;
|
self.out.indented_tab()?;
|
||||||
write!(self.buf, "{}", line)?;
|
write!(self.out, "{}", line)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if field_iter.peek().is_some() || manual_props.is_some() {
|
if field_iter.peek().is_some() || manual_props.is_some() {
|
||||||
write!(self.buf, ",")?;
|
write!(self.out, ",")?;
|
||||||
|
|
||||||
if sameline {
|
if sameline {
|
||||||
write!(self.buf, " ")?;
|
write!(self.out, " ")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(exp) = manual_props {
|
if let Some(exp) = manual_props {
|
||||||
if !sameline {
|
if !sameline {
|
||||||
self.indented_tabbed_line()?;
|
self.out.indented_tabbed_line()?;
|
||||||
}
|
}
|
||||||
self.write_manual_props(exp)?;
|
self.write_manual_props(exp)?;
|
||||||
}
|
}
|
||||||
@@ -258,10 +259,10 @@ impl Buffer {
|
|||||||
|
|
||||||
let first_line = lines.next().unwrap();
|
let first_line = lines.next().unwrap();
|
||||||
|
|
||||||
write!(self.buf, "..{first_line}")?;
|
write!(self.out, "..{first_line}")?;
|
||||||
for line in lines {
|
for line in lines {
|
||||||
self.indented_tabbed_line()?;
|
self.out.indented_tabbed_line()?;
|
||||||
write!(self.buf, "{line}")?;
|
write!(self.out, "{line}")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
+101
-45
@@ -1,35 +1,56 @@
|
|||||||
use crate::Buffer;
|
use crate::Writer;
|
||||||
use dioxus_rsx::*;
|
use dioxus_rsx::*;
|
||||||
use proc_macro2::Span;
|
use proc_macro2::Span;
|
||||||
use std::{fmt::Result, fmt::Write};
|
use std::{
|
||||||
use syn::{spanned::Spanned, Expr};
|
fmt::Result,
|
||||||
|
fmt::{self, Write},
|
||||||
|
};
|
||||||
|
use syn::{spanned::Spanned, token::Brace, Expr};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum ShortOptimization {
|
enum ShortOptimization {
|
||||||
// Special because we want to print the closing bracket immediately
|
/// Special because we want to print the closing bracket immediately
|
||||||
|
///
|
||||||
|
/// IE
|
||||||
|
/// `div {}` instead of `div { }`
|
||||||
Empty,
|
Empty,
|
||||||
|
|
||||||
// Special optimization to put everything on the same line
|
/// Special optimization to put everything on the same line and add some buffer spaces
|
||||||
|
///
|
||||||
|
/// IE
|
||||||
|
///
|
||||||
|
/// `div { "asdasd" }` instead of a multiline variant
|
||||||
Oneliner,
|
Oneliner,
|
||||||
|
|
||||||
// Optimization where children flow but props remain fixed on top
|
/// Optimization where children flow but props remain fixed on top
|
||||||
PropsOnTop,
|
PropsOnTop,
|
||||||
|
|
||||||
// The noisiest optimization where everything flows
|
/// The noisiest optimization where everything flows
|
||||||
NoOpt,
|
NoOpt,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Buffer {
|
/*
|
||||||
pub fn write_element(
|
// whitespace
|
||||||
&mut self,
|
div {
|
||||||
Element {
|
// some whitespace
|
||||||
|
class: "asdasd"
|
||||||
|
|
||||||
|
// whjiot
|
||||||
|
asdasd // whitespace
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
impl Writer {
|
||||||
|
pub fn write_element(&mut self, el: &Element) -> Result {
|
||||||
|
let Element {
|
||||||
name,
|
name,
|
||||||
key,
|
key,
|
||||||
attributes,
|
attributes,
|
||||||
children,
|
children,
|
||||||
_is_static,
|
_is_static,
|
||||||
}: &Element,
|
brace,
|
||||||
) -> Result {
|
} = el;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
1. Write the tag
|
1. Write the tag
|
||||||
2. Write the key
|
2. Write the key
|
||||||
@@ -37,7 +58,7 @@ impl Buffer {
|
|||||||
4. Write the children
|
4. Write the children
|
||||||
*/
|
*/
|
||||||
|
|
||||||
write!(self.buf, "{name} {{")?;
|
write!(self.out, "{name} {{")?;
|
||||||
|
|
||||||
// decide if we have any special optimizations
|
// decide if we have any special optimizations
|
||||||
// Default with none, opt the cases in one-by-one
|
// Default with none, opt the cases in one-by-one
|
||||||
@@ -70,6 +91,9 @@ impl Buffer {
|
|||||||
// If there's nothing at all, empty optimization
|
// If there's nothing at all, empty optimization
|
||||||
if attributes.is_empty() && children.is_empty() && key.is_none() {
|
if attributes.is_empty() && children.is_empty() && key.is_none() {
|
||||||
opt_level = ShortOptimization::Empty;
|
opt_level = ShortOptimization::Empty;
|
||||||
|
|
||||||
|
// Write comments if they exist
|
||||||
|
self.write_todo_body(brace)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiline handlers bump everything down
|
// multiline handlers bump everything down
|
||||||
@@ -80,55 +104,56 @@ impl Buffer {
|
|||||||
match opt_level {
|
match opt_level {
|
||||||
ShortOptimization::Empty => {}
|
ShortOptimization::Empty => {}
|
||||||
ShortOptimization::Oneliner => {
|
ShortOptimization::Oneliner => {
|
||||||
write!(self.buf, " ")?;
|
write!(self.out, " ")?;
|
||||||
|
|
||||||
self.write_attributes(attributes, key, true)?;
|
self.write_attributes(attributes, key, true)?;
|
||||||
|
|
||||||
if !children.is_empty() && (!attributes.is_empty() || key.is_some()) {
|
if !children.is_empty() && (!attributes.is_empty() || key.is_some()) {
|
||||||
write!(self.buf, ", ")?;
|
write!(self.out, ", ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (id, child) in children.iter().enumerate() {
|
for (id, child) in children.iter().enumerate() {
|
||||||
self.write_ident(child)?;
|
self.write_ident(child)?;
|
||||||
if id != children.len() - 1 && children.len() > 1 {
|
if id != children.len() - 1 && children.len() > 1 {
|
||||||
write!(self.buf, ", ")?;
|
write!(self.out, ", ")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(self.buf, " ")?;
|
write!(self.out, " ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShortOptimization::PropsOnTop => {
|
ShortOptimization::PropsOnTop => {
|
||||||
if !attributes.is_empty() || key.is_some() {
|
if !attributes.is_empty() || key.is_some() {
|
||||||
write!(self.buf, " ")?;
|
write!(self.out, " ")?;
|
||||||
}
|
}
|
||||||
self.write_attributes(attributes, key, true)?;
|
self.write_attributes(attributes, key, true)?;
|
||||||
|
|
||||||
if !children.is_empty() && (!attributes.is_empty() || key.is_some()) {
|
if !children.is_empty() && (!attributes.is_empty() || key.is_some()) {
|
||||||
write!(self.buf, ",")?;
|
write!(self.out, ",")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !children.is_empty() {
|
if !children.is_empty() {
|
||||||
self.write_body_indented(children)?;
|
self.write_body_indented(children)?;
|
||||||
}
|
}
|
||||||
self.tabbed_line()?;
|
self.out.tabbed_line()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShortOptimization::NoOpt => {
|
ShortOptimization::NoOpt => {
|
||||||
self.write_attributes(attributes, key, false)?;
|
self.write_attributes(attributes, key, false)?;
|
||||||
|
|
||||||
if !children.is_empty() && (!attributes.is_empty() || key.is_some()) {
|
if !children.is_empty() && (!attributes.is_empty() || key.is_some()) {
|
||||||
write!(self.buf, ",")?;
|
write!(self.out, ",")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !children.is_empty() {
|
if !children.is_empty() {
|
||||||
self.write_body_indented(children)?;
|
self.write_body_indented(children)?;
|
||||||
}
|
}
|
||||||
self.tabbed_line()?;
|
|
||||||
|
self.out.tabbed_line()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(self.buf, "}}")?;
|
write!(self.out, "}}")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -143,39 +168,39 @@ impl Buffer {
|
|||||||
|
|
||||||
if let Some(key) = key {
|
if let Some(key) = key {
|
||||||
if !sameline {
|
if !sameline {
|
||||||
self.indented_tabbed_line()?;
|
self.out.indented_tabbed_line()?;
|
||||||
}
|
}
|
||||||
write!(
|
write!(
|
||||||
self.buf,
|
self.out,
|
||||||
"key: \"{}\"",
|
"key: \"{}\"",
|
||||||
key.source.as_ref().unwrap().value()
|
key.source.as_ref().unwrap().value()
|
||||||
)?;
|
)?;
|
||||||
if !attributes.is_empty() {
|
if !attributes.is_empty() {
|
||||||
write!(self.buf, ",")?;
|
write!(self.out, ",")?;
|
||||||
if sameline {
|
if sameline {
|
||||||
write!(self.buf, " ")?;
|
write!(self.out, " ")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Some(attr) = attr_iter.next() {
|
while let Some(attr) = attr_iter.next() {
|
||||||
self.indent += 1;
|
self.out.indent += 1;
|
||||||
if !sameline {
|
if !sameline {
|
||||||
self.write_comments(attr.attr.start())?;
|
self.write_comments(attr.attr.start())?;
|
||||||
}
|
}
|
||||||
self.indent -= 1;
|
self.out.indent -= 1;
|
||||||
|
|
||||||
if !sameline {
|
if !sameline {
|
||||||
self.indented_tabbed_line()?;
|
self.out.indented_tabbed_line()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.write_attribute(attr)?;
|
self.write_attribute(attr)?;
|
||||||
|
|
||||||
if attr_iter.peek().is_some() {
|
if attr_iter.peek().is_some() {
|
||||||
write!(self.buf, ",")?;
|
write!(self.out, ",")?;
|
||||||
|
|
||||||
if sameline {
|
if sameline {
|
||||||
write!(self.buf, " ")?;
|
write!(self.out, " ")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,19 +212,19 @@ impl Buffer {
|
|||||||
match &attr.attr {
|
match &attr.attr {
|
||||||
ElementAttr::AttrText { name, value } => {
|
ElementAttr::AttrText { name, value } => {
|
||||||
write!(
|
write!(
|
||||||
self.buf,
|
self.out,
|
||||||
"{name}: \"{value}\"",
|
"{name}: \"{value}\"",
|
||||||
value = value.source.as_ref().unwrap().value()
|
value = value.source.as_ref().unwrap().value()
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
ElementAttr::AttrExpression { name, value } => {
|
ElementAttr::AttrExpression { name, value } => {
|
||||||
let out = prettyplease::unparse_expr(value);
|
let out = prettyplease::unparse_expr(value);
|
||||||
write!(self.buf, "{}: {}", name, out)?;
|
write!(self.out, "{}: {}", name, out)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementAttr::CustomAttrText { name, value } => {
|
ElementAttr::CustomAttrText { name, value } => {
|
||||||
write!(
|
write!(
|
||||||
self.buf,
|
self.out,
|
||||||
"\"{name}\": \"{value}\"",
|
"\"{name}\": \"{value}\"",
|
||||||
name = name.value(),
|
name = name.value(),
|
||||||
value = value.source.as_ref().unwrap().value()
|
value = value.source.as_ref().unwrap().value()
|
||||||
@@ -208,7 +233,7 @@ impl Buffer {
|
|||||||
|
|
||||||
ElementAttr::CustomAttrExpression { name, value } => {
|
ElementAttr::CustomAttrExpression { name, value } => {
|
||||||
let out = prettyplease::unparse_expr(value);
|
let out = prettyplease::unparse_expr(value);
|
||||||
write!(self.buf, "\"{}\": {}", name.value(), out)?;
|
write!(self.out, "\"{}\": {}", name.value(), out)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementAttr::EventTokens { name, tokens } => {
|
ElementAttr::EventTokens { name, tokens } => {
|
||||||
@@ -220,17 +245,17 @@ impl Buffer {
|
|||||||
// a one-liner for whatever reason
|
// a one-liner for whatever reason
|
||||||
// Does not need a new line
|
// Does not need a new line
|
||||||
if lines.peek().is_none() {
|
if lines.peek().is_none() {
|
||||||
write!(self.buf, "{}: {}", name, first)?;
|
write!(self.out, "{}: {}", name, first)?;
|
||||||
} else {
|
} else {
|
||||||
writeln!(self.buf, "{}: {}", name, first)?;
|
writeln!(self.out, "{}: {}", name, first)?;
|
||||||
|
|
||||||
while let Some(line) = lines.next() {
|
while let Some(line) = lines.next() {
|
||||||
self.indented_tab()?;
|
self.out.indented_tab()?;
|
||||||
write!(self.buf, "{}", line)?;
|
write!(self.out, "{}", line)?;
|
||||||
if lines.peek().is_none() {
|
if lines.peek().is_none() {
|
||||||
write!(self.buf, "")?;
|
write!(self.out, "")?;
|
||||||
} else {
|
} else {
|
||||||
writeln!(self.buf)?;
|
writeln!(self.out)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,8 +279,6 @@ impl Buffer {
|
|||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
// dbg!(beginning);
|
|
||||||
|
|
||||||
beginning.is_empty()
|
beginning.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,6 +291,10 @@ impl Buffer {
|
|||||||
if children.is_empty() {
|
if children.is_empty() {
|
||||||
// todo: allow elements with comments but no children
|
// todo: allow elements with comments but no children
|
||||||
// like div { /* comment */ }
|
// like div { /* comment */ }
|
||||||
|
// or
|
||||||
|
// div {
|
||||||
|
// // some helpful
|
||||||
|
// }
|
||||||
return Some(0);
|
return Some(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,6 +369,35 @@ impl Buffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// empty everything except for some comments
|
||||||
|
fn write_todo_body(&mut self, brace: &Brace) -> fmt::Result {
|
||||||
|
let span = brace.span.span();
|
||||||
|
let start = span.start();
|
||||||
|
let end = span.end();
|
||||||
|
|
||||||
|
if start.line == end.line {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(self.out)?;
|
||||||
|
|
||||||
|
for idx in start.line..end.line {
|
||||||
|
let line = &self.src[idx];
|
||||||
|
if line.trim().starts_with("//") {
|
||||||
|
for _ in 0..self.out.indent + 1 {
|
||||||
|
write!(self.out, " ")?
|
||||||
|
}
|
||||||
|
writeln!(self.out, "{}", line.trim()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..self.out.indent {
|
||||||
|
write!(self.out, " ")?
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_expr_length(expr: &Expr) -> Option<usize> {
|
fn get_expr_length(expr: &Expr) -> Option<usize> {
|
||||||
|
|||||||
@@ -1,45 +1,23 @@
|
|||||||
//! pretty printer for rsx!
|
//! pretty printer for rsx!
|
||||||
use std::fmt::{Result, Write};
|
use std::fmt::{Result, Write};
|
||||||
|
|
||||||
use crate::Buffer;
|
use crate::Writer;
|
||||||
|
|
||||||
impl Buffer {
|
impl Writer {
|
||||||
pub fn write_raw_expr(&mut self, exp: &syn::Expr) -> Result {
|
pub fn write_raw_expr(&mut self, exp: &syn::Expr) -> Result {
|
||||||
/*
|
/*
|
||||||
We want to normalize the expr to the appropriate indent level.
|
We want to normalize the expr to the appropriate indent level.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// in a perfect world, just fire up the rust pretty printer
|
|
||||||
// pretty_print_rust_code_as_if_it_were_rustfmt()
|
|
||||||
|
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
let placement = exp.span();
|
let placement = exp.span();
|
||||||
let start = placement.start();
|
let start = placement.start();
|
||||||
let end = placement.end();
|
let end = placement.end();
|
||||||
// let num_spaces_desired = (self.indent * 4) 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;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// offset += 1;
|
|
||||||
// }
|
|
||||||
// let had_comments = !queued_comments.is_empty();
|
|
||||||
// for comment in queued_comments.into_iter().rev() {
|
|
||||||
// writeln!(self.buf, "{}", comment)?;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if the expr is on one line, just write it directly
|
// if the expr is on one line, just write it directly
|
||||||
if start.line == end.line {
|
if start.line == end.line {
|
||||||
write!(
|
write!(
|
||||||
self.buf,
|
self.out,
|
||||||
"{}",
|
"{}",
|
||||||
&self.src[start.line - 1][start.column - 1..end.column].trim()
|
&self.src[start.line - 1][start.column - 1..end.column].trim()
|
||||||
)?;
|
)?;
|
||||||
@@ -50,7 +28,7 @@ impl Buffer {
|
|||||||
// This involves unshifting the first line if it's aligned
|
// This involves unshifting the first line if it's aligned
|
||||||
let first_line = &self.src[start.line - 1];
|
let first_line = &self.src[start.line - 1];
|
||||||
write!(
|
write!(
|
||||||
self.buf,
|
self.out,
|
||||||
"{}",
|
"{}",
|
||||||
&first_line[start.column - 1..first_line.len()].trim()
|
&first_line[start.column - 1..first_line.len()].trim()
|
||||||
)?;
|
)?;
|
||||||
@@ -66,7 +44,7 @@ impl Buffer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (id, line) in self.src[start.line..end.line].iter().enumerate() {
|
for (id, line) in self.src[start.line..end.line].iter().enumerate() {
|
||||||
writeln!(self.buf)?;
|
writeln!(self.out)?;
|
||||||
// trim the leading whitespace
|
// trim the leading whitespace
|
||||||
let line = match id {
|
let line = match id {
|
||||||
x if x == (end.line - start.line) - 1 => &line[..end.column],
|
x if x == (end.line - start.line) - 1 => &line[..end.column],
|
||||||
@@ -75,52 +53,17 @@ impl Buffer {
|
|||||||
|
|
||||||
if offset < 0 {
|
if offset < 0 {
|
||||||
for _ in 0..-offset {
|
for _ in 0..-offset {
|
||||||
write!(self.buf, " ")?;
|
write!(self.out, " ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(self.buf, "{}", line)?;
|
write!(self.out, "{}", line)?;
|
||||||
} else {
|
} else {
|
||||||
let offset = offset as usize;
|
let offset = offset as usize;
|
||||||
let right = &line[offset..];
|
let right = &line[offset..];
|
||||||
write!(self.buf, "{}", right)?;
|
write!(self.out, "{}", right)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// :(
|
|
||||||
// fn pretty_print_rust_code_as_if_it_were_rustfmt(code: &str) -> String {
|
|
||||||
// let formatted = prettyplease::unparse_expr(exp);
|
|
||||||
// for line in formatted.lines() {
|
|
||||||
// write!(self.buf, "{}", line)?;
|
|
||||||
// self.new_line()?;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
use dioxus_rsx::CallBody;
|
use dioxus_rsx::CallBody;
|
||||||
|
|
||||||
use crate::buffer::*;
|
|
||||||
use crate::util::*;
|
use crate::util::*;
|
||||||
|
use crate::writer::*;
|
||||||
|
|
||||||
mod buffer;
|
mod buffer;
|
||||||
mod component;
|
mod component;
|
||||||
mod element;
|
mod element;
|
||||||
mod expr;
|
mod expr;
|
||||||
mod util;
|
mod util;
|
||||||
|
mod writer;
|
||||||
|
|
||||||
/// A modification to the original file to be applied by an IDE
|
/// A modification to the original file to be applied by an IDE
|
||||||
///
|
///
|
||||||
@@ -101,10 +102,9 @@ pub fn fmt_file(contents: &str) -> Vec<FormattedBlock> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_block_out(body: CallBody) -> Option<String> {
|
pub fn write_block_out(body: CallBody) -> Option<String> {
|
||||||
let mut buf = Buffer {
|
let mut buf = Writer {
|
||||||
src: vec!["".to_string()],
|
src: vec!["".to_string()],
|
||||||
indent: 0,
|
..Writer::default()
|
||||||
..Buffer::default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Oneliner optimization
|
// Oneliner optimization
|
||||||
@@ -120,12 +120,13 @@ pub fn write_block_out(body: CallBody) -> Option<String> {
|
|||||||
pub fn fmt_block(block: &str, indent_level: usize) -> Option<String> {
|
pub fn fmt_block(block: &str, indent_level: usize) -> Option<String> {
|
||||||
let body = syn::parse_str::<dioxus_rsx::CallBody>(block).ok()?;
|
let body = syn::parse_str::<dioxus_rsx::CallBody>(block).ok()?;
|
||||||
|
|
||||||
let mut buf = Buffer {
|
let mut buf = Writer {
|
||||||
src: block.lines().map(|f| f.to_string()).collect(),
|
src: block.lines().map(|f| f.to_string()).collect(),
|
||||||
indent: indent_level,
|
..Writer::default()
|
||||||
..Buffer::default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
buf.out.indent = indent_level;
|
||||||
|
|
||||||
// Oneliner optimization
|
// Oneliner optimization
|
||||||
if buf.is_short_children(&body.roots).is_some() {
|
if buf.is_short_children(&body.roots).is_some() {
|
||||||
buf.write_ident(&body.roots[0]).unwrap();
|
buf.write_ident(&body.roots[0]).unwrap();
|
||||||
@@ -134,8 +135,8 @@ pub fn fmt_block(block: &str, indent_level: usize) -> Option<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// writing idents leaves the final line ended at the end of the last ident
|
// writing idents leaves the final line ended at the end of the last ident
|
||||||
if buf.buf.contains('\n') {
|
if buf.out.buf.contains('\n') {
|
||||||
buf.new_line().unwrap();
|
buf.out.new_line().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.consume()
|
buf.consume()
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
use dioxus_rsx::{BodyNode, ElementAttr, ElementAttrNamed};
|
||||||
|
use proc_macro2::{LineColumn, Span};
|
||||||
|
use std::{
|
||||||
|
collections::{HashMap, VecDeque},
|
||||||
|
fmt::{Result, Write},
|
||||||
|
};
|
||||||
|
use syn::{spanned::Spanned, Expr};
|
||||||
|
|
||||||
|
use crate::buffer::Buffer;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Writer {
|
||||||
|
pub src: Vec<String>,
|
||||||
|
pub cached_formats: HashMap<Location, String>,
|
||||||
|
pub comments: VecDeque<usize>,
|
||||||
|
pub out: Buffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
|
||||||
|
pub struct Location {
|
||||||
|
pub line: usize,
|
||||||
|
pub col: usize,
|
||||||
|
}
|
||||||
|
impl Location {
|
||||||
|
pub fn new(start: LineColumn) -> Self {
|
||||||
|
Self {
|
||||||
|
line: start.line,
|
||||||
|
col: start.column,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Writer {
|
||||||
|
// Expects to be written directly into place
|
||||||
|
pub fn write_ident(&mut self, node: &BodyNode) -> Result {
|
||||||
|
match node {
|
||||||
|
BodyNode::Element(el) => self.write_element(el),
|
||||||
|
BodyNode::Component(component) => self.write_component(component),
|
||||||
|
BodyNode::Text(text) => self.out.write_text(text),
|
||||||
|
BodyNode::RawExpr(exp) => self.write_raw_expr(exp),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn consume(self) -> Option<String> {
|
||||||
|
Some(self.out.buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_comments(&mut self, child: Span) -> Result {
|
||||||
|
// collect all comments upwards
|
||||||
|
let start = child.start();
|
||||||
|
let line_start = start.line - 1;
|
||||||
|
|
||||||
|
for (id, line) in self.src[..line_start].iter().enumerate().rev() {
|
||||||
|
if line.trim().starts_with("//") || line.is_empty() {
|
||||||
|
if id != 0 {
|
||||||
|
self.comments.push_front(id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut last_was_empty = false;
|
||||||
|
while let Some(comment_line) = self.comments.pop_front() {
|
||||||
|
let line = &self.src[comment_line];
|
||||||
|
if line.is_empty() {
|
||||||
|
if !last_was_empty {
|
||||||
|
self.out.new_line()?;
|
||||||
|
}
|
||||||
|
last_was_empty = true;
|
||||||
|
} else {
|
||||||
|
last_was_empty = false;
|
||||||
|
self.out.tabbed_line()?;
|
||||||
|
write!(self.out, "{}", self.src[comment_line].trim())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push out the indent level and write each component, line by line
|
||||||
|
pub fn write_body_indented(&mut self, children: &[BodyNode]) -> Result {
|
||||||
|
self.out.indent += 1;
|
||||||
|
|
||||||
|
self.write_body_no_indent(children)?;
|
||||||
|
|
||||||
|
self.out.indent -= 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_body_no_indent(&mut self, children: &[BodyNode]) -> Result {
|
||||||
|
let last_child = children.len();
|
||||||
|
let iter = children.iter().peekable().enumerate();
|
||||||
|
|
||||||
|
for (idx, child) in iter {
|
||||||
|
if self.current_span_is_primary(child.span()) {
|
||||||
|
self.write_comments(child.span())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
match child {
|
||||||
|
// check if the expr is a short
|
||||||
|
BodyNode::RawExpr { .. } => {
|
||||||
|
self.out.tabbed_line()?;
|
||||||
|
self.write_ident(child)?;
|
||||||
|
if idx != last_child - 1 {
|
||||||
|
write!(self.out, ",")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.out.tabbed_line()?;
|
||||||
|
self.write_ident(child)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_short_attrs(&mut self, attributes: &[ElementAttrNamed]) -> usize {
|
||||||
|
let mut total = 0;
|
||||||
|
|
||||||
|
for attr in attributes {
|
||||||
|
if self.current_span_is_primary(attr.attr.start()) {
|
||||||
|
'line: for line in self.src[..attr.attr.start().start().line - 1].iter().rev() {
|
||||||
|
match (line.trim().starts_with("//"), line.is_empty()) {
|
||||||
|
(true, _) => return 100000,
|
||||||
|
(_, true) => continue 'line,
|
||||||
|
_ => break 'line,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total += match &attr.attr {
|
||||||
|
ElementAttr::AttrText { value, name } => {
|
||||||
|
value.source.as_ref().unwrap().value().len() + name.span().line_length() + 3
|
||||||
|
}
|
||||||
|
ElementAttr::AttrExpression { name, value } => {
|
||||||
|
value.span().line_length() + name.span().line_length() + 3
|
||||||
|
}
|
||||||
|
ElementAttr::CustomAttrText { value, name } => {
|
||||||
|
value.source.as_ref().unwrap().value().len() + name.value().len() + 3
|
||||||
|
}
|
||||||
|
ElementAttr::CustomAttrExpression { name, value } => {
|
||||||
|
name.value().len() + value.span().line_length() + 3
|
||||||
|
}
|
||||||
|
ElementAttr::EventTokens { tokens, name } => {
|
||||||
|
let location = Location::new(tokens.span().start());
|
||||||
|
|
||||||
|
let len = if let std::collections::hash_map::Entry::Vacant(e) =
|
||||||
|
self.cached_formats.entry(location)
|
||||||
|
{
|
||||||
|
let formatted = prettyplease::unparse_expr(tokens);
|
||||||
|
let len = if formatted.contains('\n') {
|
||||||
|
10000
|
||||||
|
} else {
|
||||||
|
formatted.len()
|
||||||
|
};
|
||||||
|
e.insert(formatted);
|
||||||
|
len
|
||||||
|
} else {
|
||||||
|
self.cached_formats[&location].len()
|
||||||
|
};
|
||||||
|
|
||||||
|
len + name.span().line_length() + 3
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
total
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn retrieve_formatted_expr(&mut self, expr: &Expr) -> &str {
|
||||||
|
self.cached_formats
|
||||||
|
.entry(Location::new(expr.span().start()))
|
||||||
|
.or_insert_with(|| prettyplease::unparse_expr(expr))
|
||||||
|
.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait SpanLength {
|
||||||
|
fn line_length(&self) -> usize;
|
||||||
|
}
|
||||||
|
impl SpanLength for Span {
|
||||||
|
fn line_length(&self) -> usize {
|
||||||
|
self.end().line - self.start().line
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,3 +30,6 @@ twoway! ("key" => key);
|
|||||||
|
|
||||||
// Disabled because we can't handle comments on exprs yet
|
// Disabled because we can't handle comments on exprs yet
|
||||||
twoway! ("multirsx" => multirsx);
|
twoway! ("multirsx" => multirsx);
|
||||||
|
|
||||||
|
// Disabled because we can't handle comments on exprs yet
|
||||||
|
twoway! ("commentshard" => commentshard);
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
rsx! {
|
||||||
|
// Comments
|
||||||
|
div {
|
||||||
|
// Comments
|
||||||
|
class: "asdasd",
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
"hello world"
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
expr1,
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
expr2,
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
// Comments
|
||||||
|
// Comments
|
||||||
|
// Comments
|
||||||
|
// Comments
|
||||||
|
expr3,
|
||||||
|
|
||||||
|
div {
|
||||||
|
// todo some work in here
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
// todo some work in here
|
||||||
|
// todo some work in here
|
||||||
|
//
|
||||||
|
// todo some work in here
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
// todo some work in here
|
||||||
|
class: "hello world",
|
||||||
|
|
||||||
|
// todo some work in here
|
||||||
|
class: "hello world"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,8 +19,7 @@ use syn::{
|
|||||||
ext::IdentExt,
|
ext::IdentExt,
|
||||||
parse::{Parse, ParseBuffer, ParseStream},
|
parse::{Parse, ParseBuffer, ParseStream},
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
token, AngleBracketedGenericArguments, Error, Expr, Ident, LitStr, PathArguments, Result,
|
AngleBracketedGenericArguments, Error, Expr, Ident, LitStr, PathArguments, Result, Token,
|
||||||
Token,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||||
@@ -30,6 +29,7 @@ pub struct Component {
|
|||||||
pub fields: Vec<ComponentField>,
|
pub fields: Vec<ComponentField>,
|
||||||
pub children: Vec<BodyNode>,
|
pub children: Vec<BodyNode>,
|
||||||
pub manual_props: Option<Expr>,
|
pub manual_props: Option<Expr>,
|
||||||
|
pub brace: syn::token::Brace,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component {
|
impl Component {
|
||||||
@@ -88,13 +88,9 @@ impl Parse for Component {
|
|||||||
|
|
||||||
// if we see a `{` then we have a block
|
// if we see a `{` then we have a block
|
||||||
// else parse as a function-like call
|
// else parse as a function-like call
|
||||||
if stream.peek(token::Brace) {
|
let brace = syn::braced!(content in stream);
|
||||||
syn::braced!(content in stream);
|
|
||||||
} else {
|
|
||||||
syn::parenthesized!(content in stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut body = Vec::new();
|
let mut fields = Vec::new();
|
||||||
let mut children = Vec::new();
|
let mut children = Vec::new();
|
||||||
let mut manual_props = None;
|
let mut manual_props = None;
|
||||||
|
|
||||||
@@ -104,7 +100,7 @@ impl Parse for Component {
|
|||||||
content.parse::<Token![..]>()?;
|
content.parse::<Token![..]>()?;
|
||||||
manual_props = Some(content.parse::<Expr>()?);
|
manual_props = Some(content.parse::<Expr>()?);
|
||||||
} else if content.peek(Ident) && content.peek2(Token![:]) && !content.peek3(Token![:]) {
|
} else if content.peek(Ident) && content.peek2(Token![:]) && !content.peek3(Token![:]) {
|
||||||
body.push(content.parse::<ComponentField>()?);
|
fields.push(content.parse::<ComponentField>()?);
|
||||||
} else {
|
} else {
|
||||||
children.push(content.parse::<BodyNode>()?);
|
children.push(content.parse::<BodyNode>()?);
|
||||||
}
|
}
|
||||||
@@ -117,9 +113,10 @@ impl Parse for Component {
|
|||||||
Ok(Self {
|
Ok(Self {
|
||||||
name,
|
name,
|
||||||
prop_gen_args,
|
prop_gen_args,
|
||||||
fields: body,
|
fields,
|
||||||
children,
|
children,
|
||||||
manual_props,
|
manual_props,
|
||||||
|
brace,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ pub struct Element {
|
|||||||
pub attributes: Vec<ElementAttrNamed>,
|
pub attributes: Vec<ElementAttrNamed>,
|
||||||
pub children: Vec<BodyNode>,
|
pub children: Vec<BodyNode>,
|
||||||
pub _is_static: bool,
|
pub _is_static: bool,
|
||||||
|
pub brace: syn::token::Brace,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Element {
|
impl Parse for Element {
|
||||||
@@ -25,7 +26,7 @@ impl Parse for Element {
|
|||||||
|
|
||||||
// parse the guts
|
// parse the guts
|
||||||
let content: ParseBuffer;
|
let content: ParseBuffer;
|
||||||
syn::braced!(content in stream);
|
let brace = syn::braced!(content in stream);
|
||||||
|
|
||||||
let mut attributes: Vec<ElementAttrNamed> = vec![];
|
let mut attributes: Vec<ElementAttrNamed> = vec![];
|
||||||
let mut children: Vec<BodyNode> = vec![];
|
let mut children: Vec<BodyNode> = vec![];
|
||||||
@@ -152,6 +153,7 @@ impl Parse for Element {
|
|||||||
name: el_name,
|
name: el_name,
|
||||||
attributes,
|
attributes,
|
||||||
children,
|
children,
|
||||||
|
brace,
|
||||||
_is_static: false,
|
_is_static: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user