Skip to content

Commit b6ccd6f

Browse files
authored
Merge pull request #260 from Muscraft/no-title-element
chore: Don't allow Title in element
2 parents 7d5b7c1 + 60f7575 commit b6ccd6f

File tree

6 files changed

+76
-72
lines changed

6 files changed

+76
-72
lines changed

examples/highlight_source.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ fn main() {}
2222
),
2323
)
2424
.element(
25-
Level::NOTE.title("The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created."),
25+
Level::NOTE.message("The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created."),
2626

2727
)];
2828

src/renderer/mod.rs

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -285,32 +285,45 @@ impl Renderer {
285285
source_map_annotated_lines.push_back((source_map, annotated_lines));
286286
}
287287
}
288-
let mut message_iter = group.elements.iter().enumerate().peekable();
288+
let mut message_iter = group.elements.iter().peekable();
289289
let mut last_was_suggestion = false;
290-
let mut first_was_title = false;
291-
while let Some((i, section)) = message_iter.next() {
292-
let peek = message_iter.peek().map(|(_, s)| s).copied();
290+
if let Some(title) = &group.title {
291+
let peek = message_iter.peek().copied();
292+
let title_style = if g == 0 {
293+
TitleStyle::MainHeader
294+
} else {
295+
TitleStyle::Header
296+
};
297+
let buffer_msg_line_offset = buffer.num_lines();
298+
self.render_title(
299+
&mut buffer,
300+
title,
301+
max_line_num_len,
302+
title_style,
303+
matches!(peek, Some(Element::Message(_))),
304+
buffer_msg_line_offset,
305+
);
306+
let buffer_msg_line_offset = buffer.num_lines();
307+
308+
if matches!(peek, Some(Element::Message(_))) {
309+
self.draw_col_separator_no_space(
310+
&mut buffer,
311+
buffer_msg_line_offset,
312+
max_line_num_len + 1,
313+
);
314+
}
315+
if peek.is_none() && g == 0 && group_len > 1 {
316+
self.draw_col_separator_end(
317+
&mut buffer,
318+
buffer_msg_line_offset,
319+
max_line_num_len + 1,
320+
);
321+
}
322+
}
323+
let mut seen_primary = false;
324+
while let Some(section) = message_iter.next() {
325+
let peek = message_iter.peek().copied();
293326
match &section {
294-
Element::Title(title) => {
295-
if i == 0 {
296-
first_was_title = true;
297-
}
298-
let title_style = match (i == 0, g == 0) {
299-
(true, true) => TitleStyle::MainHeader,
300-
(true, false) => TitleStyle::Header,
301-
(false, _) => TitleStyle::Secondary,
302-
};
303-
let buffer_msg_line_offset = buffer.num_lines();
304-
self.render_title(
305-
&mut buffer,
306-
title,
307-
max_line_num_len,
308-
title_style,
309-
matches!(peek, Some(Element::Title(_) | Element::Message(_))),
310-
buffer_msg_line_offset,
311-
);
312-
last_was_suggestion = false;
313-
}
314327
Element::Message(title) => {
315328
let title_style = TitleStyle::Secondary;
316329
let buffer_msg_line_offset = buffer.num_lines();
@@ -321,8 +334,7 @@ impl Renderer {
321334
title_style,
322335
matches!(
323336
peek,
324-
Some(Element::Title(_) | Element::Message(_))
325-
| Some(Element::Padding(_))
337+
Some(Element::Message(_)) | Some(Element::Padding(_))
326338
),
327339
buffer_msg_line_offset,
328340
);
@@ -332,8 +344,9 @@ impl Renderer {
332344
if let Some((source_map, annotated_lines)) =
333345
source_map_annotated_lines.pop_front()
334346
{
335-
let is_primary = primary_path == cause.path.as_ref()
336-
&& i == first_was_title as usize;
347+
let is_primary =
348+
primary_path == cause.path.as_ref() && !seen_primary;
349+
seen_primary |= is_primary;
337350
self.render_snippet_annotations(
338351
&mut buffer,
339352
max_line_num_len,
@@ -348,7 +361,7 @@ impl Renderer {
348361
if g == 0 {
349362
let current_line = buffer.num_lines();
350363
match peek {
351-
Some(Element::Message(_) | Element::Title(_)) => {
364+
Some(Element::Message(_)) => {
352365
self.draw_col_separator_no_space(
353366
&mut buffer,
354367
current_line,
@@ -389,6 +402,8 @@ impl Renderer {
389402

390403
Element::Origin(origin) => {
391404
let buffer_msg_line_offset = buffer.num_lines();
405+
let is_primary = primary_path == Some(&origin.path) && !seen_primary;
406+
seen_primary |= is_primary;
392407
self.render_origin(
393408
&mut buffer,
394409
max_line_num_len,
@@ -414,18 +429,15 @@ impl Renderer {
414429
}
415430
}
416431
}
417-
if g == 0
418-
&& (matches!(section, Element::Origin(_))
419-
|| (matches!(section, Element::Title(_)) && i == 0))
420-
{
432+
if g == 0 && matches!(section, Element::Origin(_)) {
421433
let current_line = buffer.num_lines();
422434
if peek.is_none() && group_len > 1 {
423435
self.draw_col_separator_end(
424436
&mut buffer,
425437
current_line,
426438
max_line_num_len + 1,
427439
);
428-
} else if matches!(peek, Some(Element::Message(_) | Element::Title(_))) {
440+
} else if matches!(peek, Some(Element::Message(_))) {
429441
self.draw_col_separator_no_space(
430442
&mut buffer,
431443
current_line,
@@ -452,11 +464,8 @@ impl Renderer {
452464
let mut labels = None;
453465
let group = groups.first().expect("Expected at least one group");
454466

455-
let Some(Element::Title(title)) = group.elements.first() else {
456-
panic!(
457-
"Expected first element to be a Title, got: {:?}",
458-
group.elements.first()
459-
);
467+
let Some(title) = &group.title else {
468+
panic!("Expected a Title");
460469
};
461470

462471
if let Some(Element::Cause(cause)) = group
@@ -2952,10 +2961,7 @@ fn max_line_number(groups: &[Group<'_>]) -> usize {
29522961
v.elements
29532962
.iter()
29542963
.map(|s| match s {
2955-
Element::Title(_)
2956-
| Element::Message(_)
2957-
| Element::Origin(_)
2958-
| Element::Padding(_) => 0,
2964+
Element::Message(_) | Element::Origin(_) | Element::Padding(_) => 0,
29592965
Element::Cause(cause) => {
29602966
if cause.fold {
29612967
let end = cause

src/snippet.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,17 @@ pub(crate) struct Id<'a> {
3333
#[derive(Clone, Debug)]
3434
pub struct Group<'a> {
3535
pub(crate) primary_level: Level<'a>,
36+
pub(crate) title: Option<Title<'a>>,
3637
pub(crate) elements: Vec<Element<'a>>,
3738
}
3839

3940
impl<'a> Group<'a> {
4041
/// Create group with a title, deriving the primary [`Level`] for [`Annotation`]s from it
4142
pub fn with_title(title: Title<'a>) -> Self {
4243
let level = title.level.clone();
43-
Self::with_level(level).element(title)
44+
let mut x = Self::with_level(level);
45+
x.title = Some(title);
46+
x
4447
}
4548

4649
/// Create a title-less group with a primary [`Level`] for [`Annotation`]s
@@ -55,6 +58,7 @@ impl<'a> Group<'a> {
5558
pub fn with_level(level: Level<'a>) -> Self {
5659
Self {
5760
primary_level: level,
61+
title: None,
5862
elements: vec![],
5963
}
6064
}
@@ -70,28 +74,21 @@ impl<'a> Group<'a> {
7074
}
7175

7276
pub fn is_empty(&self) -> bool {
73-
self.elements.is_empty()
77+
self.elements.is_empty() && self.title.is_none()
7478
}
7579
}
7680

7781
/// A section of content within a [`Group`]
7882
#[derive(Clone, Debug)]
7983
#[non_exhaustive]
8084
pub enum Element<'a> {
81-
Title(Title<'a>),
8285
Message(Message<'a>),
8386
Cause(Snippet<'a, Annotation<'a>>),
8487
Suggestion(Snippet<'a, Patch<'a>>),
8588
Origin(Origin<'a>),
8689
Padding(Padding),
8790
}
8891

89-
impl<'a> From<Title<'a>> for Element<'a> {
90-
fn from(value: Title<'a>) -> Self {
91-
Element::Title(value)
92-
}
93-
}
94-
9592
impl<'a> From<Message<'a>> for Element<'a> {
9693
fn from(value: Message<'a>) -> Self {
9794
Element::Message(value)

tests/color/multiline_removal_suggestion.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,10 @@ fn main() {}
8181
)
8282
.element(
8383
Level::HELP
84-
.title("the trait `Iterator` is not implemented for `(bool, HashSet<u8>)`"),
84+
.message("the trait `Iterator` is not implemented for `(bool, HashSet<u8>)`"),
8585
)
8686
.element(
87-
Level::NOTE.title("required for `(bool, HashSet<u8>)` to implement `IntoIterator`"),
87+
Level::NOTE.message("required for `(bool, HashSet<u8>)` to implement `IntoIterator`"),
8888
),
8989
Group::with_title(Level::NOTE.title("required by a bound in `flatten`"))
9090
.element(

tests/formatter.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,7 +1666,7 @@ fn main() {
16661666
.annotation(AnnotationKind::Primary.span(89..90))
16671667
).element(
16681668
Level::NOTE
1669-
.title("required for the cast from `Box<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ()>>, ()>>, ()>>` to `Box<(dyn Future<Error = Foo> + 'static)>`")
1669+
.message("required for the cast from `Box<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ()>>, ()>>, ()>>` to `Box<(dyn Future<Error = Foo> + 'static)>`")
16701670
,
16711671
)];
16721672

@@ -1752,9 +1752,9 @@ fn main() {
17521752
.annotation(AnnotationKind::Primary.span(89..90))
17531753
).element(
17541754
Level::NOTE
1755-
.title("required for the cast from `Box<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ()>>, ()>>, ()>>` to `Box<(dyn Future<Error = Foo> + 'static)>`")
1755+
.message("required for the cast from `Box<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ()>>, ()>>, ()>>` to `Box<(dyn Future<Error = Foo> + 'static)>`")
17561756
).element(
1757-
Level::NOTE.title("a second note"),
1757+
Level::NOTE.message("a second note"),
17581758
)];
17591759

17601760
let expected = str![[r#"
@@ -1902,13 +1902,13 @@ fn main() {
19021902
)
19031903
).element(
19041904
Level::NOTE
1905-
.title("expected struct `Atype<Btype<..., i32>, i32>`\n found enum `Result<Result<..., _>, _>`")
1905+
.message("expected struct `Atype<Btype<..., i32>, i32>`\n found enum `Result<Result<..., _>, _>`")
19061906
).element(
19071907
Level::NOTE
1908-
.title("the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'")
1908+
.message("the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'")
19091909
).element(
19101910
Level::NOTE
1911-
.title("consider using `--verbose` to print the full type name to the console")
1911+
.message("consider using `--verbose` to print the full type name to the console")
19121912
,
19131913
)];
19141914

@@ -1986,7 +1986,7 @@ fn main() {
19861986
),
19871987
).element(
19881988
Level::NOTE
1989-
.title("expected fn pointer `for<'a> fn(Box<(dyn Any + Send + 'a)>) -> Pin<_>`\n found fn item `fn(Box<(dyn Any + Send + 'static)>) -> Pin<_> {wrapped_fn}`")
1989+
.message("expected fn pointer `for<'a> fn(Box<(dyn Any + Send + 'a)>) -> Pin<_>`\n found fn item `fn(Box<(dyn Any + Send + 'static)>) -> Pin<_> {wrapped_fn}`")
19901990
,
19911991
),Group::with_title(
19921992
Level::NOTE.title("function defined here"),
@@ -2077,7 +2077,7 @@ fn unicode_cut_handling2() {
20772077
.fold(false)
20782078
.annotation(AnnotationKind::Primary.span(499..500).label("expected item"))
20792079
).element(
2080-
Level::NOTE.title("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>")
2080+
Level::NOTE.message("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>")
20812081

20822082
)];
20832083

@@ -2114,7 +2114,7 @@ fn unicode_cut_handling3() {
21142114
.fold(false)
21152115
.annotation(AnnotationKind::Primary.span(251..254).label("expected item"))
21162116
).element(
2117-
Level::NOTE.title("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>")
2117+
Level::NOTE.message("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>")
21182118

21192119
)];
21202120

@@ -2151,7 +2151,7 @@ fn unicode_cut_handling4() {
21512151
.fold(false)
21522152
.annotation(AnnotationKind::Primary.span(334..335).label("expected item"))
21532153
).element(
2154-
Level::NOTE.title("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>")
2154+
Level::NOTE.message("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>")
21552155

21562156
)];
21572157

tests/rustc_tests.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,11 +1365,11 @@ outer_macro!(FirstStruct, FirstAttrStruct);
13651365
)
13661366
.element(
13671367
Level::HELP
1368-
.title("remove the `#[macro_export]` or move this `macro_rules!` outside the of the current function `main`")
1368+
.message("remove the `#[macro_export]` or move this `macro_rules!` outside the of the current function `main`")
13691369
)
13701370
.element(
13711371
Level::NOTE
1372-
.title("a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute")
1372+
.message("a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute")
13731373
),
13741374
Group::with_title(Level::NOTE.title("the lint level is defined here"))
13751375
.element(
@@ -1965,7 +1965,7 @@ fn main() {
19651965
.annotation(AnnotationKind::Primary.span(267..380)),
19661966
)
19671967
.element(
1968-
Level::NOTE.title("`Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated")),
1968+
Level::NOTE.message("`Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated")),
19691969
Group::with_title(Level::HELP.title("you might have meant to use `Iterator::for_each`"))
19701970
.element(
19711971
Snippet::source(source)
@@ -2555,7 +2555,8 @@ fn mismatched_types1() {
25552555
),
25562556
)
25572557
.element(
2558-
Level::NOTE.title("expected reference `&[u8]`\n found reference `&'static str`"),
2558+
Level::NOTE
2559+
.message("expected reference `&[u8]`\n found reference `&'static str`"),
25592560
),
25602561
];
25612562

@@ -2607,7 +2608,7 @@ fn mismatched_types2() {
26072608
)
26082609
.element(
26092610
Level::NOTE
2610-
.title("expected reference `&str`\n found reference `&'static [u8; 0]`"),
2611+
.message("expected reference `&str`\n found reference `&'static [u8; 0]`"),
26112612
),
26122613
];
26132614

@@ -2734,7 +2735,7 @@ pub struct Foo; //~^ ERROR
27342735
.annotation(AnnotationKind::Primary.span(111..126)),
27352736
)
27362737
.element(
2737-
Level::NOTE.title("bare URLs are not automatically turned into clickable links"),
2738+
Level::NOTE.message("bare URLs are not automatically turned into clickable links"),
27382739
),
27392740
Group::with_title(Level::NOTE.title("the lint level is defined here")).element(
27402741
Snippet::source(source_0)
@@ -3427,7 +3428,7 @@ fn main() {
34273428
.label("associated type `Pr` not found for this struct"),
34283429
),
34293430
)
3430-
.element(Level::NOTE.title("the associated type was found for\n"))];
3431+
.element(Level::NOTE.message("the associated type was found for\n"))];
34313432

34323433
let expected = str![[r#"
34333434
error[E0220]: associated type `Pr` not found for `S<bool>` in the current scope

0 commit comments

Comments
 (0)