From 393c28566206b4a077be3cfb0e4e931544f0709e Mon Sep 17 00:00:00 2001 From: Akshay Date: Tue, 26 Oct 2021 19:16:52 +0530 Subject: fix single fix command --- bin/src/config.rs | 4 ++++ bin/src/fix/single.rs | 35 +++++++++++++++++++++-------------- 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 { /// Position to attempt a fix at #[clap(short, long, parse(try_from_str = parse_line_col))] pub position: (usize, usize), + + /// Do not fix files in place, display a diff instead + #[clap(short, long = "dry-run")] + pub diff_only: bool, } 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 @@ use std::{borrow::Cow, convert::TryFrom}; use lib::{Report, LINTS}; -use rnix::{TextRange, TextSize}; +use rnix::{TextSize, WalkEvent}; use crate::err::SingleFixErr; use crate::fix::Source; @@ -12,7 +12,7 @@ pub struct SingleFixResult<'δ> { fn pos_to_byte(line: usize, col: usize, src: &str) -> Result { let mut byte: TextSize = TextSize::of(""); - for (_, l) in src.lines().enumerate().take_while(|(i, _)| i <= &line) { + for (l, _) in src.split_inclusive('\n').zip(1..).take_while(|(_, i)| i < &line) { byte += TextSize::of(l); } 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 Result { + let offset = offset - TextSize::from(1u32); // we don't really need the source to form a completely parsed tree let parsed = rnix::parse(src); - let elem_at = parsed + parsed .node() - .child_or_token_at_range(TextRange::empty(offset)) - .ok_or(SingleFixErr::NoOp)?; - - LINTS - .get(&elem_at.kind()) - .map(|rules| { - rules - .iter() - .filter_map(|rule| rule.validate(&elem_at)) - .filter(|report| report.total_suggestion_range().is_some()) - .next() + .preorder_with_tokens() + .filter_map(|event| match event { + WalkEvent::Enter(child) => { + if child.text_range().start() == offset { + LINTS.get(&child.kind()).map(|rules| { + rules + .iter() + .filter_map(|rule| rule.validate(&child)) + .filter(|report| report.total_suggestion_range().is_some()) + .next() + }) + } else { + None + } + }, + _ => None }) .flatten() + .next() .ok_or(SingleFixErr::NoOp) } 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> { let path = single_config.target; let src = std::fs::read_to_string(&path).map_err(SingleFixErr::InvalidPath)?; let (line, col) = single_config.position; - let single_result = fix::single(line, col, &src)?; - std::fs::write(&path, &*single_result.src).map_err(SingleFixErr::InvalidPath)?; + let single_fix_result = fix::single(line, col, &src)?; + if single_config.diff_only { + let text_diff = TextDiff::from_lines(src.as_str(), &single_fix_result.src); + let old_file = format!("{}", path.display()); + let new_file = format!("{} [fixed]", path.display()); + println!( + "{}", + text_diff + .unified_diff() + .context_radius(4) + .header(&old_file, &new_file) + ); + } else { + std::fs::write(&path, &*single_fix_result.src).map_err(SingleFixErr::InvalidPath)?; + } } } Ok(()) -- cgit v1.2.3