use crate::standard_json::output::error::source_location::SourceLocation;
#[derive(Debug)]
pub struct MappedLocation<'a> {
pub path: String,
pub line: Option<usize>,
pub column: Option<usize>,
pub length: Option<usize>,
pub source_code_line: Option<&'a str>,
}
impl<'a> MappedLocation<'a> {
pub fn new(path: String) -> Self {
Self {
path,
line: None,
column: None,
length: None,
source_code_line: None,
}
}
pub fn new_with_location(
path: String,
line: usize,
column: usize,
length: usize,
source_code_line: Option<&'a str>,
) -> Self {
Self {
path,
line: Some(line),
column: Some(column),
length: Some(length),
source_code_line,
}
}
pub fn try_from_source_location(
source_location: &SourceLocation,
source_code: Option<&'a str>,
) -> Self {
let source_code = match source_code {
Some(source_code) => source_code,
None => return Self::new(source_location.file.to_owned()),
};
if source_location.start <= 0 || source_location.end <= 0 {
return Self::new(source_location.file.to_owned());
}
let start = source_location.start as usize;
let end = source_location.end as usize;
let mut cursor = 1;
for (line, source_line) in source_code.lines().enumerate() {
let cursor_next = cursor + source_line.len() + 1;
if cursor <= start && start <= cursor_next {
let line = line + 1;
let column = start - cursor;
let length = end - start;
return Self::new_with_location(
source_location.file.to_owned(),
line,
column,
length,
Some(source_line),
);
}
cursor = cursor_next;
}
Self::new(source_location.file.to_owned())
}
}
impl std::fmt::Display for MappedLocation<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut path = self.path.clone();
if let Some(line) = self.line {
path.push(':');
path.push_str(line.to_string().as_str());
if let Some(column) = self.column {
path.push(':');
path.push_str(column.to_string().as_str());
if let (Some(source_code_line), Some(length)) = (self.source_code_line, self.length)
{
let line_number_length = line.to_string().len();
writeln!(f, "{} --> {path}", " ".repeat(line_number_length))?;
writeln!(f, " {} |", " ".repeat(line_number_length))?;
writeln!(f, " {line} | {source_code_line}")?;
writeln!(
f,
" {} | {} {}",
" ".repeat(line_number_length),
" ".repeat(column),
"^".repeat(std::cmp::min(length, source_code_line.len() - column))
)?;
}
}
} else {
writeln!(f, "--> {path}")?;
}
Ok(())
}
}