fix: even better comment handling

This commit is contained in:
Jonathan Kelley committed 2022-07-05 01:53:08 -04:00
1 parent 47f3cc2529
commit 4471ccba49
8 files changed
+115 -73

No files matched your search

+1 -1
View File
@@ -2,4 +2,4 @@
This crate formats rsx! by parsing call bodies and pretty-printing them back out. This crate formats rsx! by parsing call bodies and pretty-printing them back out.
It also incorporates a fork of prettyplease to allow formatting arbitrary rust code too. Prettyplease rejected a suggestion to allow arbitrary expression formatting - something our fork lets us do.
+55 -42
View File
@@ -1,11 +1,12 @@
use std::{ use std::{
collections::HashMap, collections::{HashMap, VecDeque},
fmt::{Result, Write}, fmt::{Result, Write},
rc::Rc,
}; };
use dioxus_rsx::{BodyNode, ElementAttr, ElementAttrNamed}; use dioxus_rsx::{BodyNode, ElementAttr, ElementAttrNamed};
use proc_macro2::{LineColumn, Span}; use proc_macro2::{LineColumn, Span};
use syn::spanned::Spanned; use syn::{spanned::Spanned, Expr};
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct Buffer { pub struct Buffer {
@@ -13,6 +14,7 @@ pub struct Buffer {
pub cached_formats: HashMap<Location, 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)] #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
@@ -79,46 +81,47 @@ impl Buffer {
Some(self.buf) 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 // Push out the indent level and write each component, line by line
pub fn write_body_indented(&mut self, children: &[BodyNode]) -> Result { pub fn write_body_indented(&mut self, children: &[BodyNode]) -> Result {
self.indent += 1; self.indent += 1;
let mut comments = Vec::new();
for child in children { for child in children {
// Exprs handle their own indenting/line breaks // Exprs handle their own indenting/line breaks
if !matches!(child, BodyNode::RawExpr(_)) { if !matches!(child, BodyNode::RawExpr(_)) {
// collect all comments upwards self.write_comments(child.span())?;
let start = child.span().start();
let line_start = start.line;
if self.current_element_has_comments(child) {
for (id, line) in self.src[..line_start - 1].iter().enumerate().rev() {
if line.trim().starts_with("//") || line.is_empty() {
if id != 0 {
comments.push(id);
}
} else {
break;
}
}
}
let mut last_was_empty = false;
for comment_line in comments.drain(..).rev() {
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())?;
}
}
self.tabbed_line()?; self.tabbed_line()?;
} }
@@ -130,9 +133,14 @@ impl Buffer {
} }
pub(crate) fn is_short_attrs(&mut self, attributes: &[ElementAttrNamed]) -> usize { pub(crate) fn is_short_attrs(&mut self, attributes: &[ElementAttrNamed]) -> usize {
attributes let mut total = 0;
.iter()
.map(|attr| match &attr.attr { for attr in attributes {
if self.current_element_has_comments(attr.span()) {
return 100000;
}
total += match &attr.attr {
ElementAttr::AttrText { value, name } => { ElementAttr::AttrText { value, name } => {
value.value().len() + name.span().line_length() + 3 value.value().len() + name.span().line_length() + 3
} }
@@ -165,12 +173,17 @@ impl Buffer {
len + name.span().line_length() + 3 len + name.span().line_length() + 3
} }
}) };
.sum() }
total
} }
pub fn retrieve_formatted_expr(&mut self, location: LineColumn) -> Option<String> { pub fn retrieve_formatted_expr(&mut self, expr: &Expr) -> &str {
self.cached_formats.remove(&Location::new(location)) self.cached_formats
.entry(Location::new(expr.span().start()))
.or_insert(prettyplease::unparse_expr(expr))
.as_str()
} }
} }
+10 -4
View File
@@ -1,5 +1,6 @@
use crate::Buffer; use crate::Buffer;
use dioxus_rsx::*; use dioxus_rsx::*;
use proc_macro2::Span;
use std::{fmt::Result, fmt::Write}; use std::{fmt::Result, fmt::Write};
use syn::spanned::Spanned; use syn::spanned::Spanned;
@@ -146,9 +147,14 @@ impl Buffer {
} }
while let Some(attr) = attr_iter.next() { while let Some(attr) = attr_iter.next() {
self.indent += 1;
self.write_comments(attr.attr.start())?;
self.indent -= 1;
if !sameline { if !sameline {
self.indented_tabbed_line()?; self.indented_tabbed_line()?;
} }
self.write_attribute(attr)?; self.write_attribute(attr)?;
if attr_iter.peek().is_some() { if attr_iter.peek().is_some() {
@@ -188,7 +194,7 @@ impl Buffer {
} }
ElementAttr::EventTokens { name, tokens } => { ElementAttr::EventTokens { name, tokens } => {
let out = self.retrieve_formatted_expr(tokens.span().start()).unwrap(); let out = self.retrieve_formatted_expr(tokens).to_string();
let mut lines = out.split('\n').peekable(); let mut lines = out.split('\n').peekable();
let first = lines.next().unwrap(); let first = lines.next().unwrap();
@@ -216,8 +222,8 @@ impl Buffer {
Ok(()) Ok(())
} }
pub fn current_element_has_comments(&self, child: &BodyNode) -> bool { pub fn current_element_has_comments(&self, location: Span) -> bool {
let start = child.span().start(); let start = location.start();
let line_start = start.line; let line_start = start.line;
// make sure the comments are actually relevant to this element. // make sure the comments are actually relevant to this element.
@@ -245,7 +251,7 @@ impl Buffer {
} }
for child in children { for child in children {
if self.current_element_has_comments(child) { if self.current_element_has_comments(child.span()) {
'line: for line in self.src[..child.span().start().line - 1].iter().rev() { 'line: for line in self.src[..child.span().start().line - 1].iter().rev() {
match (line.trim().starts_with("//"), line.is_empty()) { match (line.trim().starts_with("//"), line.is_empty()) {
(true, _) => return None, (true, _) => return None,
+10
View File
@@ -30,3 +30,13 @@ fn comment_case_work() {
println!("{}", out); println!("{}", out);
} }
#[test]
fn comment_attr_case_work() {
let src = include_str!("./samples/attrs.rsx");
let formatted = dioxus_autofmt::fmt_file(src);
let out = dioxus_autofmt::apply_formats(src, formatted);
println!("{}", out);
}
-25
View File
@@ -1,25 +0,0 @@
#![allow(unused)]
const SRC: &str = include_str!("./samples/all.rsx");
fn body() -> &'static str {
&SRC[6..SRC.len() - 3]
}
fn unindented_body() -> String {
body()
.lines()
.map(|line| match line.strip_prefix(" ") {
Some(line) => line,
None => line,
})
.collect::<Vec<_>>()
.join("\n")
}
#[test]
fn way_and_back() {
let blocks = dioxus_autofmt::fmt_file(SRC).into_iter().next().unwrap();
println!("{}", blocks.formatted);
}
+21
View File
@@ -0,0 +1,21 @@
rsx! {
div {
// My comment here 1
// My comment here 2
// My comment here 3
// My comment here 4
class: "asdasd",
// Comment here
onclick: move |_| {
let a = 10;
let b = 40;
let c = 50;
},
// my comment
// This here
"hi"
}
}
@@ -15,6 +15,12 @@ rsx! {
// body // body
div { "text" } div { "text" }
div {
// Attr
class: "asdads",
"health"
}
div { div {
+12 -1
View File
@@ -1,6 +1,6 @@
use super::*; use super::*;
use proc_macro2::TokenStream as TokenStream2; use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::{quote, ToTokens, TokenStreamExt}; use quote::{quote, ToTokens, TokenStreamExt};
use syn::{ use syn::{
parse::{Parse, ParseBuffer, ParseStream}, parse::{Parse, ParseBuffer, ParseStream},
@@ -209,7 +209,18 @@ pub enum ElementAttr {
/// onclick: {} /// onclick: {}
EventTokens { name: Ident, tokens: Expr }, EventTokens { name: Ident, tokens: Expr },
} }
impl ElementAttr { impl ElementAttr {
pub fn start(&self) -> Span {
match self {
ElementAttr::AttrText { name, .. } => name.span(),
ElementAttr::AttrExpression { name, .. } => name.span(),
ElementAttr::CustomAttrText { name, .. } => name.span(),
ElementAttr::CustomAttrExpression { name, .. } => name.span(),
ElementAttr::EventTokens { name, .. } => name.span(),
}
}
pub fn is_expr(&self) -> bool { pub fn is_expr(&self) -> bool {
matches!( matches!(
self, self,