2020-06-17 01:53:51 -05:00
|
|
|
use ra_db::SourceDatabaseExt;
|
2020-05-06 04:31:26 -05:00
|
|
|
use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase};
|
|
|
|
|
|
|
|
use crate::SourceFileEdit;
|
2020-06-17 01:53:51 -05:00
|
|
|
use ra_ssr::{MatchFinder, SsrError, SsrRule};
|
2020-02-10 16:45:38 -06:00
|
|
|
|
2020-05-31 03:14:36 -05:00
|
|
|
// Feature: Structural Seach and Replace
|
|
|
|
//
|
2020-06-17 01:53:51 -05:00
|
|
|
// Search and replace with named wildcards that will match any expression, type, path, pattern or item.
|
2020-05-31 03:14:36 -05:00
|
|
|
// The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`.
|
2020-06-16 05:01:03 -05:00
|
|
|
// A `$<name>` placeholder in the search pattern will match any AST node and `$<name>` will reference it in the replacement.
|
2020-06-22 03:15:51 -05:00
|
|
|
// Within a macro call, a placeholder will match up until whatever token follows the placeholder.
|
2020-05-31 03:14:36 -05:00
|
|
|
// Available via the command `rust-analyzer.ssr`.
|
|
|
|
//
|
|
|
|
// ```rust
|
2020-06-16 05:01:03 -05:00
|
|
|
// // Using structural search replace command [foo($a, $b) ==>> ($a).foo($b)]
|
2020-05-31 03:14:36 -05:00
|
|
|
//
|
|
|
|
// // BEFORE
|
|
|
|
// String::from(foo(y + 5, z))
|
|
|
|
//
|
|
|
|
// // AFTER
|
|
|
|
// String::from((y + 5).foo(z))
|
|
|
|
// ```
|
|
|
|
//
|
|
|
|
// |===
|
|
|
|
// | Editor | Action Name
|
|
|
|
//
|
|
|
|
// | VS Code | **Rust Analyzer: Structural Search Replace**
|
|
|
|
// |===
|
2020-02-10 16:45:38 -06:00
|
|
|
pub fn parse_search_replace(
|
2020-06-17 01:53:51 -05:00
|
|
|
rule: &str,
|
2020-03-15 16:23:18 -05:00
|
|
|
parse_only: bool,
|
2020-02-10 16:45:38 -06:00
|
|
|
db: &RootDatabase,
|
|
|
|
) -> Result<Vec<SourceFileEdit>, SsrError> {
|
|
|
|
let mut edits = vec![];
|
2020-06-17 01:53:51 -05:00
|
|
|
let rule: SsrRule = rule.parse()?;
|
2020-03-15 16:23:18 -05:00
|
|
|
if parse_only {
|
|
|
|
return Ok(edits);
|
|
|
|
}
|
2020-06-17 01:53:51 -05:00
|
|
|
let mut match_finder = MatchFinder::new(db);
|
|
|
|
match_finder.add_rule(rule);
|
2020-02-10 16:45:38 -06:00
|
|
|
for &root in db.local_roots().iter() {
|
|
|
|
let sr = db.source_root(root);
|
2020-06-11 04:04:09 -05:00
|
|
|
for file_id in sr.iter() {
|
2020-06-17 01:53:51 -05:00
|
|
|
if let Some(edit) = match_finder.edits_for_file(file_id) {
|
|
|
|
edits.push(SourceFileEdit { file_id, edit });
|
2020-02-10 16:45:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(edits)
|
|
|
|
}
|