diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_ide/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/ra_ide/src/ssr.rs | 36 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/make.rs | 16 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop/handlers.rs | 5 | ||||
-rw-r--r-- | crates/rust-analyzer/src/req.rs | 4 |
5 files changed, 52 insertions, 12 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 | ||
3 | use crate::source_change::SourceFileEdit; | 3 | use crate::source_change::SourceFileEdit; |
4 | use ra_db::{SourceDatabase, SourceDatabaseExt}; | ||
5 | use ra_ide_db::symbol_index::SymbolsDatabase; | ||
4 | use ra_ide_db::RootDatabase; | 6 | use ra_ide_db::RootDatabase; |
5 | use ra_syntax::ast::make::expr_from_text; | 7 | use ra_syntax::ast::make::try_expr_from_text; |
6 | use ra_syntax::ast::{AstToken, Comment}; | 8 | use ra_syntax::ast::{AstToken, Comment}; |
7 | use ra_syntax::{AstNode, SyntaxElement, SyntaxNode}; | 9 | use ra_syntax::{AstNode, SyntaxElement, SyntaxNode}; |
8 | use ra_text_edit::{TextEdit, TextEditBuilder}; | 10 | use ra_text_edit::{TextEdit, TextEditBuilder}; |
@@ -10,9 +12,6 @@ use rustc_hash::FxHashMap; | |||
10 | use std::collections::HashMap; | 12 | use std::collections::HashMap; |
11 | use std::str::FromStr; | 13 | use std::str::FromStr; |
12 | 14 | ||
13 | pub use ra_db::{SourceDatabase, SourceDatabaseExt}; | ||
14 | use ra_ide_db::symbol_index::SymbolsDatabase; | ||
15 | |||
16 | #[derive(Debug, PartialEq)] | 15 | #[derive(Debug, PartialEq)] |
17 | pub struct SsrError(String); | 16 | pub struct SsrError(String); |
18 | 17 | ||
@@ -26,14 +25,17 @@ impl std::error::Error for SsrError {} | |||
26 | 25 | ||
27 | pub fn parse_search_replace( | 26 | pub 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); }"; |
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index ae8829807..9f6f1cc53 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs | |||
@@ -112,10 +112,14 @@ pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr { | |||
112 | let token = token(op); | 112 | let token = token(op); |
113 | expr_from_text(&format!("{}{}", token, expr.syntax())) | 113 | expr_from_text(&format!("{}{}", token, expr.syntax())) |
114 | } | 114 | } |
115 | pub fn expr_from_text(text: &str) -> ast::Expr { | 115 | fn expr_from_text(text: &str) -> ast::Expr { |
116 | ast_from_text(&format!("const C: () = {};", text)) | 116 | ast_from_text(&format!("const C: () = {};", text)) |
117 | } | 117 | } |
118 | 118 | ||
119 | pub fn try_expr_from_text(text: &str) -> Option<ast::Expr> { | ||
120 | try_ast_from_text(&format!("const C: () = {};", text)) | ||
121 | } | ||
122 | |||
119 | pub fn bind_pat(name: ast::Name) -> ast::BindPat { | 123 | pub fn bind_pat(name: ast::Name) -> ast::BindPat { |
120 | return from_text(name.text()); | 124 | return from_text(name.text()); |
121 | 125 | ||
@@ -239,6 +243,16 @@ fn ast_from_text<N: AstNode>(text: &str) -> N { | |||
239 | node | 243 | node |
240 | } | 244 | } |
241 | 245 | ||
246 | fn try_ast_from_text<N: AstNode>(text: &str) -> Option<N> { | ||
247 | let parse = SourceFile::parse(text); | ||
248 | let node = parse.tree().syntax().descendants().find_map(N::cast)?; | ||
249 | let node = node.syntax().clone(); | ||
250 | let node = unroot(node); | ||
251 | let node = N::cast(node).unwrap(); | ||
252 | assert_eq!(node.syntax().text_range().start(), 0.into()); | ||
253 | Some(node) | ||
254 | } | ||
255 | |||
242 | fn unroot(n: SyntaxNode) -> SyntaxNode { | 256 | fn unroot(n: SyntaxNode) -> SyntaxNode { |
243 | SyntaxNode::new_root(n.green().clone()) | 257 | SyntaxNode::new_root(n.green().clone()) |
244 | } | 258 | } |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 8dc6e8dc0..3a31a6dd7 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -906,7 +906,10 @@ pub fn handle_document_highlight( | |||
906 | 906 | ||
907 | pub fn handle_ssr(world: WorldSnapshot, params: req::SsrParams) -> Result<req::SourceChange> { | 907 | pub fn handle_ssr(world: WorldSnapshot, params: req::SsrParams) -> Result<req::SourceChange> { |
908 | let _p = profile("handle_ssr"); | 908 | let _p = profile("handle_ssr"); |
909 | world.analysis().structural_search_replace(¶ms.arg)??.try_conv_with(&world) | 909 | world |
910 | .analysis() | ||
911 | .structural_search_replace(¶ms.query, params.parse_only)?? | ||
912 | .try_conv_with(&world) | ||
910 | } | 913 | } |
911 | 914 | ||
912 | pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<DiagnosticTask> { | 915 | pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<DiagnosticTask> { |
diff --git a/crates/rust-analyzer/src/req.rs b/crates/rust-analyzer/src/req.rs index a3efe3b9f..435f717ae 100644 --- a/crates/rust-analyzer/src/req.rs +++ b/crates/rust-analyzer/src/req.rs | |||
@@ -217,6 +217,8 @@ impl Request for Ssr { | |||
217 | } | 217 | } |
218 | 218 | ||
219 | #[derive(Debug, Deserialize, Serialize)] | 219 | #[derive(Debug, Deserialize, Serialize)] |
220 | #[serde(rename_all = "camelCase")] | ||
220 | pub struct SsrParams { | 221 | pub struct SsrParams { |
221 | pub arg: String, | 222 | pub query: String, |
223 | pub parse_only: bool, | ||
222 | } | 224 | } |