Lints and suggestions for the Nix programming language
1use std::borrow::Cow;
2
3use crate::LintMap;
4
5use rnix::TextRange;
6
7mod all;
8use all::all_with;
9
10mod single;
11use single::single;
12
13type Source<'a> = Cow<'a, str>;
14
15pub struct FixResult<'a> {
16 pub src: Source<'a>,
17 pub fixed: Vec<Fixed>,
18 pub lints: &'a LintMap,
19}
20
21#[derive(Debug, Clone)]
22pub struct Fixed {
23 pub at: TextRange,
24 pub code: u32,
25}
26
27impl<'a> FixResult<'a> {
28 fn empty(src: Source<'a>, lints: &'a LintMap) -> Self {
29 Self {
30 src,
31 fixed: Vec::new(),
32 lints,
33 }
34 }
35}
36
37pub mod main {
38 use std::borrow::Cow;
39
40 use crate::{
41 config::{
42 FixOut, Single as SingleConfig, {ConfFile, Fix as FixConfig},
43 },
44 err::{FixErr, StatixErr},
45 };
46
47 use similar::TextDiff;
48
49 pub fn all(fix_config: &FixConfig) -> Result<(), StatixErr> {
50 let conf_file = ConfFile::discover(&fix_config.conf_path)?;
51 let vfs = fix_config.vfs(conf_file.ignore.as_slice())?;
52
53 let lints = conf_file.lints();
54
55 for entry in vfs.iter() {
56 match (fix_config.out(), super::all_with(entry.contents, &lints)) {
57 (FixOut::Diff, fix_result) => {
58 let src = fix_result
59 .map(|r| r.src)
60 .unwrap_or(Cow::Borrowed(entry.contents));
61 let text_diff = TextDiff::from_lines(entry.contents, &src);
62 let old_file = format!("{}", entry.file_path.display());
63 let new_file = format!("{} [fixed]", entry.file_path.display());
64 println!(
65 "{}",
66 text_diff
67 .unified_diff()
68 .context_radius(4)
69 .header(&old_file, &new_file)
70 );
71 }
72 (FixOut::Stream, fix_result) => {
73 let src = fix_result
74 .map(|r| r.src)
75 .unwrap_or(Cow::Borrowed(entry.contents));
76 println!("{}", &src);
77 }
78 (FixOut::Write, Some(fix_result)) => {
79 let path = entry.file_path;
80 std::fs::write(path, &*fix_result.src).map_err(FixErr::InvalidPath)?;
81 }
82 _ => (),
83 }
84 }
85 Ok(())
86 }
87
88 pub fn single(single_config: &SingleConfig) -> Result<(), StatixErr> {
89 let vfs = single_config.vfs()?;
90 let entry = vfs.iter().next().unwrap();
91 let path = entry.file_path.display().to_string();
92 let original_src = entry.contents;
93 let (line, col) = single_config.position;
94
95 match (single_config.out(), super::single(line, col, original_src)) {
96 (FixOut::Diff, single_result) => {
97 let fixed_src = single_result
98 .map(|r| r.src)
99 .unwrap_or(Cow::Borrowed(original_src));
100 let text_diff = TextDiff::from_lines(original_src, &fixed_src);
101 let old_file = &path;
102 let new_file = format!("{} [fixed]", &path);
103 println!(
104 "{}",
105 text_diff
106 .unified_diff()
107 .context_radius(4)
108 .header(old_file, &new_file)
109 );
110 }
111 (FixOut::Stream, single_result) => {
112 let src = single_result
113 .map(|r| r.src)
114 .unwrap_or(Cow::Borrowed(original_src));
115 println!("{}", &src);
116 }
117 (FixOut::Write, Ok(single_result)) => {
118 let path = entry.file_path;
119 std::fs::write(path, &*single_result.src).map_err(FixErr::InvalidPath)?;
120 }
121 (_, Err(e)) => return Err(e.into()),
122 }
123 Ok(())
124 }
125}