Skip to content

Commit d10d37a

Browse files
committed
Fix "\r\n" end of line #29
1 parent 997de0e commit d10d37a

File tree

4 files changed

+176
-8
lines changed

4 files changed

+176
-8
lines changed

benches/simple.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ fn create_snippet() {
3333
}
3434
_ => continue,
3535
}
36-
}"#
37-
,
36+
}"#,
3837
line_start: 51,
3938
origin: Some("src/format.rs"),
4039
fold: false,

src/display_list/from_snippet.rs

+47-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,51 @@
22
use super::*;
33
use crate::{formatter::get_term_style, snippet};
44

5+
struct CursorLines<'a>(&'a str);
6+
7+
impl<'a> CursorLines<'a> {
8+
fn new(src: &str) -> CursorLines<'_> {
9+
CursorLines(src)
10+
}
11+
}
12+
13+
enum EndLine {
14+
EOF = 0,
15+
CRLF = 1,
16+
LF = 2,
17+
}
18+
19+
impl<'a> Iterator for CursorLines<'a> {
20+
type Item = (&'a str, EndLine);
21+
22+
fn next(&mut self) -> Option<Self::Item> {
23+
if self.0.is_empty() {
24+
None
25+
} else {
26+
self.0
27+
.find('\n')
28+
.map(|x| {
29+
let ret = if 0 < x {
30+
if self.0.as_bytes()[x - 1] == b'\r' {
31+
(&self.0[..x - 1], EndLine::LF)
32+
} else {
33+
(&self.0[..x], EndLine::CRLF)
34+
}
35+
} else {
36+
("", EndLine::CRLF)
37+
};
38+
self.0 = &self.0[x + 1..];
39+
ret
40+
})
41+
.or_else(|| {
42+
let ret = Some((&self.0[..], EndLine::EOF));
43+
self.0 = "";
44+
ret
45+
})
46+
}
47+
}
48+
}
49+
550
fn format_label(
651
label: Option<&str>,
752
style: Option<DisplayTextStyle>,
@@ -236,9 +281,7 @@ fn format_body(slice: snippet::Slice<'_>, has_footer: bool) -> Vec<DisplayLine<'
236281
let mut current_index = 0;
237282
let mut line_index_ranges = vec![];
238283

239-
let lines = slice.source.lines();
240-
let lines_len = lines.clone().count();
241-
for (i, line) in lines.enumerate() {
284+
for (line, end_line) in CursorLines::new(slice.source) {
242285
let line_length = line.chars().count();
243286
let line_range = (current_index, current_index + line_length);
244287
body.push(DisplayLine::Source {
@@ -251,9 +294,7 @@ fn format_body(slice: snippet::Slice<'_>, has_footer: bool) -> Vec<DisplayLine<'
251294
});
252295
line_index_ranges.push(line_range);
253296
current_line += 1;
254-
if i + 1 < lines_len {
255-
current_index += line_length + 1;
256-
}
297+
current_index += line_length + end_line as usize;
257298
}
258299

259300
let mut annotation_line_count = 0;

tests/dl_from_snippet.rs

+94
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use annotate_snippets::display_list::DisplayList;
12
use annotate_snippets::{display_list as dl, formatter::get_term_style, snippet};
23

34
#[test]
@@ -305,3 +306,96 @@ fn test_i26() {
305306

306307
let _ = dl::DisplayList::from(input);
307308
}
309+
310+
#[test]
311+
fn test_i_29() {
312+
let snippets = snippet::Snippet {
313+
title: Some(snippet::Annotation {
314+
id: None,
315+
label: Some("oops"),
316+
annotation_type: snippet::AnnotationType::Error,
317+
}),
318+
footer: vec![],
319+
slices: vec![snippet::Slice {
320+
source: "First line\r\nSecond oops line",
321+
line_start: 1,
322+
origin: Some("<current file>"),
323+
annotations: vec![snippet::SourceAnnotation {
324+
range: (19, 23),
325+
label: "oops",
326+
annotation_type: snippet::AnnotationType::Error,
327+
}],
328+
fold: true,
329+
}],
330+
opt: Default::default(),
331+
};
332+
333+
let expected = DisplayList {
334+
body: vec![
335+
dl::DisplayLine::Raw(dl::DisplayRawLine::Annotation {
336+
annotation: dl::Annotation {
337+
annotation_type: dl::DisplayAnnotationType::Error,
338+
id: None,
339+
label: vec![dl::DisplayTextFragment {
340+
content: "oops",
341+
style: dl::DisplayTextStyle::Emphasis,
342+
}],
343+
},
344+
source_aligned: false,
345+
continuation: false,
346+
}),
347+
dl::DisplayLine::Raw(dl::DisplayRawLine::Origin {
348+
path: "<current file>",
349+
pos: Some((2, 8)),
350+
header_type: dl::DisplayHeaderType::Initial,
351+
}),
352+
dl::DisplayLine::Source {
353+
lineno: None,
354+
inline_marks: vec![],
355+
line: dl::DisplaySourceLine::Empty,
356+
},
357+
dl::DisplayLine::Source {
358+
lineno: Some(1),
359+
inline_marks: vec![],
360+
line: dl::DisplaySourceLine::Content {
361+
text: "First line",
362+
range: (0, 10),
363+
},
364+
},
365+
dl::DisplayLine::Source {
366+
lineno: Some(2),
367+
inline_marks: vec![],
368+
line: dl::DisplaySourceLine::Content {
369+
text: "Second oops line",
370+
range: (12, 28),
371+
},
372+
},
373+
dl::DisplayLine::Source {
374+
lineno: None,
375+
inline_marks: vec![],
376+
line: dl::DisplaySourceLine::Annotation {
377+
annotation: dl::Annotation {
378+
annotation_type: dl::DisplayAnnotationType::None,
379+
id: None,
380+
label: vec![dl::DisplayTextFragment {
381+
content: "oops",
382+
style: dl::DisplayTextStyle::Regular,
383+
}],
384+
},
385+
range: (7, 11),
386+
annotation_type: dl::DisplayAnnotationType::Error,
387+
annotation_part: dl::DisplayAnnotationPart::Standalone,
388+
},
389+
},
390+
dl::DisplayLine::Source {
391+
lineno: None,
392+
inline_marks: vec![],
393+
line: dl::DisplaySourceLine::Empty,
394+
},
395+
],
396+
stylesheet: get_term_style(false),
397+
anonymized_line_numbers: false,
398+
};
399+
400+
assert_eq!(DisplayList::from(snippets), expected);
401+
}

tests/formatter.rs

+34
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use annotate_snippets::display_list::*;
2+
use annotate_snippets::snippet::{self, Snippet};
23

34
#[test]
45
fn test_source_empty() {
@@ -516,3 +517,36 @@ fn test_raw_origin_initial_pos_anon_lines() {
516517
dl.anonymized_line_numbers = true;
517518
assert_eq!(dl.to_string(), "--> src/test.rs:23:15");
518519
}
520+
521+
#[test]
522+
fn test_i_29() {
523+
let snippets = Snippet {
524+
title: Some(snippet::Annotation {
525+
id: None,
526+
label: Some("oops"),
527+
annotation_type: snippet::AnnotationType::Error,
528+
}),
529+
footer: vec![],
530+
slices: vec![snippet::Slice {
531+
source: "First line\r\nSecond oops line",
532+
line_start: 1,
533+
origin: Some("<current file>"),
534+
annotations: vec![snippet::SourceAnnotation {
535+
range: (19, 23),
536+
label: "oops",
537+
annotation_type: snippet::AnnotationType::Error,
538+
}],
539+
fold: true,
540+
}],
541+
opt: Default::default(),
542+
};
543+
let expected = r#"error: oops
544+
--> <current file>:2:8
545+
|
546+
1 | First line
547+
2 | Second oops line
548+
| ^^^^ oops
549+
|"#;
550+
551+
assert_eq!(DisplayList::from(snippets).to_string(), expected);
552+
}

0 commit comments

Comments
 (0)