aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/src/lib.rs3
-rw-r--r--crates/ra_ide/src/ssr.rs36
2 files changed, 30 insertions, 9 deletions
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index c60e86aea..40276d4fe 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -478,9 +478,10 @@ impl Analysis {
478 pub fn structural_search_replace( 478 pub fn structural_search_replace(
479 &self, 479 &self,
480 query: &str, 480 query: &str,
481 parse_only: bool,
481 ) -> Cancelable<Result<SourceChange, SsrError>> { 482 ) -> Cancelable<Result<SourceChange, SsrError>> {
482 self.with_db(|db| { 483 self.with_db(|db| {
483 let edits = ssr::parse_search_replace(query, db)?; 484 let edits = ssr::parse_search_replace(query, parse_only, db)?;
484 Ok(SourceChange::source_file_edits("ssr", edits)) 485 Ok(SourceChange::source_file_edits("ssr", edits))
485 }) 486 })
486 } 487 }
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs
index c011a2e74..1c9710a5d 100644
--- a/crates/ra_ide/src/ssr.rs
+++ b/crates/ra_ide/src/ssr.rs
@@ -1,8 +1,10 @@
1//! structural search replace 1//! structural search replace
2 2
3use crate::source_change::SourceFileEdit; 3use crate::source_change::SourceFileEdit;
4use ra_db::{SourceDatabase, SourceDatabaseExt};
5use ra_ide_db::symbol_index::SymbolsDatabase;
4use ra_ide_db::RootDatabase; 6use ra_ide_db::RootDatabase;
5use ra_syntax::ast::make::expr_from_text; 7use ra_syntax::ast::make::try_expr_from_text;
6use ra_syntax::ast::{AstToken, Comment}; 8use ra_syntax::ast::{AstToken, Comment};
7use ra_syntax::{AstNode, SyntaxElement, SyntaxNode}; 9use ra_syntax::{AstNode, SyntaxElement, SyntaxNode};
8use ra_text_edit::{TextEdit, TextEditBuilder}; 10use ra_text_edit::{TextEdit, TextEditBuilder};
@@ -10,9 +12,6 @@ use rustc_hash::FxHashMap;
10use std::collections::HashMap; 12use std::collections::HashMap;
11use std::str::FromStr; 13use std::str::FromStr;
12 14
13pub use ra_db::{SourceDatabase, SourceDatabaseExt};
14use ra_ide_db::symbol_index::SymbolsDatabase;
15
16#[derive(Debug, PartialEq)] 15#[derive(Debug, PartialEq)]
17pub struct SsrError(String); 16pub struct SsrError(String);
18 17
@@ -26,14 +25,17 @@ impl std::error::Error for SsrError {}
26 25
27pub fn parse_search_replace( 26pub fn parse_search_replace(
28 query: &str, 27 query: &str,
28 parse_only: bool,
29 db: &RootDatabase, 29 db: &RootDatabase,
30) -> Result<Vec<SourceFileEdit>, SsrError> { 30) -> Result<Vec<SourceFileEdit>, SsrError> {
31 let mut edits = vec![]; 31 let mut edits = vec![];
32 let query: SsrQuery = query.parse()?; 32 let query: SsrQuery = query.parse()?;
33 if parse_only {
34 return Ok(edits);
35 }
33 for &root in db.local_roots().iter() { 36 for &root in db.local_roots().iter() {
34 let sr = db.source_root(root); 37 let sr = db.source_root(root);
35 for file_id in sr.walk() { 38 for file_id in sr.walk() {
36 dbg!(db.file_relative_path(file_id));
37 let matches = find(&query.pattern, db.parse(file_id).tree().syntax()); 39 let matches = find(&query.pattern, db.parse(file_id).tree().syntax());
38 if !matches.matches.is_empty() { 40 if !matches.matches.is_empty() {
39 edits.push(SourceFileEdit { file_id, edit: replace(&matches, &query.template) }); 41 edits.push(SourceFileEdit { file_id, edit: replace(&matches, &query.template) });
@@ -106,7 +108,10 @@ impl FromStr for SsrQuery {
106 template = replace_in_template(template, var, new_var); 108 template = replace_in_template(template, var, new_var);
107 } 109 }
108 110
109 let template = expr_from_text(&template).syntax().clone(); 111 let template = try_expr_from_text(&template)
112 .ok_or(SsrError("Template is not an expression".into()))?
113 .syntax()
114 .clone();
110 let mut placeholders = FxHashMap::default(); 115 let mut placeholders = FxHashMap::default();
111 116
112 traverse(&template, &mut |n| { 117 traverse(&template, &mut |n| {
@@ -118,7 +123,13 @@ impl FromStr for SsrQuery {
118 } 123 }
119 }); 124 });
120 125
121 let pattern = SsrPattern { pattern: expr_from_text(&pattern).syntax().clone(), vars }; 126 let pattern = SsrPattern {
127 pattern: try_expr_from_text(&pattern)
128 .ok_or(SsrError("Pattern is not an expression".into()))?
129 .syntax()
130 .clone(),
131 vars,
132 };
122 let template = SsrTemplate { template, placeholders }; 133 let template = SsrTemplate { template, placeholders };
123 Ok(SsrQuery { pattern, template }) 134 Ok(SsrQuery { pattern, template })
124 } 135 }
@@ -284,7 +295,6 @@ mod tests {
284 assert_eq!(result.pattern.vars[0].0, "__search_pattern_a"); 295 assert_eq!(result.pattern.vars[0].0, "__search_pattern_a");
285 assert_eq!(result.pattern.vars[1].0, "__search_pattern_b"); 296 assert_eq!(result.pattern.vars[1].0, "__search_pattern_b");
286 assert_eq!(&result.template.template.text(), "bar(__search_pattern_b, __search_pattern_a)"); 297 assert_eq!(&result.template.template.text(), "bar(__search_pattern_b, __search_pattern_a)");
287 dbg!(result.template.placeholders);
288 } 298 }
289 299
290 #[test] 300 #[test]
@@ -335,6 +345,16 @@ mod tests {
335 } 345 }
336 346
337 #[test] 347 #[test]
348 fn parser_invlid_pattern() {
349 assert_eq!(parse_error_text(" ==>> ()"), "Parse error: Pattern is not an expression");
350 }
351
352 #[test]
353 fn parser_invlid_template() {
354 assert_eq!(parse_error_text("() ==>> )"), "Parse error: Template is not an expression");
355 }
356
357 #[test]
338 fn parse_match_replace() { 358 fn parse_match_replace() {
339 let query: SsrQuery = "foo($x:expr) ==>> bar($x)".parse().unwrap(); 359 let query: SsrQuery = "foo($x:expr) ==>> bar($x)".parse().unwrap();
340 let input = "fn main() { foo(1+2); }"; 360 let input = "fn main() { foo(1+2); }";