From bc0f79f74ad0ab4f663b94772ccbfabed1de625e Mon Sep 17 00:00:00 2001 From: gfreezy Date: Tue, 15 Jan 2019 00:09:03 +0800 Subject: rename mod --- crates/ra_ide_api/src/imp.rs | 90 ++++++++++++++++++++++++-- crates/ra_ide_api/tests/test/main.rs | 41 +++++++++--- crates/ra_lsp_server/src/main_loop.rs | 5 +- crates/ra_lsp_server/src/main_loop/handlers.rs | 47 +++++++++----- 4 files changed, 148 insertions(+), 35 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/imp.rs b/crates/ra_ide_api/src/imp.rs index 28e497965..3f0de8b5b 100644 --- a/crates/ra_ide_api/src/imp.rs +++ b/crates/ra_ide_api/src/imp.rs @@ -1,7 +1,10 @@ use std::sync::Arc; use hir::{ - self, Problem, source_binder, + self, Problem, source_binder::{ + self, + module_from_declaration + }, ModuleSource, }; use ra_db::{ FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase, @@ -9,16 +12,16 @@ use ra_db::{ }; use ra_ide_api_light::{self, assists, LocalEdit, Severity}; use ra_syntax::{ - TextRange, AstNode, SourceFile, - ast::{self, NameOwner}, - algo::find_node_at_offset, + algo::find_node_at_offset, ast::{self, NameOwner}, AstNode, + SourceFile, + TextRange, }; use crate::{ AnalysisChange, CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit, Query, RootChange, SourceChange, SourceFileEdit, - symbol_index::{LibrarySymbolsQuery, FileSymbol}, + symbol_index::{FileSymbol, LibrarySymbolsQuery}, }; impl db::RootDatabase { @@ -110,6 +113,7 @@ impl db::RootDatabase { }; vec![krate.crate_id()] } + pub(crate) fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> { let file = self.source_file(position.file_id); // Find the binding associated with the offset @@ -230,20 +234,94 @@ impl db::RootDatabase { .collect() } +<<<<<<< HEAD pub(crate) fn rename(&self, position: FilePosition, new_name: &str) -> Vec { self.find_all_refs(position) .iter() .map(|(file_id, text_range)| SourceFileEdit { file_id: *file_id, +======= + pub(crate) fn rename( + &self, + position: FilePosition, + new_name: &str, + ) -> Cancelable> { + let mut source_file_edits = Vec::new(); + let mut file_system_edits = Vec::new(); + + let source_file = self.source_file(position.file_id); + let syntax = source_file.syntax(); + // We are rename a mod + if let (Some(ast_module), Some(name)) = ( + find_node_at_offset::(syntax, position.offset), + find_node_at_offset::(syntax, position.offset), + ) { + if let Some(module) = module_from_declaration(self, position.file_id, &ast_module)? { + let (file_id, module_source) = module.definition_source(self)?; + match module_source { + ModuleSource::SourceFile(..) => { + let move_file = FileSystemEdit::MoveFile { + src: file_id, + dst_source_root: self.file_source_root(position.file_id), + dst_path: self + .file_relative_path(file_id) + .with_file_name(new_name) + .with_extension("rs"), + }; + file_system_edits.push(move_file); + } + ModuleSource::Module(..) => {} + } + } + + let edit = SourceFileEdit { + file_id: position.file_id, +>>>>>>> rename mod edit: { let mut builder = ra_text_edit::TextEditBuilder::default(); - builder.replace(*text_range, new_name.into()); + builder.replace(name.syntax().range(), new_name.into()); builder.finish() }, +<<<<<<< HEAD }) .collect::>() } pub(crate) fn index_resolve(&self, name_ref: &ast::NameRef) -> Vec { +======= + }; + source_file_edits.push(edit); + } + // rename references + else { + let edit = self + .find_all_refs(position)? + .iter() + .map(|(file_id, text_range)| SourceFileEdit { + file_id: *file_id, + edit: { + let mut builder = ra_text_edit::TextEditBuilder::default(); + builder.replace(*text_range, new_name.into()); + builder.finish() + }, + }) + .collect::>(); + if edit.is_empty() { + return Ok(None); + } + + source_file_edits = edit; + } + + return Ok(Some(SourceChange { + label: "rename".to_string(), + source_file_edits, + file_system_edits, + cursor_position: None, + })); + } + + pub(crate) fn index_resolve(&self, name_ref: &ast::NameRef) -> Cancelable> { +>>>>>>> rename mod let name = name_ref.text(); let mut query = Query::new(name.to_string()); query.exact(); diff --git a/crates/ra_ide_api/tests/test/main.rs b/crates/ra_ide_api/tests/test/main.rs index 2b863aedf..4aa13b0e7 100644 --- a/crates/ra_ide_api/tests/test/main.rs +++ b/crates/ra_ide_api/tests/test/main.rs @@ -1,11 +1,13 @@ +use ra_ide_api::{ + AnalysisChange, + CrateGraph, FileId, mock_analysis::{MockAnalysis, single_file, single_file_with_position}, Query, +}; +use ra_ide_api::mock_analysis::analysis_and_position; use ra_syntax::TextRange; use test_utils::assert_eq_text; use insta::assert_debug_snapshot_matches; -use ra_ide_api::{ - mock_analysis::{single_file, single_file_with_position, MockAnalysis}, - AnalysisChange, CrateGraph, FileId, Query -}; +mod runnables; #[test] fn test_unresolved_module_diagnostic() { @@ -91,6 +93,7 @@ fn test_find_all_refs_for_fn_param() { let refs = get_all_refs(code); assert_eq!(refs.len(), 2); } + #[test] fn test_rename_for_local() { test_rename( @@ -167,15 +170,35 @@ fn test_rename_for_mut_param() { ); } +#[test] +fn test_rename_mod() { + let (analysis, position) = analysis_and_position( + " + //- /bar.rs + mod fo<|>o; + //- /bar/foo.rs + // emtpy + ", + ); + let new_name = "foo2"; + let source_change = analysis.rename(position, new_name).unwrap(); + assert_eq_dbg( + r#"Some(SourceChange { label: "rename", source_file_edits: [SourceFileEdit { file_id: FileId(1), edit: TextEdit { atoms: [AtomTextEdit { delete: [4; 7), insert: "foo2" }] } }], file_system_edits: [MoveFile { src: FileId(2), dst_source_root: SourceRootId(0), dst_path: "bar/foo2.rs" }], cursor_position: None })"#, + &source_change, + ); +} + fn test_rename(text: &str, new_name: &str, expected: &str) { let (analysis, position) = single_file_with_position(text); - let edits = analysis.rename(position, new_name).unwrap(); + let source_change = analysis.rename(position, new_name).unwrap(); let mut text_edit_bulder = ra_text_edit::TextEditBuilder::default(); let mut file_id: Option = None; - for edit in edits { - file_id = Some(edit.file_id); - for atom in edit.edit.as_atoms() { - text_edit_bulder.replace(atom.delete, atom.insert.clone()); + if let Some(change) = source_change { + for edit in change.source_file_edits { + file_id = Some(edit.file_id); + for atom in edit.edit.as_atoms() { + text_edit_bulder.replace(atom.delete, atom.insert.clone()); + } } } let result = text_edit_bulder diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index c48c4dd9e..fa07b1942 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -411,10 +411,7 @@ struct PoolDispatcher<'a> { } impl<'a> PoolDispatcher<'a> { - fn on<'b, R>( - &'b mut self, - f: fn(ServerWorld, R::Params) -> Result, - ) -> Result<&'b mut Self> + fn on(&mut self, f: fn(ServerWorld, R::Params) -> Result) -> Result<&mut Self> where R: req::Request, R::Params: DeserializeOwned + Send + 'static, diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 11a705200..c010a6ddf 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use gen_lsp_server::ErrorCode; use lsp_types::{ CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity, @@ -7,7 +5,7 @@ use lsp_types::{ FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, RenameParams, SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit, - WorkspaceEdit, + WorkspaceEdit, DocumentChanges, TextDocumentEdit, DocumentChangeOperation, ResourceOp }; use ra_ide_api::{ FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity, @@ -467,26 +465,43 @@ pub fn handle_rename(world: ServerWorld, params: RenameParams) -> Result>>(); - Ok(Some(WorkspaceEdit { - changes: Some(changes), + let text_document_ops = source_change + .file_system_edits + .drain(..) + .into_iter() + .map(|e| e.try_conv_with(&world)) + .collect::>>(); - // TODO: return this instead if client/server support it. See #144 - document_changes: None, + let mut document_changes = Vec::new(); + document_changes.extend( + text_document_edits? + .into_iter() + .map(DocumentChangeOperation::Edit), + ); + document_changes.extend( + text_document_ops? + .into_iter() + .map(DocumentChangeOperation::Op), + ); + + Ok(Some(WorkspaceEdit { + changes: None, + document_changes: Some(DocumentChanges::Operations(document_changes)), })) } -- cgit v1.2.3