diff options
author | gfreezy <[email protected]> | 2019-01-14 16:09:03 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-01-19 12:36:58 +0000 |
commit | bc0f79f74ad0ab4f663b94772ccbfabed1de625e (patch) | |
tree | 21c125b75a7b757435ce641788cdcde0b9dd4f14 | |
parent | b82fe73d1ab9727ff650382d9c86a231b06245be (diff) |
rename mod
-rw-r--r-- | crates/ra_ide_api/src/imp.rs | 90 | ||||
-rw-r--r-- | crates/ra_ide_api/tests/test/main.rs | 41 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop.rs | 5 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 47 |
4 files changed, 148 insertions, 35 deletions
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 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use hir::{ | 3 | use hir::{ |
4 | self, Problem, source_binder, | 4 | self, Problem, source_binder::{ |
5 | self, | ||
6 | module_from_declaration | ||
7 | }, ModuleSource, | ||
5 | }; | 8 | }; |
6 | use ra_db::{ | 9 | use ra_db::{ |
7 | FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase, | 10 | FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase, |
@@ -9,16 +12,16 @@ use ra_db::{ | |||
9 | }; | 12 | }; |
10 | use ra_ide_api_light::{self, assists, LocalEdit, Severity}; | 13 | use ra_ide_api_light::{self, assists, LocalEdit, Severity}; |
11 | use ra_syntax::{ | 14 | use ra_syntax::{ |
12 | TextRange, AstNode, SourceFile, | 15 | algo::find_node_at_offset, ast::{self, NameOwner}, AstNode, |
13 | ast::{self, NameOwner}, | 16 | SourceFile, |
14 | algo::find_node_at_offset, | 17 | TextRange, |
15 | }; | 18 | }; |
16 | 19 | ||
17 | use crate::{ | 20 | use crate::{ |
18 | AnalysisChange, | 21 | AnalysisChange, |
19 | CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit, | 22 | CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit, |
20 | Query, RootChange, SourceChange, SourceFileEdit, | 23 | Query, RootChange, SourceChange, SourceFileEdit, |
21 | symbol_index::{LibrarySymbolsQuery, FileSymbol}, | 24 | symbol_index::{FileSymbol, LibrarySymbolsQuery}, |
22 | }; | 25 | }; |
23 | 26 | ||
24 | impl db::RootDatabase { | 27 | impl db::RootDatabase { |
@@ -110,6 +113,7 @@ impl db::RootDatabase { | |||
110 | }; | 113 | }; |
111 | vec![krate.crate_id()] | 114 | vec![krate.crate_id()] |
112 | } | 115 | } |
116 | |||
113 | pub(crate) fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> { | 117 | pub(crate) fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> { |
114 | let file = self.source_file(position.file_id); | 118 | let file = self.source_file(position.file_id); |
115 | // Find the binding associated with the offset | 119 | // Find the binding associated with the offset |
@@ -230,20 +234,94 @@ impl db::RootDatabase { | |||
230 | .collect() | 234 | .collect() |
231 | } | 235 | } |
232 | 236 | ||
237 | <<<<<<< HEAD | ||
233 | pub(crate) fn rename(&self, position: FilePosition, new_name: &str) -> Vec<SourceFileEdit> { | 238 | pub(crate) fn rename(&self, position: FilePosition, new_name: &str) -> Vec<SourceFileEdit> { |
234 | self.find_all_refs(position) | 239 | self.find_all_refs(position) |
235 | .iter() | 240 | .iter() |
236 | .map(|(file_id, text_range)| SourceFileEdit { | 241 | .map(|(file_id, text_range)| SourceFileEdit { |
237 | file_id: *file_id, | 242 | file_id: *file_id, |
243 | ======= | ||
244 | pub(crate) fn rename( | ||
245 | &self, | ||
246 | position: FilePosition, | ||
247 | new_name: &str, | ||
248 | ) -> Cancelable<Option<SourceChange>> { | ||
249 | let mut source_file_edits = Vec::new(); | ||
250 | let mut file_system_edits = Vec::new(); | ||
251 | |||
252 | let source_file = self.source_file(position.file_id); | ||
253 | let syntax = source_file.syntax(); | ||
254 | // We are rename a mod | ||
255 | if let (Some(ast_module), Some(name)) = ( | ||
256 | find_node_at_offset::<ast::Module>(syntax, position.offset), | ||
257 | find_node_at_offset::<ast::Name>(syntax, position.offset), | ||
258 | ) { | ||
259 | if let Some(module) = module_from_declaration(self, position.file_id, &ast_module)? { | ||
260 | let (file_id, module_source) = module.definition_source(self)?; | ||
261 | match module_source { | ||
262 | ModuleSource::SourceFile(..) => { | ||
263 | let move_file = FileSystemEdit::MoveFile { | ||
264 | src: file_id, | ||
265 | dst_source_root: self.file_source_root(position.file_id), | ||
266 | dst_path: self | ||
267 | .file_relative_path(file_id) | ||
268 | .with_file_name(new_name) | ||
269 | .with_extension("rs"), | ||
270 | }; | ||
271 | file_system_edits.push(move_file); | ||
272 | } | ||
273 | ModuleSource::Module(..) => {} | ||
274 | } | ||
275 | } | ||
276 | |||
277 | let edit = SourceFileEdit { | ||
278 | file_id: position.file_id, | ||
279 | >>>>>>> rename mod | ||
238 | edit: { | 280 | edit: { |
239 | let mut builder = ra_text_edit::TextEditBuilder::default(); | 281 | let mut builder = ra_text_edit::TextEditBuilder::default(); |
240 | builder.replace(*text_range, new_name.into()); | 282 | builder.replace(name.syntax().range(), new_name.into()); |
241 | builder.finish() | 283 | builder.finish() |
242 | }, | 284 | }, |
285 | <<<<<<< HEAD | ||
243 | }) | 286 | }) |
244 | .collect::<Vec<_>>() | 287 | .collect::<Vec<_>>() |
245 | } | 288 | } |
246 | pub(crate) fn index_resolve(&self, name_ref: &ast::NameRef) -> Vec<FileSymbol> { | 289 | pub(crate) fn index_resolve(&self, name_ref: &ast::NameRef) -> Vec<FileSymbol> { |
290 | ======= | ||
291 | }; | ||
292 | source_file_edits.push(edit); | ||
293 | } | ||
294 | // rename references | ||
295 | else { | ||
296 | let edit = self | ||
297 | .find_all_refs(position)? | ||
298 | .iter() | ||
299 | .map(|(file_id, text_range)| SourceFileEdit { | ||
300 | file_id: *file_id, | ||
301 | edit: { | ||
302 | let mut builder = ra_text_edit::TextEditBuilder::default(); | ||
303 | builder.replace(*text_range, new_name.into()); | ||
304 | builder.finish() | ||
305 | }, | ||
306 | }) | ||
307 | .collect::<Vec<_>>(); | ||
308 | if edit.is_empty() { | ||
309 | return Ok(None); | ||
310 | } | ||
311 | |||
312 | source_file_edits = edit; | ||
313 | } | ||
314 | |||
315 | return Ok(Some(SourceChange { | ||
316 | label: "rename".to_string(), | ||
317 | source_file_edits, | ||
318 | file_system_edits, | ||
319 | cursor_position: None, | ||
320 | })); | ||
321 | } | ||
322 | |||
323 | pub(crate) fn index_resolve(&self, name_ref: &ast::NameRef) -> Cancelable<Vec<FileSymbol>> { | ||
324 | >>>>>>> rename mod | ||
247 | let name = name_ref.text(); | 325 | let name = name_ref.text(); |
248 | let mut query = Query::new(name.to_string()); | 326 | let mut query = Query::new(name.to_string()); |
249 | query.exact(); | 327 | 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 @@ | |||
1 | use ra_ide_api::{ | ||
2 | AnalysisChange, | ||
3 | CrateGraph, FileId, mock_analysis::{MockAnalysis, single_file, single_file_with_position}, Query, | ||
4 | }; | ||
5 | use ra_ide_api::mock_analysis::analysis_and_position; | ||
1 | use ra_syntax::TextRange; | 6 | use ra_syntax::TextRange; |
2 | use test_utils::assert_eq_text; | 7 | use test_utils::assert_eq_text; |
3 | use insta::assert_debug_snapshot_matches; | 8 | use insta::assert_debug_snapshot_matches; |
4 | 9 | ||
5 | use ra_ide_api::{ | 10 | mod runnables; |
6 | mock_analysis::{single_file, single_file_with_position, MockAnalysis}, | ||
7 | AnalysisChange, CrateGraph, FileId, Query | ||
8 | }; | ||
9 | 11 | ||
10 | #[test] | 12 | #[test] |
11 | fn test_unresolved_module_diagnostic() { | 13 | fn test_unresolved_module_diagnostic() { |
@@ -91,6 +93,7 @@ fn test_find_all_refs_for_fn_param() { | |||
91 | let refs = get_all_refs(code); | 93 | let refs = get_all_refs(code); |
92 | assert_eq!(refs.len(), 2); | 94 | assert_eq!(refs.len(), 2); |
93 | } | 95 | } |
96 | |||
94 | #[test] | 97 | #[test] |
95 | fn test_rename_for_local() { | 98 | fn test_rename_for_local() { |
96 | test_rename( | 99 | test_rename( |
@@ -167,15 +170,35 @@ fn test_rename_for_mut_param() { | |||
167 | ); | 170 | ); |
168 | } | 171 | } |
169 | 172 | ||
173 | #[test] | ||
174 | fn test_rename_mod() { | ||
175 | let (analysis, position) = analysis_and_position( | ||
176 | " | ||
177 | //- /bar.rs | ||
178 | mod fo<|>o; | ||
179 | //- /bar/foo.rs | ||
180 | // emtpy | ||
181 | ", | ||
182 | ); | ||
183 | let new_name = "foo2"; | ||
184 | let source_change = analysis.rename(position, new_name).unwrap(); | ||
185 | assert_eq_dbg( | ||
186 | 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 })"#, | ||
187 | &source_change, | ||
188 | ); | ||
189 | } | ||
190 | |||
170 | fn test_rename(text: &str, new_name: &str, expected: &str) { | 191 | fn test_rename(text: &str, new_name: &str, expected: &str) { |
171 | let (analysis, position) = single_file_with_position(text); | 192 | let (analysis, position) = single_file_with_position(text); |
172 | let edits = analysis.rename(position, new_name).unwrap(); | 193 | let source_change = analysis.rename(position, new_name).unwrap(); |
173 | let mut text_edit_bulder = ra_text_edit::TextEditBuilder::default(); | 194 | let mut text_edit_bulder = ra_text_edit::TextEditBuilder::default(); |
174 | let mut file_id: Option<FileId> = None; | 195 | let mut file_id: Option<FileId> = None; |
175 | for edit in edits { | 196 | if let Some(change) = source_change { |
176 | file_id = Some(edit.file_id); | 197 | for edit in change.source_file_edits { |
177 | for atom in edit.edit.as_atoms() { | 198 | file_id = Some(edit.file_id); |
178 | text_edit_bulder.replace(atom.delete, atom.insert.clone()); | 199 | for atom in edit.edit.as_atoms() { |
200 | text_edit_bulder.replace(atom.delete, atom.insert.clone()); | ||
201 | } | ||
179 | } | 202 | } |
180 | } | 203 | } |
181 | let result = text_edit_bulder | 204 | 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> { | |||
411 | } | 411 | } |
412 | 412 | ||
413 | impl<'a> PoolDispatcher<'a> { | 413 | impl<'a> PoolDispatcher<'a> { |
414 | fn on<'b, R>( | 414 | fn on<R>(&mut self, f: fn(ServerWorld, R::Params) -> Result<R::Result>) -> Result<&mut Self> |
415 | &'b mut self, | ||
416 | f: fn(ServerWorld, R::Params) -> Result<R::Result>, | ||
417 | ) -> Result<&'b mut Self> | ||
418 | where | 415 | where |
419 | R: req::Request, | 416 | R: req::Request, |
420 | R::Params: DeserializeOwned + Send + 'static, | 417 | 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 @@ | |||
1 | use std::collections::HashMap; | ||
2 | |||
3 | use gen_lsp_server::ErrorCode; | 1 | use gen_lsp_server::ErrorCode; |
4 | use lsp_types::{ | 2 | use lsp_types::{ |
5 | CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity, | 3 | CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity, |
@@ -7,7 +5,7 @@ use lsp_types::{ | |||
7 | FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, | 5 | FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, |
8 | MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, | 6 | MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, |
9 | RenameParams, SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit, | 7 | RenameParams, SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit, |
10 | WorkspaceEdit, | 8 | WorkspaceEdit, DocumentChanges, TextDocumentEdit, DocumentChangeOperation, ResourceOp |
11 | }; | 9 | }; |
12 | use ra_ide_api::{ | 10 | use ra_ide_api::{ |
13 | FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity, | 11 | FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity, |
@@ -467,26 +465,43 @@ pub fn handle_rename(world: ServerWorld, params: RenameParams) -> Result<Option< | |||
467 | .into()); | 465 | .into()); |
468 | } | 466 | } |
469 | 467 | ||
470 | let renames = world | 468 | let change = world |
471 | .analysis() | 469 | .analysis() |
472 | .rename(FilePosition { file_id, offset }, &*params.new_name)?; | 470 | .rename(FilePosition { file_id, offset }, &*params.new_name)?; |
473 | if renames.is_empty() { | 471 | if change.is_none() { |
474 | return Ok(None); | 472 | return Ok(None); |
475 | } | 473 | } |
476 | 474 | ||
477 | let mut changes = HashMap::new(); | 475 | let mut source_change = change.unwrap(); |
478 | for edit in renames { | 476 | let text_document_edits = source_change |
479 | changes | 477 | .source_file_edits |
480 | .entry(file_id.try_conv_with(&world)?) | 478 | .drain(..) |
481 | .or_insert_with(Vec::new) | 479 | .into_iter() |
482 | .extend(edit.edit.conv_with(&line_index)); | 480 | .map(|e| e.try_conv_with(&world)) |
483 | } | 481 | .collect::<Result<Vec<TextDocumentEdit>>>(); |
484 | 482 | ||
485 | Ok(Some(WorkspaceEdit { | 483 | let text_document_ops = source_change |
486 | changes: Some(changes), | 484 | .file_system_edits |
485 | .drain(..) | ||
486 | .into_iter() | ||
487 | .map(|e| e.try_conv_with(&world)) | ||
488 | .collect::<Result<Vec<ResourceOp>>>(); | ||
487 | 489 | ||
488 | // TODO: return this instead if client/server support it. See #144 | 490 | let mut document_changes = Vec::new(); |
489 | document_changes: None, | 491 | document_changes.extend( |
492 | text_document_edits? | ||
493 | .into_iter() | ||
494 | .map(DocumentChangeOperation::Edit), | ||
495 | ); | ||
496 | document_changes.extend( | ||
497 | text_document_ops? | ||
498 | .into_iter() | ||
499 | .map(DocumentChangeOperation::Op), | ||
500 | ); | ||
501 | |||
502 | Ok(Some(WorkspaceEdit { | ||
503 | changes: None, | ||
504 | document_changes: Some(DocumentChanges::Operations(document_changes)), | ||
490 | })) | 505 | })) |
491 | } | 506 | } |
492 | 507 | ||