aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock2
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/bin/args.rs31
-rw-r--r--crates/rust-analyzer/src/bin/main.rs3
-rw-r--r--crates/rust-analyzer/src/cli.rs2
-rw-r--r--crates/rust-analyzer/src/cli/ssr.rs33
6 files changed, 73 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b19d697f5..cf0479f0b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1464,10 +1464,12 @@ dependencies = [
1464 "ra_hir_def", 1464 "ra_hir_def",
1465 "ra_hir_ty", 1465 "ra_hir_ty",
1466 "ra_ide", 1466 "ra_ide",
1467 "ra_ide_db",
1467 "ra_mbe", 1468 "ra_mbe",
1468 "ra_proc_macro_srv", 1469 "ra_proc_macro_srv",
1469 "ra_prof", 1470 "ra_prof",
1470 "ra_project_model", 1471 "ra_project_model",
1472 "ra_ssr",
1471 "ra_syntax", 1473 "ra_syntax",
1472 "ra_text_edit", 1474 "ra_text_edit",
1473 "ra_toolchain", 1475 "ra_toolchain",
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 53621fb44..97d9bf5d4 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -34,8 +34,10 @@ stdx = { path = "../stdx" }
34lsp-server = "0.3.3" 34lsp-server = "0.3.3"
35flycheck = { path = "../flycheck" } 35flycheck = { path = "../flycheck" }
36ra_ide = { path = "../ra_ide" } 36ra_ide = { path = "../ra_ide" }
37ra_ide_db = { path = "../ra_ide_db" }
37ra_prof = { path = "../ra_prof" } 38ra_prof = { path = "../ra_prof" }
38ra_project_model = { path = "../ra_project_model" } 39ra_project_model = { path = "../ra_project_model" }
40ra_ssr = { path = "../ra_ssr" }
39ra_syntax = { path = "../ra_syntax" } 41ra_syntax = { path = "../ra_syntax" }
40ra_text_edit = { path = "../ra_text_edit" } 42ra_text_edit = { path = "../ra_text_edit" }
41vfs = { path = "../vfs" } 43vfs = { path = "../vfs" }
diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs
index 8e3ca9343..3f0bb3865 100644
--- a/crates/rust-analyzer/src/bin/args.rs
+++ b/crates/rust-analyzer/src/bin/args.rs
@@ -5,6 +5,7 @@
5 5
6use anyhow::{bail, Result}; 6use anyhow::{bail, Result};
7use pico_args::Arguments; 7use pico_args::Arguments;
8use ra_ssr::SsrRule;
8use rust_analyzer::cli::{BenchWhat, Position, Verbosity}; 9use rust_analyzer::cli::{BenchWhat, Position, Verbosity};
9 10
10use std::{fmt::Write, path::PathBuf}; 11use std::{fmt::Write, path::PathBuf};
@@ -45,6 +46,9 @@ pub(crate) enum Command {
45 /// this would include the parser test files. 46 /// this would include the parser test files.
46 all: bool, 47 all: bool,
47 }, 48 },
49 Ssr {
50 rules: Vec<SsrRule>,
51 },
48 ProcMacro, 52 ProcMacro,
49 RunServer, 53 RunServer,
50 Version, 54 Version,
@@ -270,6 +274,32 @@ ARGS:
270 Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } 274 Command::Diagnostics { path, load_output_dirs, with_proc_macro, all }
271 } 275 }
272 "proc-macro" => Command::ProcMacro, 276 "proc-macro" => Command::ProcMacro,
277 "ssr" => {
278 if matches.contains(["-h", "--help"]) {
279 eprintln!(
280 "\
281rust-analyzer ssr
282
283USAGE:
284 rust-analyzer ssr [FLAGS] [RULE...]
285
286EXAMPLE:
287 rust-analyzer ssr '$a.foo($b) ==> bar($a, $b)'
288
289FLAGS:
290 -h, --help Prints help information
291
292ARGS:
293 <RULE> A structured search replace rule"
294 );
295 return Ok(Err(HelpPrinted));
296 }
297 let mut rules = Vec::new();
298 while let Some(rule) = matches.free_from_str()? {
299 rules.push(rule);
300 }
301 Command::Ssr { rules }
302 }
273 _ => { 303 _ => {
274 print_subcommands(); 304 print_subcommands();
275 return Ok(Err(HelpPrinted)); 305 return Ok(Err(HelpPrinted));
@@ -297,6 +327,7 @@ SUBCOMMANDS:
297 diagnostics 327 diagnostics
298 proc-macro 328 proc-macro
299 parse 329 parse
330 ssr
300 symbols" 331 symbols"
301 ) 332 )
302} 333}
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 45204d1a3..16882fc13 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -60,6 +60,9 @@ fn main() -> Result<()> {
60 args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => { 60 args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => {
61 cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)? 61 cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)?
62 } 62 }
63 args::Command::Ssr { rules } => {
64 cli::apply_ssr_rules(rules)?;
65 }
63 args::Command::Version => println!("rust-analyzer {}", env!("REV")), 66 args::Command::Version => println!("rust-analyzer {}", env!("REV")),
64 } 67 }
65 Ok(()) 68 Ok(())
diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs
index c5faec83a..13e3d75be 100644
--- a/crates/rust-analyzer/src/cli.rs
+++ b/crates/rust-analyzer/src/cli.rs
@@ -5,6 +5,7 @@ mod analysis_stats;
5mod analysis_bench; 5mod analysis_bench;
6mod diagnostics; 6mod diagnostics;
7mod progress_report; 7mod progress_report;
8mod ssr;
8 9
9use std::io::Read; 10use std::io::Read;
10 11
@@ -17,6 +18,7 @@ pub use analysis_bench::{analysis_bench, BenchWhat, Position};
17pub use analysis_stats::analysis_stats; 18pub use analysis_stats::analysis_stats;
18pub use diagnostics::diagnostics; 19pub use diagnostics::diagnostics;
19pub use load_cargo::load_cargo; 20pub use load_cargo::load_cargo;
21pub use ssr::apply_ssr_rules;
20 22
21#[derive(Clone, Copy)] 23#[derive(Clone, Copy)]
22pub enum Verbosity { 24pub enum Verbosity {
diff --git a/crates/rust-analyzer/src/cli/ssr.rs b/crates/rust-analyzer/src/cli/ssr.rs
new file mode 100644
index 000000000..a5265ac15
--- /dev/null
+++ b/crates/rust-analyzer/src/cli/ssr.rs
@@ -0,0 +1,33 @@
1//! Applies structured search replace rules from the command line.
2
3use crate::cli::{load_cargo::load_cargo, Result};
4use ra_ide::SourceFileEdit;
5use ra_ssr::{MatchFinder, SsrRule};
6
7pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> {
8 use ra_db::SourceDatabaseExt;
9 use ra_ide_db::symbol_index::SymbolsDatabase;
10 let (host, vfs) = load_cargo(&std::env::current_dir()?, true, true)?;
11 let db = host.raw_database();
12 let mut match_finder = MatchFinder::new(db);
13 for rule in rules {
14 match_finder.add_rule(rule);
15 }
16 let mut edits = Vec::new();
17 for &root in db.local_roots().iter() {
18 let sr = db.source_root(root);
19 for file_id in sr.iter() {
20 if let Some(edit) = match_finder.edits_for_file(file_id) {
21 edits.push(SourceFileEdit { file_id, edit });
22 }
23 }
24 }
25 for edit in edits {
26 if let Some(path) = vfs.file_path(edit.file_id).as_path() {
27 let mut contents = db.file_text(edit.file_id).to_string();
28 edit.edit.apply(&mut contents);
29 std::fs::write(path, contents)?;
30 }
31 }
32 Ok(())
33}