Skip to content

Commit 0cd0b1f

Browse files
committed
feat: Add a way to keep lines with no annotations
1 parent 9288922 commit 0cd0b1f

File tree

5 files changed

+70
-11
lines changed

5 files changed

+70
-11
lines changed

examples/struct_name_as_context.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ fn main() {
1717
.element(
1818
Snippet::source(source)
1919
.path("$DIR/struct_name_as_context.rs")
20-
.annotation(AnnotationKind::Primary.span(91..102)),
20+
.annotation(AnnotationKind::Primary.span(91..102))
21+
.annotation(AnnotationKind::Visible.span(0..8)),
2122
)
2223
.element(
2324
Level::HELP.message(

examples/struct_name_as_context.svg

Lines changed: 10 additions & 6 deletions
Loading

src/renderer/source_map.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ impl<'a> SourceMap<'a> {
157157
line: info.line,
158158
line_index: info.line_index,
159159
annotations: vec![],
160+
keep: false,
160161
})
161162
.collect::<Vec<_>>();
162163
let mut multiline_annotations = vec![];
@@ -169,7 +170,12 @@ impl<'a> SourceMap<'a> {
169170
} in annotations
170171
{
171172
let (lo, mut hi) = self.span_to_locations(span.clone());
172-
173+
if kind == AnnotationKind::Visible {
174+
for line_idx in lo.line..=hi.line {
175+
self.keep_line(&mut annotated_line_infos, line_idx);
176+
}
177+
continue;
178+
}
173179
// Watch out for "empty spans". If we get a span like 6..6, we
174180
// want to just display a `^` at 6, so convert that to
175181
// 6..7. This is degenerate input, but it's best to degrade
@@ -306,7 +312,7 @@ impl<'a> SourceMap<'a> {
306312
}
307313

308314
if fold {
309-
annotated_line_infos.retain(|l| !l.annotations.is_empty());
315+
annotated_line_infos.retain(|l| !l.annotations.is_empty() || l.keep);
310316
}
311317

312318
(max_depth, annotated_line_infos)
@@ -333,6 +339,29 @@ impl<'a> SourceMap<'a> {
333339
line: info.line,
334340
line_index,
335341
annotations: vec![line_ann],
342+
keep: false,
343+
});
344+
annotated_line_infos.sort_by_key(|l| l.line_index);
345+
}
346+
}
347+
348+
fn keep_line(&self, annotated_line_infos: &mut Vec<AnnotatedLineInfo<'a>>, line_index: usize) {
349+
if let Some(line_info) = annotated_line_infos
350+
.iter_mut()
351+
.find(|line_info| line_info.line_index == line_index)
352+
{
353+
line_info.keep = true;
354+
} else {
355+
let info = self
356+
.lines
357+
.iter()
358+
.find(|l| l.line_index == line_index)
359+
.unwrap();
360+
annotated_line_infos.push(AnnotatedLineInfo {
361+
line: info.line,
362+
line_index,
363+
annotations: vec![],
364+
keep: true,
336365
});
337366
annotated_line_infos.sort_by_key(|l| l.line_index);
338367
}
@@ -595,6 +624,7 @@ pub(crate) struct AnnotatedLineInfo<'a> {
595624
pub(crate) line: &'a str,
596625
pub(crate) line_index: usize,
597626
pub(crate) annotations: Vec<LineAnnotation<'a>>,
627+
pub(crate) keep: bool,
598628
}
599629

600630
/// A source code location used for error reporting.

src/snippet.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,24 @@ pub enum AnnotationKind {
313313
///
314314
/// [`Renderer::context`]: crate::renderer::Renderer
315315
Context,
316+
/// Prevents the annotated text from getting [folded][Snippet::fold]
317+
///
318+
/// By default, [`Snippet`]s will [fold][`Snippet::fold`] (remove) lines
319+
/// that do not contain any annotations. [`Visible`][Self::Visible] makes
320+
/// it possible to selectively prevent this behavior for specific text,
321+
/// allowing context to be preserved without adding any annotation
322+
/// characters.
323+
///
324+
/// # Example
325+
///
326+
/// ```rust
327+
/// # #[allow(clippy::needless_doctest_main)]
328+
#[doc = include_str!("../examples/struct_name_as_context.rs")]
329+
/// ```
330+
///
331+
#[doc = include_str!("../examples/struct_name_as_context.svg")]
332+
///
333+
Visible,
316334
}
317335

318336
impl AnnotationKind {

tests/formatter.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3026,13 +3026,16 @@ zappy
30263026
.element(
30273027
Snippet::source(source)
30283028
.line_start(11)
3029-
.annotation(AnnotationKind::Primary.span(1..6)),
3029+
.annotation(AnnotationKind::Primary.span(1..6))
3030+
.annotation(AnnotationKind::Visible.span(37..41)),
30303031
)];
30313032
let expected = str![[r#"
30323033
error[E0277]: the size for values of type `T` cannot be known at compilation time
30333034
|
30343035
12 | cargo
30353036
| ^^^^^
3037+
...
3038+
18 | zappy
30363039
"#]];
30373040
let renderer = Renderer::plain();
30383041
assert_data_eq!(renderer.render(input_new), expected);
@@ -3058,13 +3061,16 @@ zappy
30583061
.element(
30593062
Snippet::source(source)
30603063
.line_start(11)
3061-
.annotation(AnnotationKind::Primary.span(1..6)),
3064+
.annotation(AnnotationKind::Primary.span(1..6))
3065+
.annotation(AnnotationKind::Visible.span(16..18)),
30623066
)];
30633067
let expected = str![[r#"
30643068
error[E0277]: the size for values of type `T` cannot be known at compilation time
30653069
|
30663070
12 | cargo
30673071
| ^^^^^
3072+
13 | fuzzy
3073+
14 | pizza
30683074
"#]];
30693075
let renderer = Renderer::plain();
30703076
assert_data_eq!(renderer.render(input_new), expected);

0 commit comments

Comments
 (0)