aboutsummaryrefslogtreecommitdiff
path: root/bin/src/traits.rs
diff options
context:
space:
mode:
Diffstat (limited to 'bin/src/traits.rs')
-rw-r--r--bin/src/traits.rs83
1 files changed, 83 insertions, 0 deletions
diff --git a/bin/src/traits.rs b/bin/src/traits.rs
new file mode 100644
index 0000000..1807ad0
--- /dev/null
+++ b/bin/src/traits.rs
@@ -0,0 +1,83 @@
1use std::{
2 io::{self, Write},
3 str,
4};
5
6use ariadne::{
7 CharSet, Color, Config as CliConfig, Label, LabelAttach, Report as CliReport,
8 ReportKind as CliReportKind, Source, Fmt
9};
10use lib::Report;
11use rnix::TextRange;
12use vfs::{FileId, ReadOnlyVfs};
13
14#[derive(Debug)]
15pub struct LintResult {
16 pub file_id: FileId,
17 pub reports: Vec<Report>,
18}
19
20pub trait WriteDiagnostic {
21 fn write(&mut self, report: &LintResult, vfs: &ReadOnlyVfs) -> io::Result<()>;
22}
23
24impl<T> WriteDiagnostic for T
25where
26 T: Write,
27{
28 fn write(&mut self, lint_result: &LintResult, vfs: &ReadOnlyVfs) -> io::Result<()> {
29 let file_id = lint_result.file_id;
30 let src = str::from_utf8(vfs.get(file_id)).unwrap();
31 let path = vfs.file_path(file_id);
32 let range = |at: TextRange| at.start().into()..at.end().into();
33 let src_id = path.to_str().unwrap_or("<unknown>");
34 for report in lint_result.reports.iter() {
35 let offset = report
36 .diagnostics
37 .iter()
38 .map(|d| d.at.start().into())
39 .min()
40 .unwrap_or(0usize);
41 report
42 .diagnostics
43 .iter()
44 .fold(
45 CliReport::build(CliReportKind::Warning, src_id, offset)
46 .with_config(
47 CliConfig::default()
48 .with_cross_gap(true)
49 .with_multiline_arrows(false)
50 .with_label_attach(LabelAttach::Middle)
51 .with_char_set(CharSet::Unicode),
52 )
53 .with_message(report.note)
54 .with_code(report.code),
55 |cli_report, diagnostic| {
56 cli_report.with_label(
57 Label::new((src_id, range(diagnostic.at)))
58 .with_message(&colorize(&diagnostic.message))
59 .with_color(Color::Magenta),
60 )
61 },
62 )
63 .finish()
64 .write((src_id, Source::from(src)), &mut *self)?;
65 }
66 Ok(())
67 }
68}
69
70// everything within backticks is colorized, backticks are removed
71fn colorize(message: &str) -> String {
72 message.split('`')
73 .enumerate()
74 .map(|(idx, part)| {
75 if idx % 2 == 1 {
76 part.fg(Color::Cyan).to_string()
77 } else {
78 part.to_string()
79 }
80 })
81 .collect::<Vec<_>>()
82 .join("")
83}