Skip to main content

konjure_lang/
diagnostics.rs

1//! Terminal diagnostics render the same byte spans used by browser tooling.
2use crate::Diagnostic;
3use ariadne::{Config, IndexType, Label, Report, ReportKind, Source};
4
5/// Render an Ariadne source diagnostic without ANSI color escapes.
6///
7/// # Errors
8/// Returns `InvalidInput` if offsets do not belong to the supplied UTF-8 source.
9/// Output failures are returned instead of printing or silently discarding a report.
10pub fn render_diagnostic(diagnostic: &Diagnostic, source: &str) -> std::io::Result<String> {
11    let span = &diagnostic.span;
12    if span.start > span.end
13        || span.end > source.len()
14        || !source.is_char_boundary(span.start)
15        || !source.is_char_boundary(span.end)
16    {
17        return Err(std::io::Error::new(
18            std::io::ErrorKind::InvalidInput,
19            "diagnostic span does not match source",
20        ));
21    }
22    let mut output = Vec::new();
23    Report::build(
24        ReportKind::Error,
25        (span.module.as_str(), span.start..span.end),
26    )
27    .with_config(
28        Config::default()
29            .with_color(false)
30            .with_index_type(IndexType::Byte),
31    )
32    .with_code(&diagnostic.code)
33    .with_message(&diagnostic.message)
34    .with_label(
35        Label::new((span.module.as_str(), span.start..span.end)).with_message(&diagnostic.message),
36    )
37    .finish()
38    .write((span.module.as_str(), Source::from(source)), &mut output)?;
39    String::from_utf8(output)
40        .map_err(|error| std::io::Error::new(std::io::ErrorKind::InvalidData, error))
41}