11mod args;
22mod check;
33mod files;
4+ mod fix;
45
56use anyhow:: Result ;
67use clap:: Parser ;
@@ -13,7 +14,8 @@ use std::sync::{
1314} ;
1415
1516use crate :: args:: Args ;
16- use crate :: files:: { FileIssues , find_files, process_file} ;
17+ use crate :: files:: { FileIssues , find_files, process_file, should_exclude} ;
18+ use crate :: fix:: fix_file;
1719
1820#[ derive( Debug , Serialize , Deserialize ) ]
1921struct LintResult {
@@ -28,8 +30,29 @@ struct Summary {
2830 total_issues : usize ,
2931}
3032
33+ #[ derive( Debug , Serialize , Deserialize ) ]
34+ struct FixResult {
35+ files : HashMap < String , FixedFileInfo > ,
36+ summary : FixSummary ,
37+ }
38+
39+ #[ derive( Debug , Clone , Serialize , Deserialize ) ]
40+ struct FixedFileInfo {
41+ trailing_whitespace_fixed : usize ,
42+ tabs_converted : usize ,
43+ final_newline_added : bool ,
44+ }
45+
46+ #[ derive( Debug , Serialize , Deserialize ) ]
47+ struct FixSummary {
48+ total_files : usize ,
49+ files_fixed : usize ,
50+ total_fixes : usize ,
51+ }
52+
3153fn main ( ) -> Result < ( ) > {
3254 let args = Args :: parse ( ) ;
55+
3356 let mut all_files = Vec :: new ( ) ;
3457 for path in & args. paths {
3558 if !path. exists ( ) {
@@ -44,8 +67,72 @@ fn main() -> Result<()> {
4467 return Ok ( ( ) ) ;
4568 }
4669
70+ if args. fix {
71+ let mut fixed_files = HashMap :: new ( ) ;
72+ let mut error_count = 0 ;
73+ let mut total_files_checked = 0 ;
74+
75+ for file in & all_files {
76+ if should_exclude ( file) {
77+ continue ;
78+ }
79+
80+ total_files_checked += 1 ;
81+
82+ match fix_file ( file) {
83+ Ok ( Some ( result) ) => {
84+ fixed_files. insert (
85+ file. display ( ) . to_string ( ) ,
86+ FixedFileInfo {
87+ trailing_whitespace_fixed : result. trailing_whitespace_fixed ,
88+ tabs_converted : result. tabs_converted ,
89+ final_newline_added : result. final_newline_added ,
90+ } ,
91+ ) ;
92+ }
93+ Ok ( None ) => {
94+ // No fixes needed for this file
95+ }
96+ Err ( e) => {
97+ eprintln ! ( "Error fixing {}: {}" , file. display( ) , e) ;
98+ error_count += 1 ;
99+ }
100+ }
101+ }
102+
103+ if error_count > 0 {
104+ std:: process:: exit ( 1 ) ;
105+ }
106+
107+ if !fixed_files. is_empty ( ) {
108+ let files_fixed = fixed_files. len ( ) ;
109+ let total_fixes: usize = fixed_files
110+ . values ( )
111+ . map ( |f| {
112+ f. trailing_whitespace_fixed
113+ + f. tabs_converted
114+ + if f. final_newline_added { 1 } else { 0 }
115+ } )
116+ . sum ( ) ;
117+
118+ let result = FixResult {
119+ files : fixed_files,
120+ summary : FixSummary {
121+ total_files : total_files_checked,
122+ files_fixed,
123+ total_fixes,
124+ } ,
125+ } ;
126+
127+ println ! ( "{}" , serde_json:: to_string_pretty( & result) ?) ;
128+ }
129+
130+ return Ok ( ( ) ) ;
131+ }
132+
47133 let file_issues = Mutex :: new ( HashMap :: new ( ) ) ;
48134 let had_error = AtomicBool :: new ( false ) ;
135+
49136 all_files
50137 . par_iter ( )
51138 . for_each ( |file| match process_file ( file) {
@@ -61,8 +148,6 @@ fn main() -> Result<()> {
61148 } ) ;
62149
63150 let files = file_issues. into_inner ( ) . unwrap ( ) ;
64-
65- // Calculate summary
66151 let total_files = all_files. len ( ) ;
67152 let files_with_issues = files. len ( ) ;
68153 let total_issues: usize = files. values ( ) . map ( |f| f. total_issues ( ) ) . sum ( ) ;
@@ -76,13 +161,9 @@ fn main() -> Result<()> {
76161 } ,
77162 } ;
78163
79- // Output JSON
80164 println ! ( "{}" , serde_json:: to_string_pretty( & result) ?) ;
81-
82- // Exit with non-zero status if there were issues
83165 if files_with_issues > 0 || had_error. load ( Ordering :: Relaxed ) {
84166 std:: process:: exit ( 1 ) ;
85167 }
86-
87168 Ok ( ( ) )
88169}
0 commit comments