@@ -78,6 +78,22 @@ pub enum OperationError {
7878 /// supported with stdandard input.
7979 #[ error( "Emit mode {0} not supported with standard output." ) ]
8080 StdinBadEmit ( EmitMode ) ,
81+ /// Using `--std-file-hint` incorrectly
82+ #[ error( "{0}" ) ]
83+ StdInFileHint ( StdInFileHintError ) ,
84+ }
85+
86+ #[ derive( Error , Debug ) ]
87+ pub enum StdInFileHintError {
88+ /// The file hint does not exist
89+ #[ error( "`--std-file-hint={0:?}` could not be found" ) ]
90+ NotFound ( PathBuf ) ,
91+ /// The file hint isn't a rust file
92+ #[ error( "`--std-file-hint={0:?}` is not a rust file" ) ]
93+ NotRustFile ( PathBuf ) ,
94+ /// Attempted to pass --std-file-hint without passing input through stdin
95+ #[ error( "Cannot use `--std-file-hint` without formatting input from stdin." ) ]
96+ NotFormttingWithStdIn ,
8197}
8298
8399impl From < IoError > for OperationError {
@@ -144,6 +160,14 @@ fn make_opts() -> Options {
144160 "Set options from command line. These settings take priority over .rustfmt.toml" ,
145161 "[key1=val1,key2=val2...]" ,
146162 ) ;
163+ opts. optopt (
164+ "" ,
165+ "stdin-file-hint" ,
166+ "Inform rustfmt that the text passed to stdin is from the given file. \
167+ This option can only be passed when formatting text via stdin, \
168+ and the file name is used to determine if rustfmt can skip formatting the input.",
169+ "[Path to a rust file.]" ,
170+ ) ;
147171
148172 if is_nightly {
149173 opts. optflag (
@@ -250,6 +274,11 @@ fn format_string(input: String, options: GetOptsOptions) -> Result<i32> {
250274 // try to read config from local directory
251275 let ( mut config, _) = load_config ( Some ( Path :: new ( "." ) ) , Some ( options. clone ( ) ) ) ?;
252276
277+ if rustfmt:: is_std_ignored ( options. stdin_file_hint , & config. ignore ( ) ) {
278+ io:: stdout ( ) . write_all ( input. as_bytes ( ) ) ?;
279+ return Ok ( 0 ) ;
280+ }
281+
253282 if options. check {
254283 config. set ( ) . emit_mode ( EmitMode :: Diff ) ;
255284 } else {
@@ -490,6 +519,13 @@ fn determine_operation(matches: &Matches) -> Result<Operation, OperationError> {
490519 return Ok ( Operation :: Stdin { input : buffer } ) ;
491520 }
492521
522+ // User's can only pass `--stdin-file-hint` when formating files via stdin.
523+ if matches. opt_present ( "stdin-file-hint" ) {
524+ return Err ( OperationError :: StdInFileHint (
525+ StdInFileHintError :: NotFormttingWithStdIn ,
526+ ) ) ;
527+ }
528+
493529 Ok ( Operation :: Format {
494530 files,
495531 minimal_config_path,
@@ -515,6 +551,7 @@ struct GetOptsOptions {
515551 unstable_features : bool ,
516552 error_on_unformatted : Option < bool > ,
517553 print_misformatted_file_names : bool ,
554+ stdin_file_hint : Option < PathBuf > ,
518555}
519556
520557impl GetOptsOptions {
@@ -564,6 +601,20 @@ impl GetOptsOptions {
564601 }
565602
566603 options. config_path = matches. opt_str ( "config-path" ) . map ( PathBuf :: from) ;
604+ options. stdin_file_hint = matches. opt_str ( "stdin-file-hint" ) . map ( PathBuf :: from) ;
605+
606+ // return early if there are issues with the file hint specified
607+ if let Some ( file_hint) = & options. stdin_file_hint {
608+ if !file_hint. exists ( ) {
609+ return Err ( StdInFileHintError :: NotFound ( file_hint. to_owned ( ) ) ) ?;
610+ }
611+
612+ if let Some ( ext) = file_hint. extension ( ) {
613+ if ext != "rs" {
614+ return Err ( StdInFileHintError :: NotRustFile ( file_hint. to_owned ( ) ) ) ?;
615+ }
616+ }
617+ }
567618
568619 options. inline_config = matches
569620 . opt_strs ( "config" )
0 commit comments