use ariadne::{
Color, Config, IndexType, Label, Report,
ReportKind, Source,
};
use crate::base_types::TgqeCtx;
use crate::enums::TgqeLevelFilter;
use crate::singletons::{
Configure, SourceManager,
};
pub struct Renderer;
impl Renderer {
pub fn draw(error: &TgqeCtx) {
let Some(source_text) = ({
let cache = SourceManager
.lock()
.unwrap();
cache.source_text(
&error
.position
.coord
.filepath,
)
}) else {
eprintln!(
"[TGQE][{}] {}",
error.publisher,
error.err_info.got
);
return;
};
let filepath = if error
.position
.coord
.filepath
.is_empty()
{
"unknown"
} else {
error
.position
.coord
.filepath
.as_str()
};
let len = source_text.len();
let start = (error
.position
.span
.start
.offset
as usize)
.min(len);
let end =
(error.position.span.end.offset
as usize)
.min(len)
.max(start);
let span = (filepath, start..end);
let (kind, color) = match error
.err_info
.level
{
TgqeLevelFilter::Warn => (
ReportKind::Warning,
Color::Yellow,
),
TgqeLevelFilter::Info => (
ReportKind::Advice,
Color::Cyan,
),
TgqeLevelFilter::Error
| TgqeLevelFilter::Undefined => {
(
ReportKind::Error,
Color::Red,
)
}
};
let mut builder = Report::build(
kind,
span.clone(),
)
.with_config(
Config::default()
.with_index_type(
IndexType::Byte,
)
.with_compact(
Configure.compact,
),
)
.with_message(format!(
"{}: {}",
error.err_info.err_type,
error.err_info.got
))
.with_label(
Label::new(span.clone())
.with_message(
error
.err_info
.expect
.clone(),
)
.with_color(color),
);
builder.add_note(format!(
"\n - Publisher: {}\n - Label: {}\n - Hints: {}\n - Recoverable: {}\n - Time: {}",
error.publisher,
error.labels,
error.hints,
error.err_info.recoverable,
Self::format_time(error.ns_timestamp),
));
if let Err(e) =
builder.finish().eprint((
filepath,
Source::from(source_text),
))
{
eprintln!(
"[TGQE] Failed to render the error msg: {e}"
);
}
}
fn format_time(ns: i64) -> String {
chrono::DateTime::from_timestamp_nanos(ns)
.with_timezone(&chrono::Local)
.format("%Y-%m-%d %H:%M:%S")
.to_string()
}
}