@@ -219,6 +219,35 @@ struct ReportFormatter<'a>(&'a dyn crate::Error);
219219
220220impl < ' a > fmt:: Display for ReportFormatter < ' a > {
221221 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
222+ #[ cfg( feature = "std" ) ]
223+ {
224+ if trace_cleaning_enabled ( ) {
225+ self . cleaned_error_trace ( f) ?;
226+ } else {
227+ self . error_trace ( f) ?;
228+ }
229+ }
230+
231+ #[ cfg( not( feature = "std" ) ) ]
232+ {
233+ self . error_trace ( f) ?;
234+ }
235+
236+ #[ cfg( feature = "unstable-provider-api" ) ]
237+ {
238+ use core:: any;
239+
240+ if let Some ( bt) = any:: request_ref :: < crate :: Backtrace > ( self . 0 ) {
241+ writeln ! ( f, "\n Backtrace:\n {}" , bt) ?;
242+ }
243+ }
244+
245+ Ok ( ( ) )
246+ }
247+ }
248+
249+ impl < ' a > ReportFormatter < ' a > {
250+ fn error_trace ( & self , f : & mut fmt:: Formatter ) -> Result < ( ) , fmt:: Error > {
222251 writeln ! ( f, "{}" , self . 0 ) ?;
223252
224253 let sources = ChainCompat :: new ( self . 0 ) . skip ( 1 ) ;
@@ -236,19 +265,98 @@ impl<'a> fmt::Display for ReportFormatter<'a> {
236265 writeln ! ( f, "{:3}: {}" , i, source) ?;
237266 }
238267
239- #[ cfg( feature = "unstable-provider-api" ) ]
240- {
241- use core:: any;
268+ Ok ( ( ) )
269+ }
242270
243- if let Some ( bt) = any:: request_ref :: < crate :: Backtrace > ( self . 0 ) {
244- writeln ! ( f, "\n Backtrace:\n {}" , bt) ?;
271+ #[ cfg( feature = "std" ) ]
272+ fn cleaned_error_trace ( & self , f : & mut fmt:: Formatter ) -> Result < ( ) , fmt:: Error > {
273+ const NOTE : char = '*' ;
274+
275+ let mut original_messages = ChainCompat :: new ( self . 0 ) . map ( ToString :: to_string) ;
276+ let mut prev = original_messages. next ( ) ;
277+
278+ let mut cleaned_messages = vec ! [ ] ;
279+ let mut any_cleaned = false ;
280+ let mut any_removed = false ;
281+ for msg in original_messages {
282+ if let Some ( mut prev) = prev {
283+ let cleaned = prev. trim_end_matches ( & msg) . trim_end ( ) . trim_end_matches ( ':' ) ;
284+ if cleaned. is_empty ( ) {
285+ any_removed = true ;
286+ // Do not add this to the output list
287+ } else if cleaned != prev {
288+ any_cleaned = true ;
289+ let cleaned_len = cleaned. len ( ) ;
290+ prev. truncate ( cleaned_len) ;
291+ prev. push ( ' ' ) ;
292+ prev. push ( NOTE ) ;
293+ cleaned_messages. push ( prev) ;
294+ } else {
295+ cleaned_messages. push ( prev) ;
296+ }
245297 }
298+
299+ prev = Some ( msg) ;
300+ }
301+ cleaned_messages. extend ( prev) ;
302+
303+ let mut visible_messages = cleaned_messages. iter ( ) ;
304+
305+ let head = match visible_messages. next ( ) {
306+ Some ( v) => v,
307+ None => return Ok ( ( ) ) ,
308+ } ;
309+
310+ writeln ! ( f, "{}" , head) ?;
311+
312+ match cleaned_messages. len ( ) {
313+ 0 | 1 => { }
314+ 2 => writeln ! ( f, "\n Caused by this error:" ) ?,
315+ _ => writeln ! ( f, "\n Caused by these errors (recent errors listed first):" ) ?,
316+ }
317+
318+ for ( i, msg) in visible_messages. enumerate ( ) {
319+ // Let's use 1-based indexing for presentation
320+ let i = i + 1 ;
321+ writeln ! ( f, "{:3}: {}" , i, msg) ?;
322+ }
323+
324+ if any_cleaned || any_removed {
325+ write ! ( f, "\n NOTE: " ) ?;
326+
327+ if any_cleaned {
328+ write ! (
329+ f,
330+ "Some redundant information has been removed from the lines marked with {}. " ,
331+ NOTE ,
332+ ) ?;
333+ } else {
334+ write ! ( f, "Some redundant information has been removed. " ) ?;
335+ }
336+
337+ writeln ! (
338+ f,
339+ "Set {}=1 to disable this behavior." ,
340+ SNAFU_RAW_ERROR_MESSAGES ,
341+ ) ?;
246342 }
247343
248344 Ok ( ( ) )
249345 }
250346}
251347
348+ #[ cfg( feature = "std" ) ]
349+ const SNAFU_RAW_ERROR_MESSAGES : & str = "SNAFU_RAW_ERROR_MESSAGES" ;
350+
351+ #[ cfg( feature = "std" ) ]
352+ fn trace_cleaning_enabled ( ) -> bool {
353+ use crate :: once_bool:: OnceBool ;
354+ use std:: env;
355+
356+ static DISABLED : OnceBool = OnceBool :: new ( ) ;
357+ !DISABLED . get ( || env:: var_os ( SNAFU_RAW_ERROR_MESSAGES ) . map_or ( false , |v| v == "1" ) )
358+ }
359+
252360#[ doc( hidden) ]
253361pub trait __InternalExtractErrorType {
254362 type Err ;
0 commit comments