22
33use  std:: borrow:: Cow ; 
44use  std:: cmp:: { max,  min,  Ordering ,  Reverse } ; 
5- use  std:: collections:: { HashMap ,   VecDeque } ; 
5+ use  std:: collections:: HashMap ; 
66use  std:: fmt; 
77
88use  anstyle:: Style ; 
@@ -18,7 +18,8 @@ use crate::renderer::source_map::{
1818use  crate :: renderer:: styled_buffer:: StyledBuffer ; 
1919use  crate :: snippet:: Id ; 
2020use  crate :: { 
21-     Annotation ,  AnnotationKind ,  Element ,  Group ,  Message ,  Origin ,  Patch ,  Report ,  Snippet ,  Title , 
21+     Annotation ,  AnnotationKind ,  Element ,  Group ,  Message ,  Origin ,  Padding ,  Patch ,  Report ,  Snippet , 
22+     Title , 
2223} ; 
2324
2425const  ANONYMIZED_LINE_NUM :  & str  = "LL" ; 
@@ -27,43 +28,29 @@ pub(crate) fn render(renderer: &Renderer, groups: Report<'_>) -> String {
2728    if  renderer. short_message  { 
2829        render_short_message ( renderer,  groups) . unwrap ( ) 
2930    }  else  { 
31+         let  ( max_line_num,  og_primary_path,  groups)  = pre_process ( groups) ; 
3032        let  max_line_num_len = if  renderer. anonymized_line_numbers  { 
3133            ANONYMIZED_LINE_NUM . len ( ) 
3234        }  else  { 
33-             num_decimal_digits ( max_line_number ( groups ) ) 
35+             num_decimal_digits ( max_line_num ) 
3436        } ; 
3537        let  mut  out_string = String :: new ( ) ; 
3638        let  group_len = groups. len ( ) ; 
37-         let  mut  og_primary_path = None ; 
38-         for  ( g,  group)  in  groups. iter ( ) . enumerate ( )  { 
39+         for  ( 
40+             g, 
41+             PreProcessedGroup  { 
42+                 group, 
43+                 elements, 
44+                 primary_path, 
45+                 max_depth, 
46+             } , 
47+         )  in  groups. into_iter ( ) . enumerate ( ) 
48+         { 
3949            let  mut  buffer = StyledBuffer :: new ( ) ; 
40-             let  primary_path = group
41-                 . elements 
42-                 . iter ( ) 
43-                 . find_map ( |s| match  & s { 
44-                     Element :: Cause ( cause)  => Some ( cause. path . as_ref ( ) ) , 
45-                     Element :: Origin ( origin)  => Some ( Some ( & origin. path ) ) , 
46-                     _ => None , 
47-                 } ) 
48-                 . unwrap_or_default ( ) ; 
49-             if  og_primary_path. is_none ( )  && primary_path. is_some ( )  { 
50-                 og_primary_path = primary_path; 
51-             } 
5250            let  level = group. primary_level . clone ( ) ; 
53-             let  mut  source_map_annotated_lines = VecDeque :: new ( ) ; 
54-             let  mut  max_depth = 0 ; 
55-             for  e in  & group. elements  { 
56-                 if  let  Element :: Cause ( cause)  = e { 
57-                     let  source_map = SourceMap :: new ( & cause. source ,  cause. line_start ) ; 
58-                     let  ( depth,  annotated_lines)  =
59-                         source_map. annotated_lines ( cause. markers . clone ( ) ,  cause. fold ) ; 
60-                     max_depth = max ( max_depth,  depth) ; 
61-                     source_map_annotated_lines. push_back ( ( source_map,  annotated_lines) ) ; 
62-                 } 
63-             } 
64-             let  mut  message_iter = group. elements . iter ( ) . enumerate ( ) . peekable ( ) ; 
51+             let  mut  message_iter = elements. into_iter ( ) . enumerate ( ) . peekable ( ) ; 
6552            if  let  Some ( title)  = & group. title  { 
66-                 let  peek = message_iter. peek ( ) . map ( |( _,  s) | s) . copied ( ) ; 
53+                 let  peek = message_iter. peek ( ) . map ( |( _,  s) | s) ; 
6754                let  title_style = if  title. allows_styling  { 
6855                    TitleStyle :: Header 
6956                }  else  { 
@@ -76,12 +63,12 @@ pub(crate) fn render(renderer: &Renderer, groups: Report<'_>) -> String {
7663                    title, 
7764                    max_line_num_len, 
7865                    title_style, 
79-                     matches ! ( peek,  Some ( Element :: Message ( _) ) ) , 
66+                     matches ! ( peek,  Some ( PreProcessedElement :: Message ( _) ) ) , 
8067                    buffer_msg_line_offset, 
8168                ) ; 
8269                let  buffer_msg_line_offset = buffer. num_lines ( ) ; 
8370
84-                 if  matches ! ( peek,  Some ( Element :: Message ( _) ) )  { 
71+                 if  matches ! ( peek,  Some ( PreProcessedElement :: Message ( _) ) )  { 
8572                    draw_col_separator_no_space ( 
8673                        renderer, 
8774                        & mut  buffer, 
@@ -105,10 +92,10 @@ pub(crate) fn render(renderer: &Renderer, groups: Report<'_>) -> String {
10592            let  mut  seen_primary = false ; 
10693            let  mut  last_suggestion_path = None ; 
10794            while  let  Some ( ( i,  section) )  = message_iter. next ( )  { 
108-                 let  peek = message_iter. peek ( ) . map ( |( _,  s) | s) . copied ( ) ; 
95+                 let  peek = message_iter. peek ( ) . map ( |( _,  s) | s) ; 
10996                let  is_first = i == 0 ; 
110-                 match  & section { 
111-                     Element :: Message ( title)  => { 
97+                 match  section { 
98+                     PreProcessedElement :: Message ( title)  => { 
11299                        let  title_style = TitleStyle :: Secondary ; 
113100                        let  buffer_msg_line_offset = buffer. num_lines ( ) ; 
114101                        render_title ( 
@@ -121,49 +108,44 @@ pub(crate) fn render(renderer: &Renderer, groups: Report<'_>) -> String {
121108                            buffer_msg_line_offset, 
122109                        ) ; 
123110                    } 
124-                     Element :: Cause ( cause)  => { 
125-                         if  let  Some ( ( source_map,  annotated_lines) )  =
126-                             source_map_annotated_lines. pop_front ( ) 
127-                         { 
128-                             let  is_primary = primary_path == cause. path . as_ref ( )  && !seen_primary; 
129-                             seen_primary |= is_primary; 
130-                             render_snippet_annotations ( 
131-                                 renderer, 
132-                                 & mut  buffer, 
133-                                 max_line_num_len, 
134-                                 cause, 
135-                                 is_primary, 
136-                                 & source_map, 
137-                                 & annotated_lines, 
138-                                 max_depth, 
139-                                 peek. is_some ( )  || ( g == 0  && group_len > 1 ) , 
140-                                 is_first, 
141-                             ) ; 
111+                     PreProcessedElement :: Cause ( ( cause,  source_map,  annotated_lines) )  => { 
112+                         let  is_primary = primary_path == cause. path . as_ref ( )  && !seen_primary; 
113+                         seen_primary |= is_primary; 
114+                         render_snippet_annotations ( 
115+                             renderer, 
116+                             & mut  buffer, 
117+                             max_line_num_len, 
118+                             cause, 
119+                             is_primary, 
120+                             & source_map, 
121+                             & annotated_lines, 
122+                             max_depth, 
123+                             peek. is_some ( )  || ( g == 0  && group_len > 1 ) , 
124+                             is_first, 
125+                         ) ; 
142126
143-                             if  g == 0  { 
144-                                 let  current_line = buffer. num_lines ( ) ; 
145-                                 match  peek { 
146-                                     Some ( Element :: Message ( _) )  => { 
147-                                         draw_col_separator_no_space ( 
148-                                             renderer, 
149-                                             & mut  buffer, 
150-                                             current_line, 
151-                                             max_line_num_len + 1 , 
152-                                         ) ; 
153-                                     } 
154-                                     None  if  group_len > 1  => draw_col_separator_end ( 
127+                         if  g == 0  { 
128+                             let  current_line = buffer. num_lines ( ) ; 
129+                             match  peek { 
130+                                 Some ( PreProcessedElement :: Message ( _) )  => { 
131+                                     draw_col_separator_no_space ( 
155132                                        renderer, 
156133                                        & mut  buffer, 
157134                                        current_line, 
158135                                        max_line_num_len + 1 , 
159-                                     ) , 
160-                                     _ => { } 
136+                                     ) ; 
161137                                } 
138+                                 None  if  group_len > 1  => draw_col_separator_end ( 
139+                                     renderer, 
140+                                     & mut  buffer, 
141+                                     current_line, 
142+                                     max_line_num_len + 1 , 
143+                                 ) , 
144+                                 _ => { } 
162145                            } 
163146                        } 
164147                    } 
165-                     Element :: Suggestion ( suggestion)  => { 
166-                         let  source_map = SourceMap :: new ( & suggestion. source ,  suggestion. line_start ) ; 
148+                     PreProcessedElement :: Suggestion ( ( suggestion,  source_map) )  => { 
167149                        let  matches_previous_suggestion =
168150                            last_suggestion_path == Some ( suggestion. path . as_ref ( ) ) ; 
169151                        emit_suggestion_default ( 
@@ -179,14 +161,14 @@ pub(crate) fn render(renderer: &Renderer, groups: Report<'_>) -> String {
179161                            peek. is_some ( ) , 
180162                        ) ; 
181163
182-                         if  matches ! ( peek,  Some ( Element :: Suggestion ( _) ) )  { 
164+                         if  matches ! ( peek,  Some ( PreProcessedElement :: Suggestion ( _) ) )  { 
183165                            last_suggestion_path = Some ( suggestion. path . as_ref ( ) ) ; 
184166                        }  else  { 
185167                            last_suggestion_path = None ; 
186168                        } 
187169                    } 
188170
189-                     Element :: Origin ( origin)  => { 
171+                     PreProcessedElement :: Origin ( origin)  => { 
190172                        let  buffer_msg_line_offset = buffer. num_lines ( ) ; 
191173                        let  is_primary = primary_path == Some ( & origin. path )  && !seen_primary; 
192174                        seen_primary |= is_primary; 
@@ -209,7 +191,7 @@ pub(crate) fn render(renderer: &Renderer, groups: Report<'_>) -> String {
209191                            ) ; 
210192                        } 
211193                    } 
212-                     Element :: Padding ( _)  => { 
194+                     PreProcessedElement :: Padding ( _)  => { 
213195                        let  current_line = buffer. num_lines ( ) ; 
214196                        if  peek. is_none ( )  { 
215197                            draw_col_separator_end ( 
@@ -2625,50 +2607,122 @@ enum TitleStyle {
26252607    Secondary , 
26262608} 
26272609
2628- fn  max_line_number ( groups :  & [ Group < ' _ > ] )  -> usize  { 
2629-     groups
2630-         . iter ( ) 
2631-         . map ( |v| { 
2632-             v. elements 
2633-                 . iter ( ) 
2634-                 . map ( |s| match  s { 
2635-                     Element :: Message ( _)  | Element :: Origin ( _)  | Element :: Padding ( _)  => 0 , 
2636-                     Element :: Cause ( cause)  => { 
2637-                         if  cause. fold  { 
2638-                             let  end = cause
2639-                                 . markers 
2640-                                 . iter ( ) 
2641-                                 . map ( |a| a. span . end ) 
2642-                                 . max ( ) 
2643-                                 . unwrap_or ( cause. source . len ( ) ) 
2644-                                 . min ( cause. source . len ( ) ) ; 
2645- 
2646-                             cause. line_start  + newline_count ( & cause. source [ ..end] ) 
2647-                         }  else  { 
2648-                             cause. line_start  + newline_count ( & cause. source ) 
2649-                         } 
2610+ struct  PreProcessedGroup < ' a >  { 
2611+     group :  & ' a  Group < ' a > , 
2612+     elements :  Vec < PreProcessedElement < ' a > > , 
2613+     primary_path :  Option < & ' a  Cow < ' a ,  str > > , 
2614+     max_depth :  usize , 
2615+ } 
2616+ 
2617+ enum  PreProcessedElement < ' a >  { 
2618+     Message ( & ' a  Message < ' a > ) , 
2619+     Cause ( 
2620+         ( 
2621+             & ' a  Snippet < ' a ,  Annotation < ' a > > , 
2622+             SourceMap < ' a > , 
2623+             Vec < AnnotatedLineInfo < ' a > > , 
2624+         ) , 
2625+     ) , 
2626+     Suggestion ( ( & ' a  Snippet < ' a ,  Patch < ' a > > ,  SourceMap < ' a > ) ) , 
2627+     Origin ( & ' a  Origin < ' a > ) , 
2628+     Padding ( Padding ) , 
2629+ } 
2630+ 
2631+ fn  pre_process < ' a > ( 
2632+     groups :  & ' a  [ Group < ' a > ] , 
2633+ )  -> ( usize ,  Option < & ' a  Cow < ' a ,  str > > ,  Vec < PreProcessedGroup < ' a > > )  { 
2634+     let  mut  max_line_num = 0 ; 
2635+     let  mut  og_primary_path = None ; 
2636+     let  mut  out = Vec :: with_capacity ( groups. len ( ) ) ; 
2637+     for  group in  groups { 
2638+         let  mut  elements = Vec :: with_capacity ( group. elements . len ( ) ) ; 
2639+         let  mut  primary_path = None ; 
2640+         let  mut  max_depth = 0 ; 
2641+         for  element in  & group. elements  { 
2642+             match  element { 
2643+                 Element :: Message ( message)  => { 
2644+                     elements. push ( PreProcessedElement :: Message ( message) ) ; 
2645+                 } 
2646+                 Element :: Cause ( cause)  => { 
2647+                     let  sm = SourceMap :: new ( & cause. source ,  cause. line_start ) ; 
2648+                     let  ( depth,  annotated_lines)  =
2649+                         sm. annotated_lines ( cause. markers . clone ( ) ,  cause. fold ) ; 
2650+ 
2651+                     if  cause. fold  { 
2652+                         let  end = cause
2653+                             . markers 
2654+                             . iter ( ) 
2655+                             . map ( |a| a. span . end ) 
2656+                             . max ( ) 
2657+                             . unwrap_or ( cause. source . len ( ) ) 
2658+                             . min ( cause. source . len ( ) ) ; 
2659+ 
2660+                         max_line_num = max ( 
2661+                             cause. line_start  + newline_count ( & cause. source [ ..end] ) , 
2662+                             max_line_num, 
2663+                         ) ; 
2664+                     }  else  { 
2665+                         max_line_num = max ( 
2666+                             cause. line_start  + newline_count ( & cause. source ) , 
2667+                             max_line_num, 
2668+                         ) ; 
26502669                    } 
2651-                     Element :: Suggestion ( suggestion)  => { 
2652-                         if  suggestion. fold  { 
2653-                             let  end = suggestion
2654-                                 . markers 
2655-                                 . iter ( ) 
2656-                                 . map ( |a| a. span . end ) 
2657-                                 . max ( ) 
2658-                                 . unwrap_or ( suggestion. source . len ( ) ) 
2659-                                 . min ( suggestion. source . len ( ) ) ; 
2660- 
2661-                             suggestion. line_start  + newline_count ( & suggestion. source [ ..end] ) 
2662-                         }  else  { 
2663-                             suggestion. line_start  + newline_count ( & suggestion. source ) 
2664-                         } 
2670+ 
2671+                     if  primary_path. is_none ( )  { 
2672+                         primary_path = Some ( cause. path . as_ref ( ) ) ; 
26652673                    } 
2666-                 } ) 
2667-                 . max ( ) 
2668-                 . unwrap_or ( 1 ) 
2669-         } ) 
2670-         . max ( ) 
2671-         . unwrap_or ( 1 ) 
2674+                     max_depth = max ( depth,  max_depth) ; 
2675+                     elements. push ( PreProcessedElement :: Cause ( ( cause,  sm,  annotated_lines) ) ) ; 
2676+                 } 
2677+                 Element :: Suggestion ( suggestion)  => { 
2678+                     let  sm = SourceMap :: new ( & suggestion. source ,  suggestion. line_start ) ; 
2679+ 
2680+                     if  suggestion. fold  { 
2681+                         let  end = suggestion
2682+                             . markers 
2683+                             . iter ( ) 
2684+                             . map ( |a| a. span . end ) 
2685+                             . max ( ) 
2686+                             . unwrap_or ( suggestion. source . len ( ) ) 
2687+                             . min ( suggestion. source . len ( ) ) ; 
2688+ 
2689+                         max_line_num = max ( 
2690+                             suggestion. line_start  + newline_count ( & suggestion. source [ ..end] ) , 
2691+                             max_line_num, 
2692+                         ) ; 
2693+                     }  else  { 
2694+                         max_line_num = max ( 
2695+                             suggestion. line_start  + newline_count ( & suggestion. source ) , 
2696+                             max_line_num, 
2697+                         ) ; 
2698+                     } 
2699+ 
2700+                     elements. push ( PreProcessedElement :: Suggestion ( ( suggestion,  sm) ) ) ; 
2701+                 } 
2702+                 Element :: Origin ( origin)  => { 
2703+                     if  primary_path. is_none ( )  { 
2704+                         primary_path = Some ( Some ( & origin. path ) ) ; 
2705+                     } 
2706+                     elements. push ( PreProcessedElement :: Origin ( origin) ) ; 
2707+                 } 
2708+                 Element :: Padding ( padding)  => { 
2709+                     elements. push ( PreProcessedElement :: Padding ( padding. clone ( ) ) ) ; 
2710+                 } 
2711+             } 
2712+         } 
2713+         let  group = PreProcessedGroup  { 
2714+             group, 
2715+             elements, 
2716+             primary_path :  primary_path. unwrap_or_default ( ) , 
2717+             max_depth, 
2718+         } ; 
2719+         if  og_primary_path. is_none ( )  && group. primary_path . is_some ( )  { 
2720+             og_primary_path = group. primary_path ; 
2721+         } 
2722+         out. push ( group) ; 
2723+     } 
2724+ 
2725+     ( max_line_num,  og_primary_path,  out) 
26722726} 
26732727
26742728fn  newline_count ( body :  & str )  -> usize  { 
0 commit comments