1- use std:: fmt:: Display ;
2- use std:: fmt:: Formatter ;
3- use std:: io;
4- use std:: io:: Write ;
5- use std:: io:: stderr;
6- use std:: path:: Path ;
7- use std:: path:: PathBuf ;
8-
9- use colored:: Colorize ;
10- use fs:: relativize_path;
11- use itertools:: Either ;
12- use itertools:: Itertools ;
13- use thiserror:: Error ;
14- use workspace:: discovery:: DiscoveredSettings ;
15- use workspace:: discovery:: discover_r_file_paths;
16- use workspace:: discovery:: discover_settings;
17- use workspace:: format:: FormatFileError ;
18- use workspace:: format:: FormattedFile ;
19- use workspace:: format:: format_file;
20- use workspace:: resolve:: PathResolver ;
21- use workspace:: settings:: FormatSettings ;
22- use workspace:: settings:: Settings ;
23-
241use crate :: ExitStatus ;
252use crate :: args:: FormatCommand ;
263
4+ mod paths;
5+ mod stdin;
6+
277#[ derive( Copy , Clone , Debug ) ]
288enum FormatMode {
299 Write ,
3010 Check ,
3111}
3212
33- #[ derive( Error , Debug ) ]
34- enum FormatPathError {
35- FormatFile ( PathBuf , FormatFileError ) ,
36- Write ( PathBuf , io:: Error ) ,
37- Ignore ( #[ from] ignore:: Error ) ,
38- }
39-
4013pub ( crate ) fn format ( command : FormatCommand ) -> anyhow:: Result < ExitStatus > {
41- let mode = FormatMode :: from_command ( & command) ;
42-
43- let mut resolver = PathResolver :: new ( Settings :: default ( ) ) ;
44-
45- for DiscoveredSettings {
46- directory,
47- settings,
48- } in discover_settings ( & command. paths ) ?
49- {
50- resolver. add ( & directory, settings) ;
14+ if let Some ( status) = check_argument_consistency ( & command) {
15+ return Ok ( status) ;
5116 }
5217
53- match mode {
54- FormatMode :: Write => {
55- let errors = format_paths_write ( & command. paths , & resolver) ;
56-
57- for error in & errors {
58- tracing:: error!( "{error}" ) ;
59- }
60-
61- if errors. is_empty ( ) {
62- Ok ( ExitStatus :: Success )
63- } else {
64- Ok ( ExitStatus :: Error )
65- }
66- }
67- FormatMode :: Check => {
68- let ( paths, errors) = format_paths_check ( & command. paths , & resolver) ;
69-
70- for error in & errors {
71- tracing:: error!( "{error}" ) ;
72- }
18+ let mode = FormatMode :: from_command ( & command) ;
7319
74- inform_changed ( & paths, & mut stderr ( ) . lock ( ) ) ?;
20+ match command. stdin_file_path {
21+ Some ( path) => stdin:: format ( path, mode) ,
22+ None => paths:: format ( command. paths , mode) ,
23+ }
24+ }
7525
76- if errors. is_empty ( ) {
77- if paths. is_empty ( ) {
78- Ok ( ExitStatus :: Success )
79- } else {
80- Ok ( ExitStatus :: Failure )
81- }
82- } else {
83- Ok ( ExitStatus :: Error )
84- }
85- }
26+ fn check_argument_consistency ( command : & FormatCommand ) -> Option < ExitStatus > {
27+ if command. stdin_file_path . is_some ( ) && !command. paths . is_empty ( ) {
28+ tracing:: error!(
29+ "Can't supply paths when reading from stdin: {paths}" ,
30+ paths = command
31+ . paths
32+ . iter( )
33+ . map( |path| format!( "'{path}'" , path = path. display( ) ) )
34+ . collect:: <Vec <String >>( )
35+ . join( "," )
36+ ) ;
37+ return Some ( ExitStatus :: Error ) ;
8638 }
39+
40+ None
8741}
8842
8943impl FormatMode {
@@ -95,134 +49,3 @@ impl FormatMode {
9549 }
9650 }
9751}
98-
99- fn inform_changed ( paths : & [ PathBuf ] , f : & mut impl Write ) -> io:: Result < ( ) > {
100- for path in paths. iter ( ) . sorted_unstable ( ) {
101- writeln ! (
102- f,
103- "Would reformat: {path}" ,
104- path = relativize_path( path) . underline( )
105- ) ?;
106- }
107- Ok ( ( ) )
108- }
109-
110- fn format_paths_write < P : AsRef < Path > > (
111- paths : & [ P ] ,
112- resolver : & PathResolver < Settings > ,
113- ) -> Vec < FormatPathError > {
114- let paths = discover_r_file_paths ( paths, resolver, true ) ;
115-
116- paths
117- . into_iter ( )
118- . filter_map ( |path| match path {
119- Ok ( path) => {
120- let settings = resolver. resolve_or_fallback ( & path) ;
121- match format_path ( & path, & settings. format ) {
122- Ok ( file) => match write_path ( & path, file) {
123- Ok ( ( ) ) => None ,
124- Err ( err) => Some ( FormatPathError :: Write ( path, err) ) ,
125- } ,
126- Err ( err) => Some ( FormatPathError :: FormatFile ( path, err) ) ,
127- }
128- }
129- Err ( err) => Some ( err. into ( ) ) ,
130- } )
131- . collect ( )
132- }
133-
134- fn format_paths_check < P : AsRef < Path > > (
135- paths : & [ P ] ,
136- resolver : & PathResolver < Settings > ,
137- ) -> ( Vec < PathBuf > , Vec < FormatPathError > ) {
138- let paths = discover_r_file_paths ( paths, resolver, true ) ;
139-
140- paths
141- . into_iter ( )
142- . filter_map ( |path| match path {
143- Ok ( path) => {
144- let settings = resolver. resolve_or_fallback ( & path) ;
145- match format_path ( & path, & settings. format ) {
146- Ok ( file) => check_path ( path, file) . map ( Ok ) ,
147- Err ( err) => Some ( Err ( FormatPathError :: FormatFile ( path, err) ) ) ,
148- }
149- }
150- Err ( err) => Some ( Err ( err. into ( ) ) ) ,
151- } )
152- . partition_map ( |result| match result {
153- Ok ( result) => Either :: Left ( result) ,
154- Err ( err) => Either :: Right ( err) ,
155- } )
156- }
157-
158- fn format_path < P : AsRef < Path > > (
159- path : P ,
160- settings : & FormatSettings ,
161- ) -> std:: result:: Result < FormattedFile , FormatFileError > {
162- let path = path. as_ref ( ) ;
163- tracing:: trace!( "Formatting {path}" , path = path. display( ) ) ;
164- format_file ( path, settings)
165- }
166-
167- /// Returns `Ok(())` if the format results were successfully written back, otherwise
168- /// returns an error
169- fn write_path < P : AsRef < Path > > ( path : P , file : FormattedFile ) -> io:: Result < ( ) > {
170- match file {
171- FormattedFile :: Changed ( file) => std:: fs:: write ( path, file. new ( ) ) ,
172- FormattedFile :: Unchanged => Ok ( ( ) ) ,
173- }
174- }
175-
176- /// Returns `Some(path)` if a change occurred, otherwise returns `None`
177- fn check_path ( path : PathBuf , file : FormattedFile ) -> Option < PathBuf > {
178- match file {
179- FormattedFile :: Changed ( _) => Some ( path) ,
180- FormattedFile :: Unchanged => None ,
181- }
182- }
183-
184- impl Display for FormatPathError {
185- fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
186- match self {
187- Self :: FormatFile ( path, err) => match err {
188- FormatFileError :: Format ( err) => write ! (
189- f,
190- "Failed to format {path}: {err}" ,
191- path = relativize_path( path) . underline( ) ,
192- ) ,
193- FormatFileError :: Read ( err) => write ! (
194- f,
195- "Failed to read {path}: {err}" ,
196- path = relativize_path( path) . underline( ) ,
197- ) ,
198- } ,
199- Self :: Ignore ( err) => {
200- if let ignore:: Error :: WithPath { path, .. } = err {
201- write ! (
202- f,
203- "Failed to format {path}: {err}" ,
204- path = relativize_path( path) . underline( ) ,
205- err = err
206- . io_error( )
207- . map_or_else( || err. to_string( ) , std:: string:: ToString :: to_string)
208- )
209- } else {
210- write ! (
211- f,
212- "Encountered error: {err}" ,
213- err = err
214- . io_error( )
215- . map_or_else( || err. to_string( ) , std:: string:: ToString :: to_string)
216- )
217- }
218- }
219- Self :: Write ( path, err) => {
220- write ! (
221- f,
222- "Failed to write {path}: {err}" ,
223- path = relativize_path( path) . underline( ) ,
224- )
225- }
226- }
227- }
228- }
0 commit comments