aboutsummaryrefslogtreecommitdiff
path: root/bin/src/fix.rs
blob: 42685679ca47eb5d1e095f0714c62377e3d2a105 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use std::borrow::Cow;

use crate::LintMap;

use rnix::TextRange;

mod all;
use all::all_with;

mod single;
use single::single;

type Source<'a> = Cow<'a, str>;

pub struct FixResult<'a> {
    pub src: Source<'a>,
    pub fixed: Vec<Fixed>,
    pub lints: &'a LintMap,
}

#[derive(Debug, Clone)]
pub struct Fixed {
    pub at: TextRange,
    pub code: u32,
}

impl<'a> FixResult<'a> {
    fn empty(src: Source<'a>, lints: &'a LintMap) -> Self {
        Self {
            src,
            fixed: Vec::new(),
            lints,
        }
    }
}

pub mod main {
    use std::borrow::Cow;

    use crate::{
        config::{Fix as FixConfig, FixOut, Single as SingleConfig},
        err::{FixErr, StatixErr},
    };

    use similar::TextDiff;

    pub fn all(fix_config: FixConfig) -> Result<(), StatixErr> {
        let vfs = fix_config.vfs()?;
        let lints = fix_config.lints()?;
        for entry in vfs.iter() {
            match (fix_config.out(), super::all_with(entry.contents, &lints)) {
                (FixOut::Diff, fix_result) => {
                    let src = fix_result
                        .map(|r| r.src)
                        .unwrap_or(Cow::Borrowed(entry.contents));
                    let text_diff = TextDiff::from_lines(entry.contents, &src);
                    let old_file = format!("{}", entry.file_path.display());
                    let new_file = format!("{} [fixed]", entry.file_path.display());
                    println!(
                        "{}",
                        text_diff
                            .unified_diff()
                            .context_radius(4)
                            .header(&old_file, &new_file)
                    );
                }
                (FixOut::Stream, fix_result) => {
                    let src = fix_result
                        .map(|r| r.src)
                        .unwrap_or(Cow::Borrowed(entry.contents));
                    println!("{}", &src)
                }
                (FixOut::Write, Some(fix_result)) => {
                    let path = entry.file_path;
                    std::fs::write(path, &*fix_result.src).map_err(FixErr::InvalidPath)?;
                }
                _ => (),
            };
        }
        Ok(())
    }

    pub fn single(single_config: SingleConfig) -> Result<(), StatixErr> {
        let vfs = single_config.vfs()?;
        let entry = vfs.iter().next().unwrap();
        let path = entry.file_path.display().to_string();
        let original_src = entry.contents;
        let (line, col) = single_config.position;

        match (single_config.out(), super::single(line, col, original_src)) {
            (FixOut::Diff, single_result) => {
                let fixed_src = single_result
                    .map(|r| r.src)
                    .unwrap_or(Cow::Borrowed(original_src));
                let text_diff = TextDiff::from_lines(original_src, &fixed_src);
                let old_file = &path;
                let new_file = format!("{} [fixed]", &path);
                println!(
                    "{}",
                    text_diff
                        .unified_diff()
                        .context_radius(4)
                        .header(&old_file, &new_file)
                );
            }
            (FixOut::Stream, single_result) => {
                let src = single_result
                    .map(|r| r.src)
                    .unwrap_or(Cow::Borrowed(original_src));
                println!("{}", &src)
            }
            (FixOut::Write, Ok(single_result)) => {
                let path = entry.file_path;
                std::fs::write(path, &*single_result.src).map_err(FixErr::InvalidPath)?;
            }
            (_, Err(e)) => return Err(e.into()),
        };
        Ok(())
    }
}