rename mod
This commit is contained in:
parent
b82fe73d1a
commit
bc0f79f74a
@ -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_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 @@ pub(crate) fn crate_for(&self, file_id: FileId) -> Vec<CrateId> {
|
||||
};
|
||||
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 @@ pub(crate) fn assists(&self, frange: FileRange) -> Vec<SourceChange> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
pub(crate) fn rename(&self, position: FilePosition, new_name: &str) -> Vec<SourceFileEdit> {
|
||||
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<Option<SourceChange>> {
|
||||
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::<ast::Module>(syntax, position.offset),
|
||||
find_node_at_offset::<ast::Name>(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::<Vec<_>>()
|
||||
}
|
||||
pub(crate) fn index_resolve(&self, name_ref: &ast::NameRef) -> Vec<FileSymbol> {
|
||||
=======
|
||||
};
|
||||
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::<Vec<_>>();
|
||||
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<Vec<FileSymbol>> {
|
||||
>>>>>>> rename mod
|
||||
let name = name_ref.text();
|
||||
let mut query = Query::new(name.to_string());
|
||||
query.exact();
|
||||
|
@ -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 foo(i<|> : u32) -> u32 {
|
||||
let refs = get_all_refs(code);
|
||||
assert_eq!(refs.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename_for_local() {
|
||||
test_rename(
|
||||
@ -167,15 +170,35 @@ fn foo(mut new_name : u32) -> u32 {
|
||||
);
|
||||
}
|
||||
|
||||
#[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<FileId> = 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
|
||||
|
@ -411,10 +411,7 @@ struct PoolDispatcher<'a> {
|
||||
}
|
||||
|
||||
impl<'a> PoolDispatcher<'a> {
|
||||
fn on<'b, R>(
|
||||
&'b mut self,
|
||||
f: fn(ServerWorld, R::Params) -> Result<R::Result>,
|
||||
) -> Result<&'b mut Self>
|
||||
fn on<R>(&mut self, f: fn(ServerWorld, R::Params) -> Result<R::Result>) -> Result<&mut Self>
|
||||
where
|
||||
R: req::Request,
|
||||
R::Params: DeserializeOwned + Send + 'static,
|
||||
|
@ -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 @@
|
||||
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<Option<
|
||||
.into());
|
||||
}
|
||||
|
||||
let renames = world
|
||||
let change = world
|
||||
.analysis()
|
||||
.rename(FilePosition { file_id, offset }, &*params.new_name)?;
|
||||
if renames.is_empty() {
|
||||
if change.is_none() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut changes = HashMap::new();
|
||||
for edit in renames {
|
||||
changes
|
||||
.entry(file_id.try_conv_with(&world)?)
|
||||
.or_insert_with(Vec::new)
|
||||
.extend(edit.edit.conv_with(&line_index));
|
||||
}
|
||||
let mut source_change = change.unwrap();
|
||||
let text_document_edits = source_change
|
||||
.source_file_edits
|
||||
.drain(..)
|
||||
.into_iter()
|
||||
.map(|e| e.try_conv_with(&world))
|
||||
.collect::<Result<Vec<TextDocumentEdit>>>();
|
||||
|
||||
let text_document_ops = source_change
|
||||
.file_system_edits
|
||||
.drain(..)
|
||||
.into_iter()
|
||||
.map(|e| e.try_conv_with(&world))
|
||||
.collect::<Result<Vec<ResourceOp>>>();
|
||||
|
||||
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: Some(changes),
|
||||
|
||||
// TODO: return this instead if client/server support it. See #144
|
||||
document_changes: None,
|
||||
changes: None,
|
||||
document_changes: Some(DocumentChanges::Operations(document_changes)),
|
||||
}))
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user