diff options
Diffstat (limited to 'bin/src/main.rs')
-rw-r--r-- | bin/src/main.rs | 112 |
1 files changed, 46 insertions, 66 deletions
diff --git a/bin/src/main.rs b/bin/src/main.rs index ab99aee..b26151d 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs | |||
@@ -1,20 +1,28 @@ | |||
1 | use std::{ | 1 | #![feature(path_try_exists)] |
2 | env, fs, | 2 | |
3 | path::{Path, PathBuf}, | 3 | mod config; |
4 | }; | 4 | mod err; |
5 | mod traits; | ||
5 | 6 | ||
6 | use anyhow::{Context, Result}; | 7 | use std::io; |
7 | use ariadne::{ | 8 | |
8 | CharSet, Color, Config as CliConfig, Label, LabelAttach, Report as CliReport, | 9 | use crate::{ |
9 | ReportKind as CliReportKind, Source, | 10 | err::{LintErr, StatixErr}, |
11 | traits::{LintResult, WriteDiagnostic}, | ||
10 | }; | 12 | }; |
11 | use lib::{Report, LINTS}; | ||
12 | use rnix::{TextRange, WalkEvent}; | ||
13 | 13 | ||
14 | fn analyze(source: &str) -> Result<Vec<Report>> { | 14 | use clap::Clap; |
15 | let parsed = rnix::parse(source).as_result()?; | 15 | use config::{LintConfig, Opts, SubCommand}; |
16 | use lib::LINTS; | ||
17 | use rnix::WalkEvent; | ||
18 | use vfs::VfsEntry; | ||
16 | 19 | ||
17 | Ok(parsed | 20 | fn analyze<'ρ>(vfs_entry: VfsEntry<'ρ>) -> Result<LintResult, LintErr> { |
21 | let source = vfs_entry.contents; | ||
22 | let parsed = rnix::parse(source) | ||
23 | .as_result() | ||
24 | .map_err(|e| LintErr::Parse(vfs_entry.file_path.to_path_buf(), e))?; | ||
25 | let reports = parsed | ||
18 | .node() | 26 | .node() |
19 | .preorder_with_tokens() | 27 | .preorder_with_tokens() |
20 | .filter_map(|event| match event { | 28 | .filter_map(|event| match event { |
@@ -27,61 +35,33 @@ fn analyze(source: &str) -> Result<Vec<Report>> { | |||
27 | _ => None, | 35 | _ => None, |
28 | }) | 36 | }) |
29 | .flatten() | 37 | .flatten() |
30 | .collect()) | 38 | .collect(); |
39 | Ok(LintResult { | ||
40 | file_id: vfs_entry.file_id, | ||
41 | reports, | ||
42 | }) | ||
31 | } | 43 | } |
32 | 44 | ||
33 | fn print_report(report: Report, file_src: &str, file_path: &Path) -> Result<()> { | 45 | fn _main() -> Result<(), StatixErr> { |
34 | let range = |at: TextRange| at.start().into()..at.end().into(); | ||
35 | let src_id = file_path.to_str().unwrap_or("<unknown>"); | ||
36 | let offset = report | ||
37 | .diagnostics | ||
38 | .iter() | ||
39 | .map(|d| d.at.start().into()) | ||
40 | .min() | ||
41 | .unwrap_or(0usize); | ||
42 | report | ||
43 | .diagnostics | ||
44 | .iter() | ||
45 | .fold( | ||
46 | CliReport::build(CliReportKind::Warning, src_id, offset) | ||
47 | .with_config( | ||
48 | CliConfig::default() | ||
49 | .with_cross_gap(true) | ||
50 | .with_multiline_arrows(false) | ||
51 | .with_label_attach(LabelAttach::Middle) | ||
52 | .with_char_set(CharSet::Unicode), | ||
53 | ) | ||
54 | .with_message(report.note) | ||
55 | .with_code(report.code), | ||
56 | |cli_report, diagnostic| { | ||
57 | cli_report.with_label( | ||
58 | Label::new((src_id, range(diagnostic.at))) | ||
59 | .with_message(&diagnostic.message) | ||
60 | .with_color(Color::Magenta), | ||
61 | ) | ||
62 | }, | ||
63 | ) | ||
64 | .finish() | ||
65 | .eprint((src_id, Source::from(file_src))) | ||
66 | .context("failed to print report to stdout") | ||
67 | } | ||
68 | |||
69 | fn _main() -> Result<()> { | ||
70 | // TODO: accept cli args, construct a CLI config with a list of files to analyze | 46 | // TODO: accept cli args, construct a CLI config with a list of files to analyze |
71 | let args = env::args(); | 47 | let opts = Opts::parse(); |
72 | for (file_src, file_path, reports) in args | 48 | match opts.subcmd { |
73 | .skip(1) | 49 | Some(SubCommand::Fix(_)) => {} |
74 | .map(|s| PathBuf::from(&s)) | 50 | None => { |
75 | .filter(|p| p.is_file()) | 51 | let lint_config = LintConfig::from_opts(opts)?; |
76 | .filter_map(|path| { | 52 | let vfs = lint_config.vfs()?; |
77 | let s = fs::read_to_string(&path).ok()?; | 53 | let (reports, errors): (Vec<_>, Vec<_>) = |
78 | analyze(&s) | 54 | vfs.iter().map(analyze).partition(Result::is_ok); |
79 | .map(|analysis_result| (s, path, analysis_result)) | 55 | let lint_results: Vec<_> = reports.into_iter().map(Result::unwrap).collect(); |
80 | .ok() | 56 | let errors: Vec<_> = errors.into_iter().map(Result::unwrap_err).collect(); |
81 | }) | 57 | |
82 | { | 58 | let mut stderr = io::stderr(); |
83 | for r in reports { | 59 | lint_results.into_iter().for_each(|r| { |
84 | print_report(r, &file_src, &file_path)? | 60 | stderr.write(&r, &vfs).unwrap(); |
61 | }); | ||
62 | errors.into_iter().for_each(|e| { | ||
63 | eprintln!("{}", e); | ||
64 | }); | ||
85 | } | 65 | } |
86 | } | 66 | } |
87 | Ok(()) | 67 | Ok(()) |
@@ -90,6 +70,6 @@ fn _main() -> Result<()> { | |||
90 | fn main() { | 70 | fn main() { |
91 | match _main() { | 71 | match _main() { |
92 | Err(e) => eprintln!("{}", e), | 72 | Err(e) => eprintln!("{}", e), |
93 | _ => {} | 73 | _ => (), |
94 | } | 74 | } |
95 | } | 75 | } |