diff options
-rw-r--r-- | bin/src/config.rs | 4 | ||||
-rw-r--r-- | bin/src/fix/single.rs | 35 | ||||
-rw-r--r-- | bin/src/main.rs | 17 |
3 files changed, 40 insertions, 16 deletions
diff --git a/bin/src/config.rs b/bin/src/config.rs index fc4057a..8ddfb4a 100644 --- a/bin/src/config.rs +++ b/bin/src/config.rs | |||
@@ -83,6 +83,10 @@ pub struct Single { | |||
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))] |
85 | pub position: (usize, usize), | 85 | pub position: (usize, usize), |
86 | |||
87 | /// Do not fix files in place, display a diff instead | ||
88 | #[clap(short, long = "dry-run")] | ||
89 | pub diff_only: bool, | ||
86 | } | 90 | } |
87 | 91 | ||
88 | mod dirs { | 92 | mod dirs { |
diff --git a/bin/src/fix/single.rs b/bin/src/fix/single.rs index d430693..24b5c51 100644 --- a/bin/src/fix/single.rs +++ b/bin/src/fix/single.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use std::{borrow::Cow, convert::TryFrom}; | 1 | use std::{borrow::Cow, convert::TryFrom}; |
2 | 2 | ||
3 | use lib::{Report, LINTS}; | 3 | use lib::{Report, LINTS}; |
4 | use rnix::{TextRange, TextSize}; | 4 | use rnix::{TextSize, WalkEvent}; |
5 | 5 | ||
6 | use crate::err::SingleFixErr; | 6 | use crate::err::SingleFixErr; |
7 | use crate::fix::Source; | 7 | use crate::fix::Source; |
@@ -12,7 +12,7 @@ pub struct SingleFixResult<'δ> { | |||
12 | 12 | ||
13 | fn pos_to_byte(line: usize, col: usize, src: &str) -> Result<TextSize, SingleFixErr> { | 13 | fn pos_to_byte(line: usize, col: usize, src: &str) -> Result<TextSize, SingleFixErr> { |
14 | let mut byte: TextSize = TextSize::of(""); | 14 | let mut byte: TextSize = TextSize::of(""); |
15 | for (_, l) in src.lines().enumerate().take_while(|(i, _)| i <= &line) { | 15 | for (l, _) in src.split_inclusive('\n').zip(1..).take_while(|(_, i)| i < &line) { |
16 | byte += TextSize::of(l); | 16 | byte += TextSize::of(l); |
17 | } | 17 | } |
18 | byte += TextSize::try_from(col).map_err(|_| SingleFixErr::Conversion(col))?; | 18 | byte += TextSize::try_from(col).map_err(|_| SingleFixErr::Conversion(col))?; |
@@ -25,24 +25,31 @@ fn pos_to_byte(line: usize, col: usize, src: &str) -> Result<TextSize, SingleFix | |||
25 | } | 25 | } |
26 | 26 | ||
27 | fn find(offset: TextSize, src: &str) -> Result<Report, SingleFixErr> { | 27 | fn find(offset: TextSize, src: &str) -> Result<Report, SingleFixErr> { |
28 | let offset = offset - TextSize::from(1u32); | ||
28 | // we don't really need the source to form a completely parsed tree | 29 | // we don't really need the source to form a completely parsed tree |
29 | let parsed = rnix::parse(src); | 30 | let parsed = rnix::parse(src); |
30 | 31 | ||
31 | let elem_at = parsed | 32 | parsed |
32 | .node() | 33 | .node() |
33 | .child_or_token_at_range(TextRange::empty(offset)) | 34 | .preorder_with_tokens() |
34 | .ok_or(SingleFixErr::NoOp)?; | 35 | .filter_map(|event| match event { |
35 | 36 | WalkEvent::Enter(child) => { | |
36 | LINTS | 37 | if child.text_range().start() == offset { |
37 | .get(&elem_at.kind()) | 38 | LINTS.get(&child.kind()).map(|rules| { |
38 | .map(|rules| { | 39 | rules |
39 | rules | 40 | .iter() |
40 | .iter() | 41 | .filter_map(|rule| rule.validate(&child)) |
41 | .filter_map(|rule| rule.validate(&elem_at)) | 42 | .filter(|report| report.total_suggestion_range().is_some()) |
42 | .filter(|report| report.total_suggestion_range().is_some()) | 43 | .next() |
43 | .next() | 44 | }) |
45 | } else { | ||
46 | None | ||
47 | } | ||
48 | }, | ||
49 | _ => None | ||
44 | }) | 50 | }) |
45 | .flatten() | 51 | .flatten() |
52 | .next() | ||
46 | .ok_or(SingleFixErr::NoOp) | 53 | .ok_or(SingleFixErr::NoOp) |
47 | } | 54 | } |
48 | 55 | ||
diff --git a/bin/src/main.rs b/bin/src/main.rs index 9c57d91..cbf2601 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs | |||
@@ -55,8 +55,21 @@ fn _main() -> Result<(), StatixErr> { | |||
55 | let path = single_config.target; | 55 | let path = single_config.target; |
56 | let src = std::fs::read_to_string(&path).map_err(SingleFixErr::InvalidPath)?; | 56 | let src = std::fs::read_to_string(&path).map_err(SingleFixErr::InvalidPath)?; |
57 | let (line, col) = single_config.position; | 57 | let (line, col) = single_config.position; |
58 | let single_result = fix::single(line, col, &src)?; | 58 | let single_fix_result = fix::single(line, col, &src)?; |
59 | std::fs::write(&path, &*single_result.src).map_err(SingleFixErr::InvalidPath)?; | 59 | if single_config.diff_only { |
60 | let text_diff = TextDiff::from_lines(src.as_str(), &single_fix_result.src); | ||
61 | let old_file = format!("{}", path.display()); | ||
62 | let new_file = format!("{} [fixed]", path.display()); | ||
63 | println!( | ||
64 | "{}", | ||
65 | text_diff | ||
66 | .unified_diff() | ||
67 | .context_radius(4) | ||
68 | .header(&old_file, &new_file) | ||
69 | ); | ||
70 | } else { | ||
71 | std::fs::write(&path, &*single_fix_result.src).map_err(SingleFixErr::InvalidPath)?; | ||
72 | } | ||
60 | } | 73 | } |
61 | } | 74 | } |
62 | Ok(()) | 75 | Ok(()) |