diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index bbfdadafc72..647bbc8af54 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs @@ -15,11 +15,13 @@ use completions::flyimport::position_for_import; use ide_db::{ base_db::FilePosition, helpers::{ - import_assets::{LocatedImport, NameToImport}, - insert_use::ImportScope, + import_assets::NameToImport, + insert_use::{self, ImportScope}, + mod_path_to_ast, }, items_locator, RootDatabase, }; +use syntax::algo; use text_edit::TextEdit; use crate::{completions::Completions, context::CompletionContext, item::CompletionKind}; @@ -177,41 +179,35 @@ pub fn resolve_completion_edits( position: FilePosition, imports: impl IntoIterator, ) -> Option> { + let _p = profile::span("resolve_completion_edits"); let ctx = CompletionContext::new(db, position, config)?; let position_for_import = position_for_import(&ctx, None)?; let scope = ImportScope::find_insert_use_container_with_macros(position_for_import, &ctx.sema)?; let current_module = ctx.sema.scope(position_for_import).module()?; let current_crate = current_module.krate(); + let new_ast = scope.clone_for_update(); + let mut import_insert = TextEdit::builder(); - Some( - imports - .into_iter() - .filter_map(|(full_import_path, imported_name)| { - let (import_path, item_to_import) = items_locator::items_with_name( - &ctx.sema, - current_crate, - NameToImport::Exact(imported_name), - items_locator::AssocItemSearch::Include, - Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()), - ) - .filter_map(|candidate| { - current_module - .find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind) - .zip(Some(candidate)) - }) - .find(|(mod_path, _)| mod_path.to_string() == full_import_path)?; - let import = LocatedImport::new( - import_path.clone(), - item_to_import, - item_to_import, - Some(import_path), - ); - - ImportEdit { import, scope: scope.clone() } - .to_text_edit(config.insert_use) - .map(|edit| edit) + // FIXME: lift out and make some tests here, this is ImportEdit::to_text_edit but changed to work with multiple edits + imports.into_iter().for_each(|(full_import_path, imported_name)| { + let items_with_name = items_locator::items_with_name( + &ctx.sema, + current_crate, + NameToImport::Exact(imported_name), + items_locator::AssocItemSearch::Include, + Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()), + ); + let import = items_with_name + .filter_map(|candidate| { + current_module.find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind) }) - .collect(), - ) + .find(|mod_path| mod_path.to_string() == full_import_path); + if let Some(import_path) = import { + insert_use::insert_use(&new_ast, mod_path_to_ast(&import_path), &config.insert_use); + } + }); + + algo::diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert); + Some(vec![import_insert.finish()]) }