Fix: #2604, Fix: #2240, Fix: #2341, Fix #1355 - Better error handling and and spaces handling in autofmt (#2736)

* add new autofmt sample
* Feat: implement rustfmt::skip support for rsx
* generally improve error handling with better expect messages
* wip: nested rsx formatting and expression formatting
* nested rsx formatting works
* collapse autofmt crate
* cast indent through macros
* use proper whitespace
* no more eating comments!
* Use proper error handling
This commit is contained in:
Jonathan Kelley authored and GitHub committed 2024-07-30 18:36:13 -07:00
1 parent ef0202f999
commit 828cc502f1
47 files changed
+1621 -1055

No files matched your search

+35 -32
View File
@@ -4,14 +4,13 @@
use crate::writer::*;
use dioxus_rsx::{BodyNode, CallBody};
use proc_macro2::LineColumn;
use syn::{parse::Parser, ExprMacro};
use proc_macro2::{LineColumn, Span};
use syn::parse::Parser;
mod buffer;
mod collect_macros;
mod indent;
mod prettier_please;
mod rsx_block;
mod writer;
pub use indent::{IndentOptions, IndentType};
@@ -37,6 +36,16 @@ pub struct FormattedBlock {
pub end: usize,
}
/// Format a file into a list of `FormattedBlock`s to be applied by an IDE for autoformatting.
///
/// It accepts
#[deprecated(note = "Use try_fmt_file instead - this function panics on error.")]
pub fn fmt_file(contents: &str, indent: IndentOptions) -> Vec<FormattedBlock> {
let parsed =
syn::parse_file(contents).expect("fmt_file should only be called on valid syn::File files");
try_fmt_file(contents, &parsed, indent).expect("Failed to format file")
}
/// Format a file into a list of `FormattedBlock`s to be applied by an IDE for autoformatting.
///
/// This function expects a complete file, not just a block of code. To format individual rsx! blocks, use fmt_block instead.
@@ -45,19 +54,27 @@ pub struct FormattedBlock {
/// back to the file precisely.
///
/// Nested blocks of RSX will be handled automatically
pub fn fmt_file(contents: &str, indent: IndentOptions) -> Vec<FormattedBlock> {
///
/// This returns an error if the rsx itself is invalid.
///
/// Will early return if any of the expressions are not complete. Even though we *could* return the
/// expressions, eventually we'll want to pass off expression formatting to rustfmt which will reject
/// those.
pub fn try_fmt_file(
contents: &str,
parsed: &syn::File,
indent: IndentOptions,
) -> syn::Result<Vec<FormattedBlock>> {
let mut formatted_blocks = Vec::new();
let parsed = syn::parse_file(contents).unwrap();
let macros = collect_macros::collect_from_file(&parsed);
let macros = collect_macros::collect_from_file(parsed);
// No macros, no work to do
if macros.is_empty() {
return formatted_blocks;
return Ok(formatted_blocks);
}
let mut writer = Writer::new(contents);
writer.out.indent = indent;
let mut writer = Writer::new(contents, indent);
// Don't parse nested macros
let mut end_span = LineColumn { column: 0, line: 0 };
@@ -69,14 +86,7 @@ pub fn fmt_file(contents: &str, indent: IndentOptions) -> Vec<FormattedBlock> {
continue;
}
let body = match item.parse_body_with(CallBody::parse_strict) {
Ok(v) => v,
//there is aparsing error, we give up and don't format the rsx
Err(e) => {
eprintln!("Error while parsing rsx {:?} ", e);
return formatted_blocks;
}
};
let body = item.parse_body_with(CallBody::parse_strict)?;
let rsx_start = macro_path.span().start();
@@ -86,15 +96,16 @@ pub fn fmt_file(contents: &str, indent: IndentOptions) -> Vec<FormattedBlock> {
.count_indents(writer.src[rsx_start.line - 1]);
// TESTME
// If we fail to parse this macro then we have no choice to give up and return what we've got
// Writing *should* not fail but it's possible that it does
if writer.write_rsx_call(&body.body).is_err() {
return formatted_blocks;
let span = writer.invalid_exprs.pop().unwrap_or_else(Span::call_site);
return Err(syn::Error::new(span, "Failed emit valid rsx - likely due to partially complete expressions in the rsx! macro"));
}
// writing idents leaves the final line ended at the end of the last ident
if writer.out.buf.contains('\n') {
writer.out.new_line().unwrap();
writer.out.tab().unwrap();
_ = writer.out.new_line();
_ = writer.out.tab();
}
let span = item.delimiter.span().join();
@@ -124,7 +135,7 @@ pub fn fmt_file(contents: &str, indent: IndentOptions) -> Vec<FormattedBlock> {
});
}
formatted_blocks
Ok(formatted_blocks)
}
/// Write a Callbody (the rsx block) to a string
@@ -132,14 +143,7 @@ pub fn fmt_file(contents: &str, indent: IndentOptions) -> Vec<FormattedBlock> {
/// If the tokens can't be formatted, this returns None. This is usually due to an incomplete expression
/// that passed partial expansion but failed to parse.
pub fn write_block_out(body: &CallBody) -> Option<String> {
let mut buf = Writer::new("");
buf.write_rsx_call(&body.body).ok()?;
buf.consume()
}
pub fn fmt_block_from_expr(raw: &str, expr: ExprMacro) -> Option<String> {
let body = CallBody::parse_strict.parse2(expr.mac.tokens).unwrap();
let mut buf = Writer::new(raw);
let mut buf = Writer::new("", IndentOptions::default());
buf.write_rsx_call(&body.body).ok()?;
buf.consume()
}
@@ -147,8 +151,7 @@ pub fn fmt_block_from_expr(raw: &str, expr: ExprMacro) -> Option<String> {
pub fn fmt_block(block: &str, indent_level: usize, indent: IndentOptions) -> Option<String> {
let body = CallBody::parse_strict.parse_str(block).unwrap();
let mut buf = Writer::new(block);
buf.out.indent = indent;
let mut buf = Writer::new(block, indent);
buf.out.indent_level = indent_level;
buf.write_rsx_call(&body.body).ok()?;