Skip to content

Commit e5296bf

Browse files
committed
Merge #257: fix: utf-16 rendering for multiline errors
d6b0b17 fix: display for Span with `start` == `end` (Volodymyr Herashchenko) cec0e8c fix: support for unicode separator (Volodymyr Herashchenko) 2adcc4f fix: multiline display with utf-16 symbols (Volodymyr Herashchenko) ab33e52 fix: remove `println!()` from test (Volodymyr Herashchenko) Pull request description: Fixes multiline display in case if first line of `Error` is contains UTF-16 symbol. Also removes `println!()` statement in test and revert check for newline in `get_line_col` to == '\n', because `chumsky::is_newline` is introducing CRLF regression. ACKs for top commit: KyrylR: ACK d6b0b17 Tree-SHA512: 201a27906b382cd50d8b62a20e136f72012d1d55c9ed32c766c139de9325a0f776e8439cb0038113b0a2ec2d711ccd7507236011a9588e9b2ea44ab48273f4ff
2 parents 1d4cfaa + d6b0b17 commit e5296bf

1 file changed

Lines changed: 76 additions & 4 deletions

File tree

src/error.rs

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,14 @@ impl fmt::Display for RichError {
222222

223223
writeln!(f, "{:width$} |", " ", width = line_num_width)?;
224224

225-
let mut lines = file.lines().skip(start_line_index).peekable();
226-
let start_line_len = lines.peek().map_or(0, |l| l.len());
225+
let mut lines = file
226+
.split(|c: char| c.is_newline())
227+
.skip(start_line_index)
228+
.peekable();
229+
230+
let start_line_len = lines
231+
.peek()
232+
.map_or(0, |l| l.chars().map(char::len_utf16).sum());
227233

228234
for (relative_line_index, line_str) in lines.take(n_spanned_lines).enumerate() {
229235
let line_num = start_line_index + relative_line_index + 1;
@@ -234,7 +240,7 @@ impl fmt::Display for RichError {
234240

235241
let (underline_start, underline_length) = match is_multiline {
236242
true => (0, start_line_len),
237-
false => (start_col, end_col - start_col),
243+
false => (start_col, (end_col - start_col).max(1)),
238244
};
239245
write!(f, "{:width$} |", " ", width = line_num_width)?;
240246
write!(f, "{:width$}", " ", width = underline_start)?;
@@ -717,7 +723,73 @@ let x: u32 = Left(
717723
1 | /*😀*/ let a: u8 = 65536;
718724
| ^^^^^ Cannot parse: number too large to fit in target type"#;
719725

720-
println!("{error}");
726+
assert_eq!(&expected[1..], &error.to_string());
727+
}
728+
729+
#[test]
730+
fn multiline_display_with_utf16_chars() {
731+
let file = r#"/*😀 this symbol should not break the rendering*/
732+
let a: u8 = 65536;
733+
let x: u32 = Left(
734+
Right(0)
735+
);"#;
736+
let error = Error::CannotParse("This span covers the entire file".to_string())
737+
.with_span(Span::from(file))
738+
.with_file(Arc::from(file));
739+
740+
let expected = r#"
741+
|
742+
1 | /*😀 this symbol should not break the rendering*/
743+
2 | let a: u8 = 65536;
744+
3 | let x: u32 = Left(
745+
4 | Right(0)
746+
5 | );
747+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot parse: This span covers the entire file"#;
748+
749+
assert_eq!(&expected[1..], &error.to_string());
750+
}
751+
752+
#[test]
753+
fn display_with_unicode_separator() {
754+
let file = "let a: u8 = 65536;\u{2028}let b: u8 = 0;";
755+
let error = Error::CannotParse("number too large to fit in target type".to_string())
756+
.with_span(Span::new(12, 17))
757+
.with_file(Arc::from(file));
758+
759+
let expected = r#"
760+
|
761+
1 | let a: u8 = 65536;
762+
| ^^^^^ Cannot parse: number too large to fit in target type"#;
763+
764+
assert_eq!(&expected[1..], &error.to_string());
765+
}
766+
767+
#[test]
768+
fn display_span_as_point() {
769+
let file = "fn main()";
770+
let error = Error::Grammar("Error span at (0,0)".to_string())
771+
.with_span(Span::new(0, 0))
772+
.with_file(Arc::from(file));
773+
774+
let expected = r#"
775+
|
776+
1 | fn main()
777+
| ^ Grammar error: Error span at (0,0)"#;
778+
assert_eq!(&expected[1..], &error.to_string());
779+
}
780+
781+
#[test]
782+
fn display_span_as_point_on_trailing_empty_line() {
783+
let file = "fn main(){\n let a:\n";
784+
let error = Error::CannotParse("eof".to_string())
785+
.with_span(Span::new(file.len(), file.len()))
786+
.with_file(Arc::from(file));
787+
788+
let expected = r#"
789+
|
790+
3 |
791+
| ^ Cannot parse: eof"#;
792+
721793
assert_eq!(&expected[1..], &error.to_string());
722794
}
723795
}

0 commit comments

Comments
 (0)