Bugfix - avoid panics when displaying error snippets. (#2674)

This commit is contained in:
Finn Bear 2023-09-12 03:34:17 -07:00 committed by GitHub
parent 5bfe598a96
commit 82e0d85da0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 17 deletions

View file

@ -137,32 +137,35 @@ impl<I: Clone> ParseError<I> {
#[derive(Clone, Copy, Debug)]
pub struct Location {
pub line: usize,
/// In chars.
pub column: usize,
}
impl Location {
/// Returns the location of a substring in the larger string.
pub fn of_in(substr: &str, s: &str) -> Self {
let offset = s
.len()
.checked_sub(substr.len())
/// Returns the location of the start of substring in the larger input string.
///
/// Assumption: substr must be a subslice of input.
pub fn of_in(substr: &str, input: &str) -> Self {
// 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");
let lines = s.split('\n').enumerate();
let mut total = 0;
for (idx, line) in lines {
// Bytes of input prior to line being iteratated.
let mut bytes_prior = 0;
for (line_idx, line) in input.split('\n').enumerate() {
// +1 for the '\n'
let new_total = total + line.len() + 1;
if new_total > offset {
let bytes_so_far = bytes_prior + line.len() + 1;
if bytes_so_far > offset {
// found line.
let line_offset = offset - total;
let line_offset = offset - bytes_prior;
let column = line[..line_offset].chars().count();
// +1 because line and column are 1 index.
return Self {
line: idx + 1,
line: line_idx + 1,
column: column + 1,
};
}
total = new_total;
bytes_prior = bytes_so_far;
}
unreachable!()
}

View file

@ -40,7 +40,7 @@ pub struct Snippet {
truncation: Truncation,
/// The location of the snippet in the orignal source code.
location: Location,
/// The offset into the snippet where the location is.
/// The offset, in chars, into the snippet where the location is.
offset: usize,
/// A possible explanation for this snippet.
explain: Option<String>,
@ -58,7 +58,7 @@ impl Snippet {
explain: Option<&'static str>,
) -> Self {
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 {
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.
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();
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();
let mut truncation = Truncation::None;