Skip to content

Commit 53fb3ac

Browse files
committed
refactor: Move some processing earlier to allow reuse
1 parent 1f8b606 commit 53fb3ac

File tree

1 file changed

+168
-114
lines changed

1 file changed

+168
-114
lines changed

src/renderer/render.rs

Lines changed: 168 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use std::borrow::Cow;
44
use std::cmp::{max, min, Ordering, Reverse};
5-
use std::collections::{HashMap, VecDeque};
5+
use std::collections::HashMap;
66
use std::fmt;
77

88
use anstyle::Style;
@@ -18,7 +18,8 @@ use crate::renderer::source_map::{
1818
use crate::renderer::styled_buffer::StyledBuffer;
1919
use crate::snippet::Id;
2020
use 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

2425
const 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

26742728
fn newline_count(body: &str) -> usize {

0 commit comments

Comments
 (0)