Skip to content

Commit 2e552d8

Browse files
committed
Add support for formatting multiple files at once
Close #75
1 parent 13e9545 commit 2e552d8

1 file changed

Lines changed: 69 additions & 35 deletions

File tree

src/main.rs

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use std::{
22
env, fs,
3-
io::{self, IsTerminal, Read},
3+
io::{self, IsTerminal, Write},
44
path::PathBuf,
55
};
66

77
use clap::{CommandFactory, Parser};
88

9-
use gdscript_formatter::{formatter::format_gdscript_with_config, FormatterConfig};
9+
use gdscript_formatter::{FormatterConfig, formatter::format_gdscript_with_config};
1010

1111
#[derive(Parser)]
1212
#[clap(
@@ -19,14 +19,16 @@ use gdscript_formatter::{formatter::format_gdscript_with_config, FormatterConfig
1919
)]
2020
struct Args {
2121
#[arg(
22-
help = "Input GDScript file to format. If no file path is provided, the program reads from standard input and outputs to standard output.",
23-
value_name = "FILE"
22+
help = "Input GDScript file(s) to format. If no file path is provided, the program reads from standard input and outputs to standard output.",
23+
value_name = "FILES"
2424
)]
25-
input: Option<PathBuf>,
25+
input: Vec<PathBuf>,
2626
#[arg(
2727
long,
2828
help = "Output formatted code to stdout instead of overwriting the input file. \
29-
This flag is ignored when reading from stdin (stdout is always used)"
29+
If multiple input files are provided, each file's content is preceded by a comment indicating the file name, with the form \
30+
#--file:<file_path> \
31+
This flag is ignored when reading from stdin (stdout is always used)."
3032
)]
3133
stdout: bool,
3234
#[arg(
@@ -77,47 +79,79 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
7779

7880
let args = Args::parse();
7981

80-
let input_content = match &args.input {
81-
Some(file_path) => fs::read_to_string(file_path)
82-
.map_err(|e| format!("Failed to read file {}: {}", file_path.display(), e))?,
83-
None => {
84-
let mut buffer = String::new();
85-
io::stdin()
86-
.read_to_string(&mut buffer)
87-
.map_err(|e| format!("Failed to read from stdin: {}", e))?;
88-
buffer
89-
}
90-
};
91-
9282
let config = FormatterConfig {
9383
indent_size: args.indent_size,
9484
use_spaces: args.use_spaces,
9585
reorder_code: args.reorder_code,
9686
safe: args.safe,
9787
};
9888

99-
let formatted_content = format_gdscript_with_config(&input_content, &config)?;
89+
let input_gdscript_files: Vec<&PathBuf> = args
90+
.input
91+
.iter()
92+
.filter(|path| path.extension().map_or(false, |ext| ext == "gd"))
93+
.collect();
10094

101-
if args.check {
102-
if input_content != formatted_content {
103-
eprintln!("The file is not formatted");
104-
std::process::exit(1);
105-
}
106-
println!("File is formatted");
107-
} else {
108-
match (args.input.as_ref(), args.stdout) {
109-
// If we're reading from a file without the --stdout flag: we overwrite the input file
110-
(Some(input_file), false) => {
111-
fs::write(input_file, formatted_content).map_err(|e| {
112-
format!("Failed to write to file {}: {}", input_file.display(), e)
113-
})?;
95+
if input_gdscript_files.is_empty() {
96+
eprintln!(
97+
"Error: No GDScript files found in the arguments provided. Please provide at least one .gd file."
98+
);
99+
std::process::exit(1);
100+
}
101+
102+
let total_files = input_gdscript_files.len();
103+
let mut all_formatted = true;
104+
105+
for (index, file_path) in input_gdscript_files.iter().enumerate() {
106+
let file_number = index + 1;
107+
terminal_clear_line();
108+
print!("\rFormatting file {}/{}", file_number, total_files);
109+
io::stdout().flush().unwrap();
110+
111+
let input_content = fs::read_to_string(file_path)
112+
.map_err(|error| format!("Failed to read file {}: {}", file_path.display(), error))?;
113+
114+
let formatted_content = format_gdscript_with_config(&input_content, &config)?;
115+
116+
if args.check {
117+
if input_content != formatted_content {
118+
all_formatted = false;
114119
}
115-
// Otherwise we output to stdout
116-
_ => {
117-
print!("{}", formatted_content);
120+
} else if args.stdout {
121+
// Clear the current line before printing formatted files to stdout, to erase the "Formatting file ..." message
122+
terminal_clear_line();
123+
// If there are multiple input files we still allow stdout but we print a separator
124+
if total_files > 1 {
125+
println!("#--file:{}", file_path.display());
118126
}
127+
print!("{}", formatted_content);
128+
} else {
129+
fs::write(file_path, formatted_content)
130+
.map_err(|e| format!("Failed to write to file {}: {}", file_path.display(), e))?;
119131
}
120132
}
121133

134+
if args.check {
135+
if all_formatted {
136+
terminal_clear_line();
137+
println!("\rAll {} file(s) are formatted", total_files);
138+
} else {
139+
terminal_clear_line();
140+
eprintln!("\rSome files are not formatted");
141+
std::process::exit(1);
142+
}
143+
} else if !args.stdout {
144+
terminal_clear_line();
145+
println!(
146+
"\rFormatted {} file{}",
147+
total_files,
148+
if total_files == 1 { "" } else { "s" }
149+
);
150+
}
151+
122152
Ok(())
123153
}
154+
155+
fn terminal_clear_line() {
156+
print!("\r{}", " ".repeat(80));
157+
}

0 commit comments

Comments
 (0)