@@ -20,6 +20,9 @@ use clap::{ArgMatches, Command, Error};
2020use std:: error:: Error as StdError ;
2121use std:: ffi:: OsString ;
2222
23+ use std:: io:: Write as _;
24+ use std:: io:: stderr;
25+
2326/// Color enum for consistent styling
2427#[ derive( Debug , Clone , Copy ) ]
2528pub enum Color {
@@ -66,7 +69,7 @@ struct ColorManager(bool);
6669impl ColorManager {
6770 /// Create a new ColorManager based on environment variables
6871 fn from_env ( ) -> Self {
69- Self ( should_use_color_for_stream ( & std :: io :: stderr ( ) ) )
72+ Self ( should_use_color_for_stream ( & stderr ( ) ) )
7073 }
7174
7275 /// Apply color to text if colors are enabled
@@ -124,7 +127,7 @@ impl<'a> ErrorFormatter<'a> {
124127 ErrorKind :: MissingRequiredArgument => self . handle_missing_required ( err, exit_code) ,
125128 ErrorKind :: TooFewValues | ErrorKind :: TooManyValues | ErrorKind :: WrongNumberOfValues => {
126129 // These need full clap formatting
127- eprint ! ( "{}" , err. render( ) ) ;
130+ let _ = write ! ( stderr ( ) , "{}" , err. render( ) ) ;
128131 exit_code
129132 }
130133 _ => self . handle_generic_error ( err, exit_code) ,
@@ -144,28 +147,28 @@ impl<'a> ErrorFormatter<'a> {
144147 let error_word = translate ! ( "common-error" ) ;
145148
146149 // Print main error
147- eprintln ! (
148- "{}" ,
150+ let _ = write ! (
151+ stderr( ) ,
152+ "{}\n \n " ,
149153 translate!(
150154 "clap-error-unexpected-argument" ,
151155 "arg" => self . color_mgr. colorize( & arg_str, Color :: Yellow ) ,
152156 "error_word" => self . color_mgr. colorize( & error_word, Color :: Red )
153157 )
154158 ) ;
155- eprintln ! ( ) ;
156159
157160 // Show suggestion if available
158161 if let Some ( suggested_arg) = err. get ( ContextKind :: SuggestedArg ) {
159162 let tip_word = translate ! ( "common-tip" ) ;
160- eprintln ! (
161- "{}" ,
163+ let _ = write ! (
164+ stderr( ) ,
165+ "{}\n \n " ,
162166 translate!(
163167 "clap-error-similar-argument" ,
164168 "tip_word" => self . color_mgr. colorize( & tip_word, Color :: Green ) ,
165169 "suggestion" => self . color_mgr. colorize( & suggested_arg. to_string( ) , Color :: Green )
166170 )
167171 ) ;
168- eprintln ! ( ) ;
169172 } else {
170173 // Look for other tips from clap
171174 self . print_clap_tips ( err) ;
@@ -190,7 +193,8 @@ impl<'a> ErrorFormatter<'a> {
190193 if value. is_empty ( ) {
191194 // Value required but not provided
192195 let error_word = translate ! ( "common-error" ) ;
193- eprintln ! (
196+ let _ = writeln ! (
197+ stderr( ) ,
194198 "{}" ,
195199 translate!( "clap-error-value-required" ,
196200 "error_word" => self . color_mgr. colorize( & error_word, Color :: Red ) ,
@@ -208,7 +212,7 @@ impl<'a> ErrorFormatter<'a> {
208212 // Include validation error if present
209213 match err. source ( ) {
210214 Some ( source) if matches ! ( err. kind( ) , ErrorKind :: ValueValidation ) => {
211- eprintln ! ( "{error_msg}: {source}" ) ;
215+ let _ = writeln ! ( stderr ( ) , "{error_msg}: {source}" ) ;
212216 }
213217 _ => eprintln ! ( "{error_msg}" ) ,
214218 }
@@ -218,17 +222,15 @@ impl<'a> ErrorFormatter<'a> {
218222 if matches ! ( err. kind( ) , ErrorKind :: InvalidValue ) {
219223 if let Some ( valid_values) = err. get ( ContextKind :: ValidValue ) {
220224 if !valid_values. to_string ( ) . is_empty ( ) {
221- eprintln ! ( ) ;
222- eprintln ! (
223- " [{}: {valid_values}]" ,
225+ let _ = writeln ! (
226+ stderr ( ) ,
227+ "\n [{}: {valid_values}]" ,
224228 translate!( "clap-error-possible-values" )
225229 ) ;
226230 }
227231 }
228232 }
229-
230- eprintln ! ( ) ;
231- eprintln ! ( "{}" , translate!( "common-help-suggestion" ) ) ;
233+ let _ = writeln ! ( stderr( ) , "\n {}" , translate!( "common-help-suggestion" ) ) ;
232234 } else {
233235 self . print_simple_error_msg ( & err. render ( ) . to_string ( ) ) ;
234236 }
@@ -255,7 +257,8 @@ impl<'a> ErrorFormatter<'a> {
255257 . starts_with ( "error: the following required arguments were not provided:" ) =>
256258 {
257259 let error_word = translate ! ( "common-error" ) ;
258- eprintln ! (
260+ let _ = writeln ! (
261+ stderr( ) ,
259262 "{}" ,
260263 translate!(
261264 "clap-error-missing-required-arguments" ,
@@ -266,23 +269,23 @@ impl<'a> ErrorFormatter<'a> {
266269 // Print the missing arguments
267270 for line in lines. iter ( ) . skip ( 1 ) {
268271 if line. starts_with ( " " ) {
269- eprintln ! ( "{line}" ) ;
272+ let _ = writeln ! ( stderr ( ) , "{line}" ) ;
270273 } else if line. starts_with ( "Usage:" ) || line. starts_with ( "For more information" )
271274 {
272275 break ;
273276 }
274277 }
275- eprintln ! ( ) ;
278+ let _ = write ! ( stderr ( ) , " \n " ) ;
276279
277280 // Print usage
278281 lines
279282 . iter ( )
280283 . skip_while ( |line| !line. starts_with ( "Usage:" ) )
281284 . for_each ( |line| {
282285 if line. starts_with ( "For more information, try '--help'." ) {
283- eprintln ! ( "{}" , translate!( "common-help-suggestion" ) ) ;
286+ let _ = writeln ! ( stderr ( ) , "{}" , translate!( "common-help-suggestion" ) ) ;
284287 } else {
285- eprintln ! ( "{line}" ) ;
288+ let _ = writeln ! ( stderr ( ) , "{line}" ) ;
286289 }
287290 } ) ;
288291 }
@@ -296,18 +299,18 @@ impl<'a> ErrorFormatter<'a> {
296299 let rendered_str = err. render ( ) . to_string ( ) ;
297300 if let Some ( main_error_line) = rendered_str. lines ( ) . next ( ) {
298301 self . print_localized_error_line ( main_error_line) ;
299- eprintln ! ( ) ;
300- eprintln ! ( "{}" , translate!( "common-help-suggestion" ) ) ;
302+ let _ = writeln ! ( stderr( ) , "\n {}" , translate!( "common-help-suggestion" ) ) ;
301303 } else {
302- eprint ! ( "{}" , err. render( ) ) ;
304+ let _ = write ! ( stderr ( ) , "{}" , err. render( ) ) ;
303305 }
304306 exit_code
305307 }
306308
307309 /// Print a simple error message (no exit)
308310 fn print_simple_error_msg ( & self , message : & str ) {
309311 let error_word = translate ! ( "common-error" ) ;
310- eprintln ! (
312+ let _ = writeln ! (
313+ stderr( ) ,
311314 "{}: {message}" ,
312315 self . color_mgr. colorize( & error_word, Color :: Red )
313316 ) ;
@@ -320,9 +323,9 @@ impl<'a> ErrorFormatter<'a> {
320323
321324 if let Some ( colon_pos) = line. find ( ':' ) {
322325 let after_colon = & line[ colon_pos..] ;
323- eprintln ! ( "{colored_error}{after_colon}" ) ;
326+ let _ = writeln ! ( stderr ( ) , "{colored_error}{after_colon}" ) ;
324327 } else {
325- eprintln ! ( "{line}" ) ;
328+ let _ = writeln ! ( stderr ( ) , "{line}" ) ;
326329 }
327330 }
328331
@@ -335,14 +338,15 @@ impl<'a> ErrorFormatter<'a> {
335338 let tip_word = translate ! ( "common-tip" ) ;
336339 if let Some ( colon_pos) = trimmed. find ( ':' ) {
337340 let after_colon = & trimmed[ colon_pos..] ;
338- eprintln ! (
341+ let _ = writeln ! (
342+ stderr( ) ,
339343 " {}{after_colon}" ,
340344 self . color_mgr. colorize( & tip_word, Color :: Green )
341345 ) ;
342346 } else {
343- eprintln ! ( "{line}" ) ;
347+ let _ = writeln ! ( stderr ( ) , "{line}" ) ;
344348 }
345- eprintln ! ( ) ;
349+ let _ = write ! ( stderr ( ) , " \n " ) ;
346350 }
347351 }
348352 }
@@ -353,9 +357,11 @@ impl<'a> ErrorFormatter<'a> {
353357 let usage_text = translate ! ( & usage_key) ;
354358 let formatted_usage = crate :: format_usage ( & usage_text) ;
355359 let usage_label = translate ! ( "common-usage" ) ;
356- eprintln ! ( "{usage_label}: {formatted_usage}" ) ;
357- eprintln ! ( ) ;
358- eprintln ! ( "{}" , translate!( "common-help-suggestion" ) ) ;
360+ let _ = writeln ! (
361+ stderr( ) ,
362+ "{usage_label}: {formatted_usage}\n \n {}" ,
363+ translate!( "common-help-suggestion" )
364+ ) ;
359365 }
360366}
361367
@@ -609,7 +615,7 @@ mod tests {
609615 env:: set_var ( "NO_COLOR" , "1" ) ;
610616 }
611617 assert_eq ! ( get_color_choice( ) , clap:: ColorChoice :: Never ) ;
612- assert ! ( !should_use_color_for_stream( & std :: io :: stderr( ) ) ) ;
618+ assert ! ( !should_use_color_for_stream( & stderr( ) ) ) ;
613619 let mgr = ColorManager :: from_env ( ) ;
614620 assert ! ( !mgr. 0 ) ;
615621 unsafe {
@@ -621,7 +627,7 @@ mod tests {
621627 env:: set_var ( "CLICOLOR_FORCE" , "1" ) ;
622628 }
623629 assert_eq ! ( get_color_choice( ) , clap:: ColorChoice :: Always ) ;
624- assert ! ( should_use_color_for_stream( & std :: io :: stderr( ) ) ) ;
630+ assert ! ( should_use_color_for_stream( & stderr( ) ) ) ;
625631 let mgr = ColorManager :: from_env ( ) ;
626632 assert ! ( mgr. 0 ) ;
627633 unsafe {
@@ -633,7 +639,7 @@ mod tests {
633639 env:: set_var ( "FORCE_COLOR" , "1" ) ;
634640 }
635641 assert_eq ! ( get_color_choice( ) , clap:: ColorChoice :: Always ) ;
636- assert ! ( should_use_color_for_stream( & std :: io :: stderr( ) ) ) ;
642+ assert ! ( should_use_color_for_stream( & stderr( ) ) ) ;
637643 unsafe {
638644 env:: remove_var ( "FORCE_COLOR" ) ;
639645 }
0 commit comments