Bugfix - avoid panics when displaying error snippets. (#2674)
This commit is contained in:
parent
5bfe598a96
commit
82e0d85da0
2 changed files with 20 additions and 17 deletions
|
@ -137,32 +137,35 @@ impl<I: Clone> ParseError<I> {
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Location {
|
pub struct Location {
|
||||||
pub line: usize,
|
pub line: usize,
|
||||||
|
/// In chars.
|
||||||
pub column: usize,
|
pub column: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Location {
|
impl Location {
|
||||||
/// Returns the location of a substring in the larger string.
|
/// Returns the location of the start of substring in the larger input string.
|
||||||
pub fn of_in(substr: &str, s: &str) -> Self {
|
///
|
||||||
let offset = s
|
/// Assumption: substr must be a subslice of input.
|
||||||
.len()
|
pub fn of_in(substr: &str, input: &str) -> Self {
|
||||||
.checked_sub(substr.len())
|
// Bytes of input before substr.
|
||||||
|
let offset = (substr.as_ptr() as usize)
|
||||||
|
.checked_sub(input.as_ptr() as usize)
|
||||||
.expect("tried to find location of substring in unrelated string");
|
.expect("tried to find location of substring in unrelated string");
|
||||||
let lines = s.split('\n').enumerate();
|
// Bytes of input prior to line being iteratated.
|
||||||
let mut total = 0;
|
let mut bytes_prior = 0;
|
||||||
for (idx, line) in lines {
|
for (line_idx, line) in input.split('\n').enumerate() {
|
||||||
// +1 for the '\n'
|
// +1 for the '\n'
|
||||||
let new_total = total + line.len() + 1;
|
let bytes_so_far = bytes_prior + line.len() + 1;
|
||||||
if new_total > offset {
|
if bytes_so_far > offset {
|
||||||
// found line.
|
// found line.
|
||||||
let line_offset = offset - total;
|
let line_offset = offset - bytes_prior;
|
||||||
let column = line[..line_offset].chars().count();
|
let column = line[..line_offset].chars().count();
|
||||||
// +1 because line and column are 1 index.
|
// +1 because line and column are 1 index.
|
||||||
return Self {
|
return Self {
|
||||||
line: idx + 1,
|
line: line_idx + 1,
|
||||||
column: column + 1,
|
column: column + 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
total = new_total;
|
bytes_prior = bytes_so_far;
|
||||||
}
|
}
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ pub struct Snippet {
|
||||||
truncation: Truncation,
|
truncation: Truncation,
|
||||||
/// The location of the snippet in the orignal source code.
|
/// The location of the snippet in the orignal source code.
|
||||||
location: Location,
|
location: Location,
|
||||||
/// The offset into the snippet where the location is.
|
/// The offset, in chars, into the snippet where the location is.
|
||||||
offset: usize,
|
offset: usize,
|
||||||
/// A possible explanation for this snippet.
|
/// A possible explanation for this snippet.
|
||||||
explain: Option<String>,
|
explain: Option<String>,
|
||||||
|
@ -58,7 +58,7 @@ impl Snippet {
|
||||||
explain: Option<&'static str>,
|
explain: Option<&'static str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let line = source.split('\n').nth(location.line - 1).unwrap();
|
let line = source.split('\n').nth(location.line - 1).unwrap();
|
||||||
let (line, truncation, offset) = Self::truncate_line(line, location.column);
|
let (line, truncation, offset) = Self::truncate_line(line, location.column - 1);
|
||||||
|
|
||||||
Snippet {
|
Snippet {
|
||||||
source: line.to_owned(),
|
source: line.to_owned(),
|
||||||
|
@ -71,9 +71,9 @@ impl Snippet {
|
||||||
|
|
||||||
/// Trims whitespace of an line and additionally truncates a string if it is too long.
|
/// Trims whitespace of an line and additionally truncates a string if it is too long.
|
||||||
fn truncate_line(mut line: &str, around_offset: usize) -> (&str, Truncation, usize) {
|
fn truncate_line(mut line: &str, around_offset: usize) -> (&str, Truncation, usize) {
|
||||||
let full_line_length = line.len();
|
let full_line_length = line.chars().count();
|
||||||
line = line.trim_start();
|
line = line.trim_start();
|
||||||
let mut offset = around_offset - (full_line_length - line.len());
|
let mut offset = around_offset - (full_line_length - line.chars().count());
|
||||||
line = line.trim_end();
|
line = line.trim_end();
|
||||||
let mut truncation = Truncation::None;
|
let mut truncation = Truncation::None;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue