use typst::diag::SourceDiagnostic;
use typst::syntax::DiagSpan;
use typst::{World, WorldExt};
use crate::error::{Diagnostic, Hint, Severity};
use crate::world::PublishWorld;
pub(crate) fn to_diagnostics(world: &PublishWorld, diags: &[SourceDiagnostic]) -> Vec<Diagnostic> {
diags
.iter()
.map(|d| {
let (file, line, column) = locate(world, d.span);
Diagnostic {
severity: match d.severity {
typst::diag::Severity::Error => Severity::Error,
typst::diag::Severity::Warning => Severity::Warning,
},
message: d.message.to_string(),
file,
line,
column,
hints: d
.hints
.iter()
.map(|h| {
let (file, line, column) = locate(world, h.span);
Hint {
message: h.v.to_string(),
file,
line,
column,
}
})
.collect(),
}
})
.collect()
}
fn locate(world: &PublishWorld, span: DiagSpan) -> (Option<String>, Option<usize>, Option<usize>) {
let Some(id) = span.id() else {
return (None, None, None);
};
let file = Some(id.vpath().get_without_slash().to_owned());
let Ok(source) = world.source(id) else {
return (file, None, None);
};
let Some(range) = world.range(span) else {
return (file, None, None);
};
match source.lines().byte_to_line_column(range.start) {
Some((line, column)) => (file, Some(line + 1), Some(column + 1)),
None => (file, None, None),
}
}