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) ) ;
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