| //! Applies structured search replace rules from the command line. |
| |
| use anyhow::Context; |
| use ide_ssr::MatchFinder; |
| use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice}; |
| use project_model::{CargoConfig, RustLibSource}; |
| |
| use crate::cli::flags; |
| |
| impl flags::Ssr { |
| pub fn run(self) -> anyhow::Result<()> { |
| use ide_db::base_db::SourceDatabaseExt; |
| let mut cargo_config = CargoConfig::default(); |
| cargo_config.sysroot = Some(RustLibSource::Discover); |
| let load_cargo_config = LoadCargoConfig { |
| load_out_dirs_from_check: true, |
| with_proc_macro_server: ProcMacroServerChoice::Sysroot, |
| prefill_caches: false, |
| }; |
| let (host, vfs, _proc_macro) = load_workspace_at( |
| &std::env::current_dir()?, |
| &cargo_config, |
| &load_cargo_config, |
| &|_| {}, |
| )?; |
| let db = host.raw_database(); |
| let mut match_finder = MatchFinder::at_first_file(db)?; |
| for rule in self.rule { |
| match_finder.add_rule(rule)?; |
| } |
| let edits = match_finder.edits(); |
| for (file_id, edit) in edits { |
| if let Some(path) = vfs.file_path(file_id).as_path() { |
| let mut contents = db.file_text(file_id).to_string(); |
| edit.apply(&mut contents); |
| std::fs::write(path, contents) |
| .with_context(|| format!("failed to write {path}"))?; |
| } |
| } |
| Ok(()) |
| } |
| } |
| |
| impl flags::Search { |
| /// Searches for `patterns`, printing debug information for any nodes whose text exactly matches |
| /// `debug_snippet`. This is intended for debugging and probably isn't in it's current form useful |
| /// for much else. |
| pub fn run(self) -> anyhow::Result<()> { |
| use ide_db::base_db::SourceDatabaseExt; |
| use ide_db::symbol_index::SymbolsDatabase; |
| let cargo_config = CargoConfig::default(); |
| let load_cargo_config = LoadCargoConfig { |
| load_out_dirs_from_check: true, |
| with_proc_macro_server: ProcMacroServerChoice::Sysroot, |
| prefill_caches: false, |
| }; |
| let (host, _vfs, _proc_macro) = load_workspace_at( |
| &std::env::current_dir()?, |
| &cargo_config, |
| &load_cargo_config, |
| &|_| {}, |
| )?; |
| let db = host.raw_database(); |
| let mut match_finder = MatchFinder::at_first_file(db)?; |
| for pattern in self.pattern { |
| match_finder.add_search_pattern(pattern)?; |
| } |
| if let Some(debug_snippet) = &self.debug { |
| for &root in db.local_roots().iter() { |
| let sr = db.source_root(root); |
| for file_id in sr.iter() { |
| for debug_info in match_finder.debug_where_text_equal(file_id, debug_snippet) { |
| println!("{debug_info:#?}"); |
| } |
| } |
| } |
| } else { |
| for m in match_finder.matches().flattened().matches { |
| // We could possibly at some point do something more useful than just printing |
| // the matched text. For now though, that's the easiest thing to do. |
| println!("{}", m.matched_text()); |
| } |
| } |
| Ok(()) |
| } |
| } |