Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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

Lines changed: 1 addition & 2 deletions
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

Lines changed: 47 additions & 6 deletions
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

Lines changed: 94 additions & 0 deletions
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

Lines changed: 34 additions & 0 deletions
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)

AltStyle によって変換されたページ (->オリジナル) /