aboutsummaryrefslogtreecommitdiff
path: root/crates/rust-analyzer/src/cli/ssr.rs
blob: 4fb829ea5cfd7a5c8acde37e7444613f52bcf8d4 (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
//! Applies structured search replace rules from the command line.

use crate::cli::{load_cargo::load_cargo, Result};
use ra_ide::SourceFileEdit;
use ra_ssr::{MatchFinder, SsrPattern, SsrRule};

pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> {
    use ra_db::SourceDatabaseExt;
    use ra_ide_db::symbol_index::SymbolsDatabase;
    let (host, vfs) = load_cargo(&std::env::current_dir()?, true, true)?;
    let db = host.raw_database();
    let mut match_finder = MatchFinder::new(db);
    for rule in rules {
        match_finder.add_rule(rule);
    }
    let mut edits = Vec::new();
    for &root in db.local_roots().iter() {
        let sr = db.source_root(root);
        for file_id in sr.iter() {
            if let Some(edit) = match_finder.edits_for_file(file_id) {
                edits.push(SourceFileEdit { file_id, edit });
            }
        }
    }
    for edit in edits {
        if let Some(path) = vfs.file_path(edit.file_id).as_path() {
            let mut contents = db.file_text(edit.file_id).to_string();
            edit.edit.apply(&mut contents);
            std::fs::write(path, contents)?;
        }
    }
    Ok(())
}

/// Searches for `patterns`, printing debug information for any nodes whose text exactly matches
/// `debug_snippet`. This is intended for debugging and probably isn't in it's current form useful
/// for much else.
pub fn search_for_patterns(patterns: Vec<SsrPattern>, debug_snippet: Option<String>) -> Result<()> {
    use ra_db::SourceDatabaseExt;
    use ra_ide_db::symbol_index::SymbolsDatabase;
    let (host, vfs) = load_cargo(&std::env::current_dir()?, true, true)?;
    let db = host.raw_database();
    let mut match_finder = MatchFinder::new(db);
    for pattern in patterns {
        match_finder.add_search_pattern(pattern);
    }
    for &root in db.local_roots().iter() {
        let sr = db.source_root(root);
        for file_id in sr.iter() {
            if let Some(debug_snippet) = &debug_snippet {
                for debug_info in match_finder.debug_where_text_equal(file_id, debug_snippet) {
                    println!("{:#?}", debug_info);
                }
            } else {
                let matches = match_finder.find_matches_in_file(file_id);
                if !matches.matches.is_empty() {
                    let matches = matches.flattened().matches;
                    if let Some(path) = vfs.file_path(file_id).as_path() {
                        println!("{} matches in '{}'", matches.len(), path.to_string_lossy());
                    }
                    // We could possibly at some point do something more useful than just printing
                    // the matched text. For now though, that's the easiest thing to do.
                    for m in matches {
                        println!("{}", m.matched_text());
                    }
                }
            }
        }
    }
    Ok(())
}