|
@@ -27,15 +27,17 @@ pub struct Autoformat {
|
|
impl Autoformat {
|
|
impl Autoformat {
|
|
// Todo: autoformat the entire crate
|
|
// Todo: autoformat the entire crate
|
|
pub async fn autoformat(self) -> Result<()> {
|
|
pub async fn autoformat(self) -> Result<()> {
|
|
|
|
+ let Autoformat { check, raw, file } = self;
|
|
|
|
+
|
|
// Default to formatting the project
|
|
// Default to formatting the project
|
|
- if self.raw.is_none() && self.file.is_none() {
|
|
|
|
- if let Err(e) = autoformat_project(self.check).await {
|
|
|
|
|
|
+ if raw.is_none() && file.is_none() {
|
|
|
|
+ if let Err(e) = autoformat_project(check).await {
|
|
eprintln!("error formatting project: {}", e);
|
|
eprintln!("error formatting project: {}", e);
|
|
exit(1);
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if let Some(raw) = self.raw {
|
|
|
|
|
|
+ if let Some(raw) = raw {
|
|
let indent = indentation_for(".")?;
|
|
let indent = indentation_for(".")?;
|
|
if let Some(inner) = dioxus_autofmt::fmt_block(&raw, 0, indent) {
|
|
if let Some(inner) = dioxus_autofmt::fmt_block(&raw, 0, indent) {
|
|
println!("{}", inner);
|
|
println!("{}", inner);
|
|
@@ -47,47 +49,90 @@ impl Autoformat {
|
|
}
|
|
}
|
|
|
|
|
|
// Format single file
|
|
// Format single file
|
|
- if let Some(file) = self.file {
|
|
|
|
- let file_content;
|
|
|
|
- let indent;
|
|
|
|
- if file == "-" {
|
|
|
|
- indent = indentation_for(".")?;
|
|
|
|
- let mut contents = String::new();
|
|
|
|
- std::io::stdin().read_to_string(&mut contents)?;
|
|
|
|
- file_content = Ok(contents);
|
|
|
|
- } else {
|
|
|
|
- indent = indentation_for(".")?;
|
|
|
|
- file_content = fs::read_to_string(&file);
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- match file_content {
|
|
|
|
- Ok(s) => {
|
|
|
|
- let edits = dioxus_autofmt::fmt_file(&s, indent);
|
|
|
|
- let out = dioxus_autofmt::apply_formats(&s, edits);
|
|
|
|
- if file == "-" {
|
|
|
|
- print!("{}", out);
|
|
|
|
- } else {
|
|
|
|
- match fs::write(&file, out) {
|
|
|
|
- Ok(_) => {
|
|
|
|
- println!("formatted {}", file);
|
|
|
|
- }
|
|
|
|
- Err(e) => {
|
|
|
|
- eprintln!("failed to write formatted content to file: {}", e);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- Err(e) => {
|
|
|
|
- eprintln!("failed to open file: {}", e);
|
|
|
|
- exit(1);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ if let Some(file) = file {
|
|
|
|
+ refactor_file(file)?;
|
|
}
|
|
}
|
|
|
|
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+fn refactor_file(file: String) -> Result<(), Error> {
|
|
|
|
+ let indent = indentation_for(".")?;
|
|
|
|
+ let file_content = if file == "-" {
|
|
|
|
+ let mut contents = String::new();
|
|
|
|
+ std::io::stdin().read_to_string(&mut contents)?;
|
|
|
|
+ Ok(contents)
|
|
|
|
+ } else {
|
|
|
|
+ fs::read_to_string(&file)
|
|
|
|
+ };
|
|
|
|
+ let Ok(s) = file_content else {
|
|
|
|
+ eprintln!("failed to open file: {}", file_content.unwrap_err());
|
|
|
|
+ exit(1);
|
|
|
|
+ };
|
|
|
|
+ let edits = dioxus_autofmt::fmt_file(&s, indent);
|
|
|
|
+ let out = dioxus_autofmt::apply_formats(&s, edits);
|
|
|
|
+
|
|
|
|
+ if file == "-" {
|
|
|
|
+ print!("{}", out);
|
|
|
|
+ } else if let Err(e) = fs::write(&file, out) {
|
|
|
|
+ eprintln!("failed to write formatted content to file: {e}",);
|
|
|
|
+ } else {
|
|
|
|
+ println!("formatted {}", file);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Ok(())
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+fn get_project_files(config: &CrateConfig) -> Vec<PathBuf> {
|
|
|
|
+ let mut files = vec![];
|
|
|
|
+
|
|
|
|
+ let gitignore_path = config.crate_dir.join(".gitignore");
|
|
|
|
+ if gitignore_path.is_file() {
|
|
|
|
+ let gitigno = gitignore::File::new(gitignore_path.as_path()).unwrap();
|
|
|
|
+ if let Ok(git_files) = gitigno.included_files() {
|
|
|
|
+ let git_files = git_files
|
|
|
|
+ .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
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+fn is_target_dir(file: &Path) -> bool {
|
|
|
|
+ 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>,
|
|
|
|
+ indent: IndentOptions,
|
|
|
|
+) -> Result<usize, tokio::io::Error> {
|
|
|
|
+ let contents = tokio::fs::read_to_string(&path).await?;
|
|
|
|
+
|
|
|
|
+ let edits = dioxus_autofmt::fmt_file(&contents, indent);
|
|
|
|
+ let len = edits.len();
|
|
|
|
+
|
|
|
|
+ if !edits.is_empty() {
|
|
|
|
+ let out = dioxus_autofmt::apply_formats(&contents, edits);
|
|
|
|
+ tokio::fs::write(path, out).await?;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Ok(len)
|
|
|
|
+}
|
|
|
|
+
|
|
/// 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 Tokio for multithreading, so it should be really really fast
|
|
@@ -96,8 +141,7 @@ impl Autoformat {
|
|
async fn autoformat_project(check: bool) -> Result<()> {
|
|
async fn autoformat_project(check: bool) -> Result<()> {
|
|
let crate_config = crate::CrateConfig::new(None)?;
|
|
let crate_config = crate::CrateConfig::new(None)?;
|
|
|
|
|
|
- let mut files_to_format = vec![];
|
|
|
|
- collect_rs_files(&crate_config.crate_dir, &mut files_to_format);
|
|
|
|
|
|
+ let files_to_format = get_project_files(&crate_config);
|
|
|
|
|
|
if files_to_format.is_empty() {
|
|
if files_to_format.is_empty() {
|
|
return Ok(());
|
|
return Ok(());
|
|
@@ -107,38 +151,17 @@ async fn autoformat_project(check: bool) -> Result<()> {
|
|
|
|
|
|
let counts = files_to_format
|
|
let counts = files_to_format
|
|
.into_iter()
|
|
.into_iter()
|
|
- .filter(|file| {
|
|
|
|
- if file.components().any(|f| f.as_os_str() == "target") {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- true
|
|
|
|
- })
|
|
|
|
.map(|path| async {
|
|
.map(|path| async {
|
|
- let _path = path.clone();
|
|
|
|
- let _indent = indent.clone();
|
|
|
|
- let res = tokio::spawn(async move {
|
|
|
|
- let contents = tokio::fs::read_to_string(&path).await?;
|
|
|
|
-
|
|
|
|
- let edits = dioxus_autofmt::fmt_file(&contents, _indent.clone());
|
|
|
|
- let len = edits.len();
|
|
|
|
-
|
|
|
|
- if !edits.is_empty() {
|
|
|
|
- let out = dioxus_autofmt::apply_formats(&contents, edits);
|
|
|
|
- tokio::fs::write(&path, out).await?;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- Ok(len) as Result<usize, tokio::io::Error>
|
|
|
|
- })
|
|
|
|
- .await;
|
|
|
|
|
|
+ let path_clone = path.clone();
|
|
|
|
+ let res = tokio::spawn(format_file(path, indent.clone())).await;
|
|
|
|
|
|
match res {
|
|
match res {
|
|
Err(err) => {
|
|
Err(err) => {
|
|
- eprintln!("error formatting file: {}\n{err}", _path.display());
|
|
|
|
|
|
+ eprintln!("error formatting file: {}\n{err}", path_clone.display());
|
|
None
|
|
None
|
|
}
|
|
}
|
|
Ok(Err(err)) => {
|
|
Ok(Err(err)) => {
|
|
- eprintln!("error formatting file: {}\n{err}", _path.display());
|
|
|
|
|
|
+ eprintln!("error formatting file: {}\n{err}", path_clone.display());
|
|
None
|
|
None
|
|
}
|
|
}
|
|
Ok(Ok(res)) => Some(res),
|
|
Ok(Ok(res)) => Some(res),
|
|
@@ -148,13 +171,7 @@ async fn autoformat_project(check: bool) -> Result<()> {
|
|
.collect::<Vec<_>>()
|
|
.collect::<Vec<_>>()
|
|
.await;
|
|
.await;
|
|
|
|
|
|
- let files_formatted: usize = counts
|
|
|
|
- .into_iter()
|
|
|
|
- .map(|f| match f {
|
|
|
|
- Some(res) => res,
|
|
|
|
- _ => 0,
|
|
|
|
- })
|
|
|
|
- .sum();
|
|
|
|
|
|
+ let files_formatted: usize = counts.into_iter().flatten().sum();
|
|
|
|
|
|
if files_formatted > 0 && check {
|
|
if files_formatted > 0 && check {
|
|
eprintln!("{} files needed formatting", files_formatted);
|
|
eprintln!("{} files needed formatting", files_formatted);
|
|
@@ -207,26 +224,24 @@ fn indentation_for(file_or_dir: impl AsRef<Path>) -> Result<IndentOptions> {
|
|
))
|
|
))
|
|
}
|
|
}
|
|
|
|
|
|
-fn collect_rs_files(folder: &Path, files: &mut Vec<PathBuf>) {
|
|
|
|
- let Ok(folder) = folder.read_dir() else {
|
|
|
|
|
|
+fn collect_rs_files(folder: &impl AsRef<Path>, files: &mut Vec<PathBuf>) {
|
|
|
|
+ if is_target_dir(folder.as_ref()) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ let Ok(folder) = folder.as_ref().read_dir() else {
|
|
return;
|
|
return;
|
|
};
|
|
};
|
|
-
|
|
|
|
// load the gitignore
|
|
// load the gitignore
|
|
-
|
|
|
|
for entry in folder {
|
|
for entry in folder {
|
|
let Ok(entry) = entry else {
|
|
let Ok(entry) = entry else {
|
|
continue;
|
|
continue;
|
|
};
|
|
};
|
|
-
|
|
|
|
let path = entry.path();
|
|
let path = entry.path();
|
|
-
|
|
|
|
if path.is_dir() {
|
|
if path.is_dir() {
|
|
collect_rs_files(&path, files);
|
|
collect_rs_files(&path, files);
|
|
}
|
|
}
|
|
-
|
|
|
|
if let Some(ext) = path.extension() {
|
|
if let Some(ext) = path.extension() {
|
|
- if ext == "rs" {
|
|
|
|
|
|
+ if ext == "rs" && !is_target_dir(&path) {
|
|
files.push(path);
|
|
files.push(path);
|
|
}
|
|
}
|
|
}
|
|
}
|