aboutsummaryrefslogtreecommitdiff
path: root/bin/src
diff options
context:
space:
mode:
Diffstat (limited to 'bin/src')
-rw-r--r--bin/src/main.rs2
-rw-r--r--bin/src/traits.rs135
2 files changed, 96 insertions, 41 deletions
diff --git a/bin/src/main.rs b/bin/src/main.rs
index 4cd525a..6f0343e 100644
--- a/bin/src/main.rs
+++ b/bin/src/main.rs
@@ -49,7 +49,7 @@ fn _main() -> Result<(), StatixErr> {
49 49
50 let mut stderr = io::stderr(); 50 let mut stderr = io::stderr();
51 lint_results.for_each(|r| { 51 lint_results.for_each(|r| {
52 stderr.write(&r, &vfs).unwrap(); 52 stderr.write(&r, &vfs, lint_config.format).unwrap();
53 }); 53 });
54 errors.for_each(|e| { 54 errors.for_each(|e| {
55 eprintln!("{}", e); 55 eprintln!("{}", e);
diff --git a/bin/src/traits.rs b/bin/src/traits.rs
index c3427df..5cf7208 100644
--- a/bin/src/traits.rs
+++ b/bin/src/traits.rs
@@ -3,7 +3,7 @@ use std::{
3 str, 3 str,
4}; 4};
5 5
6use crate::lint::LintResult; 6use crate::{config::OutFormat, lint::LintResult};
7 7
8use ariadne::{ 8use ariadne::{
9 CharSet, Color, Config as CliConfig, Fmt, Label, LabelAttach, Report as CliReport, 9 CharSet, Color, Config as CliConfig, Fmt, Label, LabelAttach, Report as CliReport,
@@ -13,55 +13,110 @@ use rnix::TextRange;
13use vfs::ReadOnlyVfs; 13use vfs::ReadOnlyVfs;
14 14
15pub trait WriteDiagnostic { 15pub trait WriteDiagnostic {
16 fn write(&mut self, report: &LintResult, vfs: &ReadOnlyVfs) -> io::Result<()>; 16 fn write(
17 &mut self,
18 report: &LintResult,
19 vfs: &ReadOnlyVfs,
20 format: OutFormat,
21 ) -> io::Result<()>;
17} 22}
18 23
19impl<T> WriteDiagnostic for T 24impl<T> WriteDiagnostic for T
20where 25where
21 T: Write, 26 T: Write,
22{ 27{
23 fn write(&mut self, lint_result: &LintResult, vfs: &ReadOnlyVfs) -> io::Result<()> { 28 fn write(
24 let file_id = lint_result.file_id; 29 &mut self,
25 let src = str::from_utf8(vfs.get(file_id)).unwrap(); 30 lint_result: &LintResult,
26 let path = vfs.file_path(file_id); 31 vfs: &ReadOnlyVfs,
27 let range = |at: TextRange| at.start().into()..at.end().into(); 32 format: OutFormat,
28 let src_id = path.to_str().unwrap_or("<unknown>"); 33 ) -> io::Result<()> {
29 for report in lint_result.reports.iter() { 34 match format {
30 let offset = report 35 OutFormat::StdErr => write_stderr(self, lint_result, vfs),
31 .diagnostics 36 OutFormat::Errfmt => write_errfmt(self, lint_result, vfs),
32 .iter() 37 _ => Ok(()),
33 .map(|d| d.at.start().into())
34 .min()
35 .unwrap_or(0usize);
36 report
37 .diagnostics
38 .iter()
39 .fold(
40 CliReport::build(CliReportKind::Warning, src_id, offset)
41 .with_config(
42 CliConfig::default()
43 .with_cross_gap(true)
44 .with_multiline_arrows(false)
45 .with_label_attach(LabelAttach::Middle)
46 .with_char_set(CharSet::Unicode),
47 )
48 .with_message(report.note)
49 .with_code(report.code),
50 |cli_report, diagnostic| {
51 cli_report.with_label(
52 Label::new((src_id, range(diagnostic.at)))
53 .with_message(&colorize(&diagnostic.message))
54 .with_color(Color::Magenta),
55 )
56 },
57 )
58 .finish()
59 .write((src_id, Source::from(src)), &mut *self)?;
60 } 38 }
61 Ok(())
62 } 39 }
63} 40}
64 41
42fn write_stderr<T: Write>(
43 writer: &mut T,
44 lint_result: &LintResult,
45 vfs: &ReadOnlyVfs,
46) -> io::Result<()> {
47 let file_id = lint_result.file_id;
48 let src = str::from_utf8(vfs.get(file_id)).unwrap();
49 let path = vfs.file_path(file_id);
50 let range = |at: TextRange| at.start().into()..at.end().into();
51 let src_id = path.to_str().unwrap_or("<unknown>");
52 for report in lint_result.reports.iter() {
53 let offset = report
54 .diagnostics
55 .iter()
56 .map(|d| d.at.start().into())
57 .min()
58 .unwrap_or(0usize);
59 report
60 .diagnostics
61 .iter()
62 .fold(
63 CliReport::build(CliReportKind::Warning, src_id, offset)
64 .with_config(
65 CliConfig::default()
66 .with_cross_gap(true)
67 .with_multiline_arrows(false)
68 .with_label_attach(LabelAttach::Middle)
69 .with_char_set(CharSet::Unicode),
70 )
71 .with_message(report.note)
72 .with_code(report.code),
73 |cli_report, diagnostic| {
74 cli_report.with_label(
75 Label::new((src_id, range(diagnostic.at)))
76 .with_message(&colorize(&diagnostic.message))
77 .with_color(Color::Magenta),
78 )
79 },
80 )
81 .finish()
82 .write((src_id, Source::from(src)), &mut *writer)?;
83 }
84 Ok(())
85}
86
87fn write_errfmt<T: Write>(writer: &mut T, lint_result: &LintResult, vfs: &ReadOnlyVfs) -> io::Result<()> {
88 let file_id = lint_result.file_id;
89 let src = str::from_utf8(vfs.get(file_id)).unwrap();
90 let path = vfs.file_path(file_id);
91 for report in lint_result.reports.iter() {
92 for diagnostic in report.diagnostics.iter() {
93 let line = line(diagnostic.at, &src);
94 let col = column(diagnostic.at, &src);
95 writeln!(
96 writer,
97 "{filename}>{linenumber}:{columnnumber}:{errortype}:{errornumber}:{errormessage}",
98 filename = path.to_str().unwrap_or("<unknown>"),
99 linenumber = line,
100 columnnumber = col,
101 errortype = "W",
102 errornumber = report.code,
103 errormessage = diagnostic.message
104 )?;
105 }
106 }
107 Ok(())
108}
109
110fn line(at: TextRange, src: &str) -> usize {
111 let at = at.start().into();
112 src[..at].chars().filter(|&c| c == '\n').count() + 1
113}
114
115fn column(at: TextRange, src: &str) -> usize {
116 let at = at.start().into();
117 src[..at].rfind('\n').map(|c| at - c).unwrap_or(at + 1)
118}
119
65// everything within backticks is colorized, backticks are removed 120// everything within backticks is colorized, backticks are removed
66fn colorize(message: &str) -> String { 121fn colorize(message: &str) -> String {
67 message 122 message