118 lines
2.9 KiB
Rust
118 lines
2.9 KiB
Rust
use std::{collections::HashMap, path::PathBuf};
|
|
|
|
pub type FileID = usize;
|
|
pub type FileMap = HashMap<FileID, SrcFile>;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct SrcFile {
|
|
pub path: PathBuf,
|
|
pub text: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub struct FilePos {
|
|
pub file: FileID,
|
|
pub line: usize,
|
|
pub col: usize,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct FileSpan {
|
|
pub file: FileID,
|
|
pub start: FilePos,
|
|
pub end: FilePos,
|
|
}
|
|
|
|
impl FilePos {
|
|
pub fn start(file: FileID) -> Self {
|
|
Self {
|
|
line: 0,
|
|
col: 0,
|
|
file,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl FilePos {
|
|
pub fn to(self, end: FilePos) -> FileSpan {
|
|
FileSpan {
|
|
start: self,
|
|
end,
|
|
file: self.file,
|
|
}
|
|
}
|
|
pub fn char_span(self) -> FileSpan {
|
|
FileSpan::at(self)
|
|
}
|
|
}
|
|
|
|
const BEFORE: usize = 1;
|
|
const AFTER: usize = 0;
|
|
|
|
impl FileSpan {
|
|
const BUILTIN_FILE: usize = usize::MAX;
|
|
pub fn at(pos: FilePos) -> Self {
|
|
Self {
|
|
start: pos,
|
|
end: pos,
|
|
file: pos.file,
|
|
}
|
|
}
|
|
pub fn builtin() -> Self {
|
|
let pos = FilePos {
|
|
file: Self::BUILTIN_FILE,
|
|
line: 0,
|
|
col: 0,
|
|
};
|
|
Self::at(pos)
|
|
}
|
|
pub fn is_builtin(&self) -> bool {
|
|
self.file == Self::BUILTIN_FILE
|
|
}
|
|
pub fn write_for(&self, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> {
|
|
if self.is_builtin() {
|
|
return Ok(());
|
|
}
|
|
let start = self.start.line.saturating_sub(BEFORE);
|
|
let num_before = self.start.line - start;
|
|
let mut lines = file.lines().skip(start);
|
|
let width = format!("{}", self.end.line + AFTER).len();
|
|
let same_line = self.start.line == self.end.line;
|
|
for i in 0..num_before {
|
|
writeln!(writer, "{:>width$} | {}", start + i, lines.next().unwrap())?;
|
|
}
|
|
let line = lines.next().unwrap();
|
|
writeln!(writer, "{:>width$} | {}", self.start.line, line)?;
|
|
let len = if same_line {
|
|
self.end.col - self.start.col + 1
|
|
} else {
|
|
line.len() - self.start.col
|
|
};
|
|
writeln!(
|
|
writer,
|
|
"{} | {}",
|
|
" ".repeat(width),
|
|
" ".repeat(self.start.col) + &"^".repeat(len)
|
|
)?;
|
|
if !same_line {
|
|
for _ in 0..self.end.line - self.start.line - 1 {
|
|
lines.next();
|
|
}
|
|
let line = lines.next().unwrap();
|
|
writeln!(writer, "{:>width$} | {}", self.end.line, line)?;
|
|
writeln!(
|
|
writer,
|
|
"{} | {}",
|
|
" ".repeat(width),
|
|
"^".repeat(self.end.col + 1)
|
|
)?;
|
|
}
|
|
// for i in 0..AFTER {
|
|
// if let Some(next) = lines.next() {
|
|
// writeln!(writer, "{:>width$} | {}", self.end.line + i + 1, next)?;
|
|
// }
|
|
// }
|
|
Ok(())
|
|
}
|
|
}
|