aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide_api/src/imp.rs90
-rw-r--r--crates/ra_ide_api/tests/test/main.rs41
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs5
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs47
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 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use hir::{ 3use hir::{
4 self, Problem, source_binder, 4 self, Problem, source_binder::{
5 self,
6 module_from_declaration
7 }, ModuleSource,
5}; 8};
6use ra_db::{ 9use ra_db::{
7 FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase, 10 FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase,
@@ -9,16 +12,16 @@ use ra_db::{
9}; 12};
10use ra_ide_api_light::{self, assists, LocalEdit, Severity}; 13use ra_ide_api_light::{self, assists, LocalEdit, Severity};
11use ra_syntax::{ 14use 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
17use crate::{ 20use 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
24impl db::RootDatabase { 27impl 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 @@
1use ra_ide_api::{
2 AnalysisChange,
3 CrateGraph, FileId, mock_analysis::{MockAnalysis, single_file, single_file_with_position}, Query,
4};
5use ra_ide_api::mock_analysis::analysis_and_position;
1use ra_syntax::TextRange; 6use ra_syntax::TextRange;
2use test_utils::assert_eq_text; 7use test_utils::assert_eq_text;
3use insta::assert_debug_snapshot_matches; 8use insta::assert_debug_snapshot_matches;
4 9
5use ra_ide_api::{ 10mod runnables;
6 mock_analysis::{single_file, single_file_with_position, MockAnalysis},
7 AnalysisChange, CrateGraph, FileId, Query
8};
9 11
10#[test] 12#[test]
11fn test_unresolved_module_diagnostic() { 13fn 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]
95fn test_rename_for_local() { 98fn 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]
174fn 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
170fn test_rename(text: &str, new_name: &str, expected: &str) { 191fn 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
413impl<'a> PoolDispatcher<'a> { 413impl<'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 @@
1use std::collections::HashMap;
2
3use gen_lsp_server::ErrorCode; 1use gen_lsp_server::ErrorCode;
4use lsp_types::{ 2use 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};
12use ra_ide_api::{ 10use 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