aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bin/src/config.rs4
-rw-r--r--bin/src/fix/single.rs23
-rw-r--r--bin/src/main.rs25
-rw-r--r--flake.nix9
-rw-r--r--lib/src/lib.rs7
-rw-r--r--vim-plugin/ftplugin/nix.vim8
-rw-r--r--vim-plugin/plugin/statix.vim14
7 files changed, 67 insertions, 23 deletions
diff --git a/bin/src/config.rs b/bin/src/config.rs
index c856a59..79bed35 100644
--- a/bin/src/config.rs
+++ b/bin/src/config.rs
@@ -77,8 +77,8 @@ impl Fix {
77#[derive(Clap, Debug)] 77#[derive(Clap, Debug)]
78pub struct Single { 78pub struct Single {
79 /// File to run single-fix on 79 /// File to run single-fix on
80 #[clap(default_value = ".", parse(from_os_str))] 80 #[clap(parse(from_os_str))]
81 pub target: PathBuf, 81 pub target: Option<PathBuf>,
82 82
83 /// Position to attempt a fix at 83 /// Position to attempt a fix at
84 #[clap(short, long, parse(try_from_str = parse_line_col))] 84 #[clap(short, long, parse(try_from_str = parse_line_col))]
diff --git a/bin/src/fix/single.rs b/bin/src/fix/single.rs
index c09c710..4d492f8 100644
--- a/bin/src/fix/single.rs
+++ b/bin/src/fix/single.rs
@@ -15,7 +15,7 @@ fn pos_to_byte(line: usize, col: usize, src: &str) -> Result<TextSize, SingleFix
15 for (l, _) in src 15 for (l, _) in src
16 .split_inclusive('\n') 16 .split_inclusive('\n')
17 .zip(1..) 17 .zip(1..)
18 .take_while(|(_, i)| i < &line) 18 .take_while(|(_, i)| *i < line)
19 { 19 {
20 byte += TextSize::of(l); 20 byte += TextSize::of(l);
21 } 21 }
@@ -29,7 +29,6 @@ fn pos_to_byte(line: usize, col: usize, src: &str) -> Result<TextSize, SingleFix
29} 29}
30 30
31fn find(offset: TextSize, src: &str) -> Result<Report, SingleFixErr> { 31fn find(offset: TextSize, src: &str) -> Result<Report, SingleFixErr> {
32 let offset = offset - TextSize::from(1u32);
33 // we don't really need the source to form a completely parsed tree 32 // we don't really need the source to form a completely parsed tree
34 let parsed = rnix::parse(src); 33 let parsed = rnix::parse(src);
35 34
@@ -38,22 +37,18 @@ fn find(offset: TextSize, src: &str) -> Result<Report, SingleFixErr> {
38 .preorder_with_tokens() 37 .preorder_with_tokens()
39 .filter_map(|event| match event { 38 .filter_map(|event| match event {
40 WalkEvent::Enter(child) => { 39 WalkEvent::Enter(child) => {
41 if child.text_range().start() == offset { 40 LINTS.get(&child.kind()).map(|rules| {
42 LINTS.get(&child.kind()).map(|rules| { 41 rules
43 rules 42 .iter()
44 .iter() 43 .filter_map(|rule| rule.validate(&child))
45 .filter_map(|rule| rule.validate(&child)) 44 .filter(|report| report.total_suggestion_range().is_some())
46 .filter(|report| report.total_suggestion_range().is_some()) 45 .next()
47 .next() 46 })
48 })
49 } else {
50 None
51 }
52 } 47 }
53 _ => None, 48 _ => None,
54 }) 49 })
55 .flatten() 50 .flatten()
56 .next() 51 .find(|report| report.total_diagnostic_range().unwrap().contains(offset))
57 .ok_or(SingleFixErr::NoOp) 52 .ok_or(SingleFixErr::NoOp)
58} 53}
59 54
diff --git a/bin/src/main.rs b/bin/src/main.rs
index 4063621..9e9c8ac 100644
--- a/bin/src/main.rs
+++ b/bin/src/main.rs
@@ -4,7 +4,7 @@ mod fix;
4mod lint; 4mod lint;
5mod traits; 5mod traits;
6 6
7use std::io; 7use std::io::{self, BufRead};
8 8
9use crate::{ 9use crate::{
10 err::{FixErr, SingleFixErr, StatixErr}, 10 err::{FixErr, SingleFixErr, StatixErr},
@@ -55,15 +55,26 @@ fn _main() -> Result<(), StatixErr> {
55 } 55 }
56 } 56 }
57 } 57 }
58 // FIXME: this block nasty, configure in/out streams in `impl Single` maybe
58 SubCommand::Single(single_config) => { 59 SubCommand::Single(single_config) => {
59 let path = single_config.target; 60 let src = if let Some(path) = &single_config.target {
60 let src = std::fs::read_to_string(&path).map_err(SingleFixErr::InvalidPath)?; 61 std::fs::read_to_string(&path).map_err(SingleFixErr::InvalidPath)?
62 } else {
63 io::stdin().lock().lines().map(|l| l.unwrap()).collect::<Vec<String>>().join("\n")
64 };
65
66 let path_id = if let Some(path) = &single_config.target {
67 path.display().to_string()
68 } else {
69 "<unknown>".to_owned()
70 };
71
61 let (line, col) = single_config.position; 72 let (line, col) = single_config.position;
62 let single_fix_result = fix::single(line, col, &src)?; 73 let single_fix_result = fix::single(line, col, &src)?;
63 if single_config.diff_only { 74 if single_config.diff_only {
64 let text_diff = TextDiff::from_lines(src.as_str(), &single_fix_result.src); 75 let text_diff = TextDiff::from_lines(src.as_str(), &single_fix_result.src);
65 let old_file = format!("{}", path.display()); 76 let old_file = format!("{}", path_id);
66 let new_file = format!("{} [fixed]", path.display()); 77 let new_file = format!("{} [fixed]", path_id);
67 println!( 78 println!(
68 "{}", 79 "{}",
69 text_diff 80 text_diff
@@ -71,9 +82,11 @@ fn _main() -> Result<(), StatixErr> {
71 .context_radius(4) 82 .context_radius(4)
72 .header(&old_file, &new_file) 83 .header(&old_file, &new_file)
73 ); 84 );
74 } else { 85 } else if let Some(path) = single_config.target {
75 std::fs::write(&path, &*single_fix_result.src) 86 std::fs::write(&path, &*single_fix_result.src)
76 .map_err(SingleFixErr::InvalidPath)?; 87 .map_err(SingleFixErr::InvalidPath)?;
88 } else {
89 print!("{}", &*single_fix_result.src)
77 } 90 }
78 } 91 }
79 } 92 }
diff --git a/flake.nix b/flake.nix
index 9bef554..8c86114 100644
--- a/flake.nix
+++ b/flake.nix
@@ -69,10 +69,17 @@
69 ''; 69 '';
70 }; 70 };
71 71
72 statix-vim =
73 with final; pkgs.vimUtils.buildVimPlugin {
74 pname = "statix-vim";
75 version = "0.1.0";
76 src = ./vim-plugin;
77 };
78
72 }; 79 };
73 80
74 packages = forAllSystems (system: { 81 packages = forAllSystems (system: {
75 inherit (nixpkgsFor."${system}") statix; 82 inherit (nixpkgsFor."${system}") statix statix-vim;
76 }); 83 });
77 84
78 defaultPackage = 85 defaultPackage =
diff --git a/lib/src/lib.rs b/lib/src/lib.rs
index 41e38c8..c2f24c6 100644
--- a/lib/src/lib.rs
+++ b/lib/src/lib.rs
@@ -56,6 +56,13 @@ impl Report {
56 .flat_map(|d| Some(d.suggestion.as_ref()?.at)) 56 .flat_map(|d| Some(d.suggestion.as_ref()?.at))
57 .reduce(|acc, next| acc.cover(next)) 57 .reduce(|acc, next| acc.cover(next))
58 } 58 }
59 /// A range that encompasses all the diagnostics provided in this report
60 pub fn total_diagnostic_range(&self) -> Option<TextRange> {
61 self.diagnostics
62 .iter()
63 .flat_map(|d| Some(d.at))
64 .reduce(|acc, next| acc.cover(next))
65 }
59 /// Unsafe but handy replacement for above 66 /// Unsafe but handy replacement for above
60 pub fn range(&self) -> TextRange { 67 pub fn range(&self) -> TextRange {
61 self.total_suggestion_range().unwrap() 68 self.total_suggestion_range().unwrap()
diff --git a/vim-plugin/ftplugin/nix.vim b/vim-plugin/ftplugin/nix.vim
new file mode 100644
index 0000000..885857f
--- /dev/null
+++ b/vim-plugin/ftplugin/nix.vim
@@ -0,0 +1,8 @@
1setlocal makeprg=statix\ check\ -o\ errfmt\ %
2setlocal errorformat=%f>%l:%c:%t:%n:%m
3
4augroup StatixCheck
5 autocmd!
6 autocmd! BufWritePost *.nix | silent make! | silent redraw!
7 autocmd QuickFixCmdPost [^l]* cwindow
8augroup END
diff --git a/vim-plugin/plugin/statix.vim b/vim-plugin/plugin/statix.vim
new file mode 100644
index 0000000..736cce2
--- /dev/null
+++ b/vim-plugin/plugin/statix.vim
@@ -0,0 +1,14 @@
1function! ApplyStatixSuggestion()
2 let l:l = line('.')
3 let l:c = col('.')
4 let l:filter = "%!statix single -p " . l . "," . c . ""
5 execute l:filter
6
7 silent if v:shell_error == 1
8 undo
9 endif
10
11 call cursor(l, c)
12endfunction
13
14nnoremap gf :call ApplyStatixSuggestion()<cr>