aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/Cargo.toml2
-rw-r--r--crates/ra_ide/src/lib.rs18
-rw-r--r--crates/ra_ide/src/ssr.rs72
3 files changed, 11 insertions, 81 deletions
diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml
index e25aad6cf..8519e9cca 100644
--- a/crates/ra_ide/Cargo.toml
+++ b/crates/ra_ide/Cargo.toml
@@ -29,7 +29,7 @@ cfg = { path = "../cfg" }
29profile = { path = "../profile" } 29profile = { path = "../profile" }
30test_utils = { path = "../test_utils" } 30test_utils = { path = "../test_utils" }
31ra_assists = { path = "../ra_assists" } 31ra_assists = { path = "../ra_assists" }
32ra_ssr = { path = "../ra_ssr" } 32ssr = { path = "../ssr" }
33 33
34# ra_ide should depend only on the top-level `hir` package. if you need 34# ra_ide should depend only on the top-level `hir` package. if you need
35# something from some `hir_xxx` subpackage, reexport the API via `hir`. 35# something from some `hir_xxx` subpackage, reexport the API via `hir`.
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 66a234fff..bbc9e4b8a 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -39,7 +39,6 @@ mod matching_brace;
39mod parent_module; 39mod parent_module;
40mod references; 40mod references;
41mod runnables; 41mod runnables;
42mod ssr;
43mod status; 42mod status;
44mod syntax_highlighting; 43mod syntax_highlighting;
45mod syntax_tree; 44mod syntax_tree;
@@ -95,7 +94,7 @@ pub use ide_db::{
95 RootDatabase, 94 RootDatabase,
96}; 95};
97pub use ra_assists::{Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist}; 96pub use ra_assists::{Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist};
98pub use ra_ssr::SsrError; 97pub use ssr::SsrError;
99pub use text_edit::{Indel, TextEdit}; 98pub use text_edit::{Indel, TextEdit};
100 99
101pub type Cancelable<T> = Result<T, Canceled>; 100pub type Cancelable<T> = Result<T, Canceled>;
@@ -515,20 +514,23 @@ impl Analysis {
515 &self, 514 &self,
516 query: &str, 515 query: &str,
517 parse_only: bool, 516 parse_only: bool,
518 position: FilePosition, 517 resolve_context: FilePosition,
519 selections: Vec<FileRange>, 518 selections: Vec<FileRange>,
520 ) -> Cancelable<Result<SourceChange, SsrError>> { 519 ) -> Cancelable<Result<SourceChange, SsrError>> {
521 self.with_db(|db| { 520 self.with_db(|db| {
522 let edits = ssr::parse_search_replace(query, parse_only, db, position, selections)?; 521 let rule: ssr::SsrRule = query.parse()?;
522 let mut match_finder = ssr::MatchFinder::in_context(db, resolve_context, selections);
523 match_finder.add_rule(rule)?;
524 let edits = if parse_only { Vec::new() } else { match_finder.edits() };
523 Ok(SourceChange::from(edits)) 525 Ok(SourceChange::from(edits))
524 }) 526 })
525 } 527 }
526 528
527 /// Performs an operation on that may be Canceled. 529 /// Performs an operation on that may be Canceled.
528 fn with_db<F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe, T>( 530 fn with_db<F, T>(&self, f: F) -> Cancelable<T>
529 &self, 531 where
530 f: F, 532 F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe,
531 ) -> Cancelable<T> { 533 {
532 self.db.catch_canceled(f) 534 self.db.catch_canceled(f)
533 } 535 }
534} 536}
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs
deleted file mode 100644
index a8a704192..000000000
--- a/crates/ra_ide/src/ssr.rs
+++ /dev/null
@@ -1,72 +0,0 @@
1use base_db::{FilePosition, FileRange};
2use ide_db::RootDatabase;
3
4use crate::SourceFileEdit;
5use ra_ssr::{MatchFinder, SsrError, SsrRule};
6
7// Feature: Structural Search and Replace
8//
9// Search and replace with named wildcards that will match any expression, type, path, pattern or item.
10// The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`.
11// A `$<name>` placeholder in the search pattern will match any AST node and `$<name>` will reference it in the replacement.
12// Within a macro call, a placeholder will match up until whatever token follows the placeholder.
13//
14// All paths in both the search pattern and the replacement template must resolve in the context
15// in which this command is invoked. Paths in the search pattern will then match the code if they
16// resolve to the same item, even if they're written differently. For example if we invoke the
17// command in the module `foo` with a pattern of `Bar`, then code in the parent module that refers
18// to `foo::Bar` will match.
19//
20// Paths in the replacement template will be rendered appropriately for the context in which the
21// replacement occurs. For example if our replacement template is `foo::Bar` and we match some
22// code in the `foo` module, we'll insert just `Bar`.
23//
24// Inherent method calls should generally be written in UFCS form. e.g. `foo::Bar::baz($s, $a)` will
25// match `$s.baz($a)`, provided the method call `baz` resolves to the method `foo::Bar::baz`.
26//
27// The scope of the search / replace will be restricted to the current selection if any, otherwise
28// it will apply to the whole workspace.
29//
30// Placeholders may be given constraints by writing them as `${<name>:<constraint1>:<constraint2>...}`.
31//
32// Supported constraints:
33//
34// |===
35// | Constraint | Restricts placeholder
36//
37// | kind(literal) | Is a literal (e.g. `42` or `"forty two"`)
38// | not(a) | Negates the constraint `a`
39// |===
40//
41// Available via the command `rust-analyzer.ssr`.
42//
43// ```rust
44// // Using structural search replace command [foo($a, $b) ==>> ($a).foo($b)]
45//
46// // BEFORE
47// String::from(foo(y + 5, z))
48//
49// // AFTER
50// String::from((y + 5).foo(z))
51// ```
52//
53// |===
54// | Editor | Action Name
55//
56// | VS Code | **Rust Analyzer: Structural Search Replace**
57// |===
58pub fn parse_search_replace(
59 rule: &str,
60 parse_only: bool,
61 db: &RootDatabase,
62 resolve_context: FilePosition,
63 selections: Vec<FileRange>,
64) -> Result<Vec<SourceFileEdit>, SsrError> {
65 let rule: SsrRule = rule.parse()?;
66 let mut match_finder = MatchFinder::in_context(db, resolve_context, selections);
67 match_finder.add_rule(rule)?;
68 if parse_only {
69 return Ok(Vec::new());
70 }
71 Ok(match_finder.edits())
72}