diff options
Diffstat (limited to 'bin/src')
-rw-r--r-- | bin/src/main.rs | 2 | ||||
-rw-r--r-- | bin/src/traits.rs | 135 |
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 | ||
6 | use crate::lint::LintResult; | 6 | use crate::{config::OutFormat, lint::LintResult}; |
7 | 7 | ||
8 | use ariadne::{ | 8 | use 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; | |||
13 | use vfs::ReadOnlyVfs; | 13 | use vfs::ReadOnlyVfs; |
14 | 14 | ||
15 | pub trait WriteDiagnostic { | 15 | pub 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 | ||
19 | impl<T> WriteDiagnostic for T | 24 | impl<T> WriteDiagnostic for T |
20 | where | 25 | where |
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 | ||
42 | fn 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 | |||
87 | fn 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 | |||
110 | fn line(at: TextRange, src: &str) -> usize { | ||
111 | let at = at.start().into(); | ||
112 | src[..at].chars().filter(|&c| c == '\n').count() + 1 | ||
113 | } | ||
114 | |||
115 | fn 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 |
66 | fn colorize(message: &str) -> String { | 121 | fn colorize(message: &str) -> String { |
67 | message | 122 | message |