aboutsummaryrefslogtreecommitdiff
path: root/bin/src/fix.rs
blob: da5a4707dc58016d6bb9ccb80fdd99da24f37b07 (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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use std::borrow::Cow;

use crate::LintMap;

use lib::session::SessionInfo;
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,
    pub sess: &'a SessionInfo,
}

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

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

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

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

    use lib::session::SessionInfo;
    use similar::TextDiff;

    pub fn all(fix_config: FixConfig) -> Result<(), StatixErr> {
        let conf_file = ConfFile::discover(&fix_config.conf_path)?;
        let vfs = fix_config.vfs(conf_file.ignore.as_slice())?;

        let lints = conf_file.lints();
        let version = conf_file.version()?;

        let session = SessionInfo::from_version(version);

        for entry in vfs.iter() {
            match (
                fix_config.out(),
                super::all_with(entry.contents, &lints, &session),
            ) {
                (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;

        let conf_file = ConfFile::discover(&single_config.conf_path)?;

        let version = conf_file.version()?;

        let session = SessionInfo::from_version(version);

        match (
            single_config.out(),
            super::single(line, col, original_src, &session),
        ) {
            (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(())
    }
}