Merge pull request #1902 from Dangerised/master

add rustfmt support
This commit is contained in:
Evan Almloff authored and GitHub committed 2024-02-09 09:33:05 -06:00
commit 0a4603d30e
5 files changed
+90 -95

No files matched your search

Generated
+4 -10
View File
@@ -2405,11 +2405,11 @@ dependencies = [
"flate2", "flate2",
"fs_extra", "fs_extra",
"futures-util", "futures-util",
"gitignore",
"headers 0.3.9", "headers 0.3.9",
"html_parser", "html_parser",
"hyper 0.14.28", "hyper 0.14.28",
"hyper-rustls 0.23.2", "hyper-rustls 0.23.2",
"ignore",
"indicatif", "indicatif",
"interprocess-docfix", "interprocess-docfix",
"lazy_static", "lazy_static",
@@ -2418,11 +2418,14 @@ dependencies = [
"mlua", "mlua",
"notify", "notify",
"open", "open",
"prettier-please",
"rayon",
"reqwest", "reqwest",
"rsx-rosetta", "rsx-rosetta",
"serde", "serde",
"serde_json", "serde_json",
"subprocess", "subprocess",
"syn 2.0.48",
"tar", "tar",
"tauri-bundler", "tauri-bundler",
"tempfile", "tempfile",
@@ -3917,15 +3920,6 @@ dependencies = [
"url", "url",
] ]
[[package]]
name = "gitignore"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d051488d9a601181a9b90c9ad8ae7e8251d642ddd2463008f2f5019d255bd89"
dependencies = [
"glob",
]
[[package]] [[package]]
name = "gix-actor" name = "gix-actor"
version = "0.28.1" version = "0.28.1"
+1 -1
View File
@@ -84,7 +84,7 @@ dioxus-signals = { path = "packages/signals" }
dioxus-cli-config = { path = "packages/cli-config", version = "0.4.1" } dioxus-cli-config = { path = "packages/cli-config", version = "0.4.1" }
generational-box = { path = "packages/generational-box", version = "0.4.3" } generational-box = { path = "packages/generational-box", version = "0.4.3" }
dioxus-hot-reload = { path = "packages/hot-reload", version = "0.4.0" } dioxus-hot-reload = { path = "packages/hot-reload", version = "0.4.0" }
dioxus-fullstack = { path = "packages/fullstack", version = "0.4.1" } dioxus-fullstack = { path = "packages/fullstack", version = "0.4.1" }
dioxus_server_macro = { path = "packages/server-macro", version = "0.4.1" } dioxus_server_macro = { path = "packages/server-macro", version = "0.4.1" }
tracing = "0.1.37" tracing = "0.1.37"
tracing-futures = "0.2.5" tracing-futures = "0.2.5"
+7 -2
View File
@@ -26,7 +26,7 @@ fs_extra = "1.2.0"
cargo_toml = "0.18.0" cargo_toml = "0.18.0"
futures-util = { workspace = true } futures-util = { workspace = true }
notify = { version = "5.0.0-pre.16", features = ["serde"] } notify = { version = "5.0.0-pre.16", features = ["serde"] }
html_parser = { workspace = true } html_parser = { workspace = true }
cargo_metadata = "0.18.1" cargo_metadata = "0.18.1"
tokio = { version = "1.16.1", features = ["fs", "sync", "rt", "macros"] } tokio = { version = "1.16.1", features = ["fs", "sync", "rt", "macros"] }
atty = "0.2.14" atty = "0.2.14"
@@ -36,6 +36,7 @@ hyper = "0.14.17"
hyper-rustls = "0.23.2" hyper-rustls = "0.23.2"
indicatif = "0.17.5" indicatif = "0.17.5"
subprocess = "0.2.9" subprocess = "0.2.9"
rayon = "1.8.0"
axum = { version = "0.5.1", features = ["ws", "headers"] } axum = { version = "0.5.1", features = ["ws", "headers"] }
axum-server = { version = "0.5.1", features = ["tls-rustls"] } axum-server = { version = "0.5.1", features = ["tls-rustls"] }
@@ -74,6 +75,10 @@ toml_edit = "0.21.0"
# bundling # bundling
tauri-bundler = { version = "=1.4.*", features = ["native-tls-vendored"] } tauri-bundler = { version = "=1.4.*", features = ["native-tls-vendored"] }
# formatting
syn = { version = "2.0" }
prettyplease = { workspace = true }
manganis-cli-support = { workspace = true, features = ["webp", "html"] } manganis-cli-support = { workspace = true, features = ["webp", "html"] }
dioxus-autofmt = { workspace = true } dioxus-autofmt = { workspace = true }
@@ -84,7 +89,7 @@ dioxus-html = { workspace = true, features = ["hot-reload-context"] }
dioxus-core = { workspace = true, features = ["serialize"] } dioxus-core = { workspace = true, features = ["serialize"] }
dioxus-hot-reload = { workspace = true } dioxus-hot-reload = { workspace = true }
interprocess-docfix = { version = "1.2.2" } interprocess-docfix = { version = "1.2.2" }
gitignore = "1.0.8" ignore = "0.4.22"
[features] [features]
default = [] default = []
+78 -81
View File
@@ -1,5 +1,5 @@
use dioxus_autofmt::{IndentOptions, IndentType}; use dioxus_autofmt::{IndentOptions, IndentType};
use futures_util::{stream::FuturesUnordered, StreamExt}; use rayon::prelude::*;
use std::{fs, path::Path, process::exit}; use std::{fs, path::Path, process::exit};
use super::*; use super::*;
@@ -10,6 +10,10 @@ use super::*;
/// Format some rsx /// Format some rsx
#[derive(Clone, Debug, Parser)] #[derive(Clone, Debug, Parser)]
pub struct Autoformat { pub struct Autoformat {
/// Format rust code before the formatting the rsx macros
#[clap(long)]
pub all_code: bool,
/// Run in 'check' mode. Exits with 0 if input is formatted correctly. Exits /// Run in 'check' mode. Exits with 0 if input is formatted correctly. Exits
/// with 1 and prints a diff if formatting is required. /// with 1 and prints a diff if formatting is required.
#[clap(short, long)] #[clap(short, long)]
@@ -29,19 +33,19 @@ pub struct Autoformat {
} }
impl Autoformat { impl Autoformat {
// Todo: autoformat the entire crate pub fn autoformat(self) -> Result<()> {
pub async fn autoformat(self) -> Result<()> {
let Autoformat { let Autoformat {
check, check,
raw, raw,
file, file,
split_line_attributes, split_line_attributes,
all_code: format_rust_code,
.. ..
} = self; } = self;
// Default to formatting the project // Default to formatting the project
if raw.is_none() && file.is_none() { if raw.is_none() && file.is_none() {
if let Err(e) = autoformat_project(check, split_line_attributes).await { if let Err(e) = autoformat_project(check, split_line_attributes, format_rust_code) {
eprintln!("error formatting project: {}", e); eprintln!("error formatting project: {}", e);
exit(1); exit(1);
} }
@@ -60,14 +64,18 @@ impl Autoformat {
// Format single file // Format single file
if let Some(file) = file { if let Some(file) = file {
refactor_file(file, split_line_attributes)?; refactor_file(file, split_line_attributes, format_rust_code)?;
} }
Ok(()) Ok(())
} }
} }
fn refactor_file(file: String, split_line_attributes: bool) -> Result<(), Error> { fn refactor_file(
file: String,
split_line_attributes: bool,
format_rust_code: bool,
) -> Result<(), Error> {
let indent = indentation_for(".", split_line_attributes)?; let indent = indentation_for(".", split_line_attributes)?;
let file_content = if file == "-" { let file_content = if file == "-" {
let mut contents = String::new(); let mut contents = String::new();
@@ -76,10 +84,15 @@ fn refactor_file(file: String, split_line_attributes: bool) -> Result<(), Error>
} else { } else {
fs::read_to_string(&file) fs::read_to_string(&file)
}; };
let Ok(s) = file_content else { let Ok(mut s) = file_content else {
eprintln!("failed to open file: {}", file_content.unwrap_err()); eprintln!("failed to open file: {}", file_content.unwrap_err());
exit(1); exit(1);
}; };
if format_rust_code {
s = format_rust(&s)?;
}
let edits = dioxus_autofmt::fmt_file(&s, indent); let edits = dioxus_autofmt::fmt_file(&s, indent);
let out = dioxus_autofmt::apply_formats(&s, edits); let out = dioxus_autofmt::apply_formats(&s, edits);
@@ -94,50 +107,46 @@ fn refactor_file(file: String, split_line_attributes: bool) -> Result<(), Error>
Ok(()) Ok(())
} }
fn get_project_files(config: &CrateConfig) -> Vec<PathBuf> { use std::ffi::OsStr;
let mut files = vec![]; fn get_project_files() -> Vec<PathBuf> {
let mut files = Vec::new();
let gitignore_path = config.crate_dir.join(".gitignore"); for result in ignore::Walk::new("./") {
if gitignore_path.is_file() { let path = result.unwrap().into_path();
let gitigno = gitignore::File::new(gitignore_path.as_path()).unwrap(); if let Some(ext) = path.extension() {
if let Ok(git_files) = gitigno.included_files() { if ext == OsStr::new("rs") {
let git_files = git_files files.push(path);
.into_iter() }
.filter(|f| f.ends_with(".rs") && !is_target_dir(f)); }
files.extend(git_files)
};
} else {
collect_rs_files(&config.crate_dir, &mut files);
} }
files files
} }
fn is_target_dir(file: &Path) -> bool { fn format_file(
let stripped = if let Ok(cwd) = std::env::current_dir() {
file.strip_prefix(cwd).unwrap_or(file)
} else {
file
};
if let Some(first) = stripped.components().next() {
first.as_os_str() == "target"
} else {
false
}
}
async fn format_file(
path: impl AsRef<Path>, path: impl AsRef<Path>,
indent: IndentOptions, indent: IndentOptions,
) -> Result<usize, tokio::io::Error> { format_rust_code: bool,
let contents = tokio::fs::read_to_string(&path).await?; ) -> Result<usize> {
let mut contents = fs::read_to_string(&path)?;
let mut if_write = false;
if format_rust_code {
let formatted = format_rust(&contents)
.map_err(|err| Error::ParseError(format!("Syntax Error:\n{}", err)))?;
if contents != formatted {
if_write = true;
contents = formatted;
}
}
let edits = dioxus_autofmt::fmt_file(&contents, indent); let edits = dioxus_autofmt::fmt_file(&contents, indent);
let len = edits.len(); let len = edits.len();
if !edits.is_empty() { if !edits.is_empty() {
if_write = true;
}
if if_write {
let out = dioxus_autofmt::apply_formats(&contents, edits); let out = dioxus_autofmt::apply_formats(&contents, edits);
tokio::fs::write(path, out).await?; fs::write(path, out)?;
} }
Ok(len) Ok(len)
@@ -145,13 +154,15 @@ async fn format_file(
/// Read every .rs file accessible when considering the .gitignore and try to format it /// Read every .rs file accessible when considering the .gitignore and try to format it
/// ///
/// Runs using Tokio for multithreading, so it should be really really fast /// Runs using rayon for multithreading, so it should be really really fast
/// ///
/// Doesn't do mod-descending, so it will still try to format unreachable files. TODO. /// Doesn't do mod-descending, so it will still try to format unreachable files. TODO.
async fn autoformat_project(check: bool, split_line_attributes: bool) -> Result<()> { fn autoformat_project(
let crate_config = dioxus_cli_config::CrateConfig::new(None)?; check: bool,
split_line_attributes: bool,
let files_to_format = get_project_files(&crate_config); format_rust_code: bool,
) -> Result<()> {
let files_to_format = get_project_files();
if files_to_format.is_empty() { if files_to_format.is_empty() {
return Ok(()); return Ok(());
@@ -164,26 +175,18 @@ async fn autoformat_project(check: bool, split_line_attributes: bool) -> Result<
let indent = indentation_for(&files_to_format[0], split_line_attributes)?; let indent = indentation_for(&files_to_format[0], split_line_attributes)?;
let counts = files_to_format let counts = files_to_format
.into_iter() .into_par_iter()
.map(|path| async { .map(|path| {
let path_clone = path.clone(); let res = format_file(&path, indent.clone(), format_rust_code);
let res = tokio::spawn(format_file(path, indent.clone())).await;
match res { match res {
Ok(cnt) => Some(cnt),
Err(err) => { Err(err) => {
eprintln!("error formatting file: {}\n{err}", path_clone.display()); eprintln!("error formatting file : {}\n{:#?}", path.display(), err);
None None
} }
Ok(Err(err)) => {
eprintln!("error formatting file: {}\n{err}", path_clone.display());
None
}
Ok(Ok(res)) => Some(res),
} }
}) })
.collect::<FuturesUnordered<_>>() .collect::<Vec<_>>();
.collect::<Vec<_>>()
.await;
let files_formatted: usize = counts.into_iter().flatten().sum(); let files_formatted: usize = counts.into_iter().flatten().sum();
@@ -242,28 +245,21 @@ fn indentation_for(
)) ))
} }
fn collect_rs_files(folder: &impl AsRef<Path>, files: &mut Vec<PathBuf>) { /// Format rust code using prettyplease
if is_target_dir(folder.as_ref()) { fn format_rust(input: &str) -> Result<String> {
return; let syntax_tree = syn::parse_file(input).map_err(format_syn_error)?;
} let output = prettyplease::unparse(&syntax_tree);
let Ok(folder) = folder.as_ref().read_dir() else { Ok(output)
return; }
};
// load the gitignore fn format_syn_error(err: syn::Error) -> Error {
for entry in folder { let start = err.span().start();
let Ok(entry) = entry else { let line = start.line;
continue; let column = start.column;
}; Error::ParseError(format!(
let path = entry.path(); "Syntax Error in line {} column {}:\n{}",
if path.is_dir() { line, column, err
collect_rs_files(&path, files); ))
}
if let Some(ext) = path.extension() {
if ext == "rs" && !is_target_dir(&path) {
files.push(path);
}
}
}
} }
#[tokio::test] #[tokio::test]
@@ -284,13 +280,14 @@ async fn test_auto_fmt() {
.to_string(); .to_string();
let fmt = Autoformat { let fmt = Autoformat {
all_code: false,
check: false, check: false,
raw: Some(test_rsx), raw: Some(test_rsx),
file: None, file: None,
split_line_attributes: false, split_line_attributes: false,
}; };
fmt.autoformat().await.unwrap(); fmt.autoformat().unwrap();
} }
/*#[test] /*#[test]
-1
View File
@@ -70,7 +70,6 @@ async fn main() -> anyhow::Result<()> {
Autoformat(opts) => opts Autoformat(opts) => opts
.autoformat() .autoformat()
.await
.context(error_wrapper("Error autoformatting RSX")), .context(error_wrapper("Error autoformatting RSX")),
Check(opts) => opts Check(opts) => opts