Lints and suggestions for the Nix programming language
at main 125 lines 3.9 kB view raw
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}