116 lines
2.7 KiB
Rust
116 lines
2.7 KiB
Rust
use std::{io::Read, path::PathBuf};
|
|
|
|
use miette::{SourceCode, SourceSpan, SpanContents};
|
|
|
|
#[derive(Debug)]
|
|
pub struct SourceFile {
|
|
pub(crate) path: PathBuf,
|
|
}
|
|
|
|
impl SourceCode for SourceFile {
|
|
fn read_span<'a>(
|
|
&'a self,
|
|
span: &miette::SourceSpan,
|
|
context_lines_before: usize,
|
|
context_lines_after: usize,
|
|
) -> std::result::Result<Box<dyn miette::SpanContents<'a> + 'a>, miette::MietteError> {
|
|
let mut file = std::fs::File::open(&self.path)?;
|
|
|
|
// read keeping the last
|
|
|
|
let mut data = Vec::new();
|
|
|
|
file.read_to_end(&mut data)?;
|
|
|
|
let data = data.leak();
|
|
|
|
let line = data.iter().filter(|&&x| x == b'\n').count();
|
|
|
|
let mut start_new_lines = 0;
|
|
|
|
let start_pos = data[0..span.offset()]
|
|
.iter()
|
|
.rposition(|&x| {
|
|
if x == b'\n' {
|
|
if start_new_lines > context_lines_before {
|
|
true
|
|
} else {
|
|
start_new_lines += 1;
|
|
false
|
|
}
|
|
} else {
|
|
false
|
|
}
|
|
})
|
|
.map(|x| x + 1)
|
|
.unwrap_or(0);
|
|
|
|
let mut end_new_lines = 0;
|
|
|
|
let end_pos = data[span.offset()..]
|
|
.iter()
|
|
.position(|&x| {
|
|
if x == b'\n' {
|
|
if end_new_lines >= context_lines_after {
|
|
true
|
|
} else {
|
|
end_new_lines += 1;
|
|
false
|
|
}
|
|
} else {
|
|
false
|
|
}
|
|
})
|
|
.map(|x| x + span.offset())
|
|
.unwrap_or(data.len());
|
|
|
|
let compact_data = &data[start_pos..end_pos];
|
|
|
|
Ok(Box::new(SourceFileSpanContents {
|
|
span: SourceSpan::new(start_pos.into(), end_pos - start_pos),
|
|
start_line_number: line - start_new_lines,
|
|
line_count: start_new_lines + 1 + end_new_lines,
|
|
path: self.path.clone(),
|
|
data: compact_data,
|
|
}))
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct SourceFileSpanContents {
|
|
data: &'static [u8],
|
|
span: SourceSpan,
|
|
start_line_number: usize,
|
|
line_count: usize,
|
|
path: PathBuf,
|
|
}
|
|
|
|
impl<'a> SpanContents<'a> for SourceFileSpanContents {
|
|
fn data(&'_ self) -> &'a [u8] {
|
|
self.data
|
|
}
|
|
|
|
fn span(&self) -> &SourceSpan {
|
|
&self.span
|
|
}
|
|
|
|
fn line(&self) -> usize {
|
|
self.start_line_number
|
|
}
|
|
|
|
fn column(&self) -> usize {
|
|
0
|
|
}
|
|
|
|
fn line_count(&self) -> usize {
|
|
self.line_count
|
|
}
|
|
|
|
fn name(&self) -> Option<&str> {
|
|
self.path.to_str()
|
|
}
|
|
|
|
fn language(&self) -> Option<&str> {
|
|
None
|
|
}
|
|
}
|