This commit is contained in:
2026-04-08 23:28:50 -04:00
parent edabc22431
commit bdf08ce52c
11 changed files with 417 additions and 158 deletions
+106
View File
@@ -0,0 +1,106 @@
#[derive(Debug, Clone, Copy)]
pub struct Span {
pub file: usize,
pub start: usize,
pub end: usize,
}
pub struct Spanned<T> {
pub inner: T,
pub span: Span,
}
impl<T> std::ops::Deref for Spanned<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> std::ops::DerefMut for Spanned<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
pub struct CompilerMsg {
pub spans: Vec<Span>,
pub msg: String,
}
#[derive(Default)]
pub struct CompilerOutput {
pub errors: Vec<CompilerMsg>,
pub files: Vec<String>,
}
impl CompilerOutput {
pub fn new() -> Self {
Self::default()
}
pub fn error(&mut self, msg: impl Into<CompilerMsg>) {
self.errors.push(msg.into());
}
pub fn write(&self, w: &mut impl std::io::Write) {
let files: Vec<_> = self
.files
.iter()
.map(|path| std::fs::read_to_string(path).unwrap())
.collect();
for error in &self.errors {
writeln!(w, "Error: {}", error.msg).unwrap();
for span in &error.spans {
span.write(w, &files[span.file]).unwrap();
}
}
}
}
impl Span {
pub fn write(&self, w: &mut impl std::io::Write, text: &str) -> std::io::Result<()> {
let mut line_start = 0;
let mut found = false;
let mut line = 1;
let mut spans = Vec::new();
for (i, c) in text.char_indices() {
if i == self.start {
found = true;
}
if i == self.end {
found = true;
}
if c == '\n' {
if found {
spans.push((line, line_start..i));
}
line_start = i + 1;
line += 1;
found = false;
}
}
let start_chars = text[self.start..].lines().next().unwrap().len();
let underline = "\x1b[4:3m";
let underline_color = "\x1b[58;5;1m";
let end = "\x1b[0m";
if let [(line, range)] = &spans[..] {
writeln!(
w,
" {line:3} | {}{underline}{underline_color}{}{end}{}",
&text[range.start..self.start],
&text[self.start..=self.end],
&text[(self.end + 1)..range.end]
)?;
}
Ok(())
}
}
impl From<String> for CompilerMsg {
fn from(value: String) -> Self {
Self {
spans: Vec::new(),
msg: value.to_string(),
}
}
}