pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> {
self.ref_match
}
+
+ pub fn import_to_add(&self) -> Option<&ImportToAdd> {
+ self.import_to_add.as_ref()
+ }
}
/// An extra import to add after the completion is applied.
-#[derive(Clone)]
-pub(crate) struct ImportToAdd {
- pub(crate) import_path: ModPath,
- pub(crate) import_scope: ImportScope,
- pub(crate) merge_behaviour: Option<MergeBehaviour>,
+#[derive(Debug, Clone)]
+pub struct ImportToAdd {
+ pub import_path: ModPath,
+ pub import_scope: ImportScope,
+ pub merge_behaviour: Option<MergeBehaviour>,
}
/// A helper to make `CompletionItem`s.
pub use crate::{
config::CompletionConfig,
- item::{CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat},
+ item::{CompletionItem, CompletionItemKind, CompletionScore, ImportToAdd, InsertTextFormat},
};
//FIXME: split the following feature into fine-grained features.
},
};
pub use completion::{
- CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
+ CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportToAdd,
+ InsertTextFormat,
};
pub use ide_db::{
call_info::CallInfo,
--- /dev/null
+#[derive(Debug, Default)]
+pub struct CompletionResolveActions {}
use crossbeam_channel::{unbounded, Receiver, Sender};
use flycheck::FlycheckHandle;
-use ide::{Analysis, AnalysisHost, Change, FileId};
+use ide::{Analysis, AnalysisHost, Change, FileId, ImportToAdd};
use ide_db::base_db::{CrateId, VfsPath};
use lsp_types::{SemanticTokens, Url};
use parking_lot::{Mutex, RwLock};
pub(crate) config: Config,
pub(crate) analysis_host: AnalysisHost,
pub(crate) diagnostics: DiagnosticCollection,
+ pub(crate) additional_imports: FxHashMap<String, ImportToAdd>,
pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>,
pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
config,
analysis_host,
diagnostics: Default::default(),
+ additional_imports: FxHashMap::default(),
mem_docs: FxHashMap::default(),
semantic_tokens_cache: Arc::new(Default::default()),
vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query,
RangeInfo, Runnable, RunnableKind, SearchScope, TextEdit,
};
+use ide_db::helpers::{insert_use, mod_path_to_ast};
use itertools::Itertools;
use lsp_server::ErrorCode;
use lsp_types::{
SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
};
use project_model::TargetKind;
+use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize};
use serde_json::to_value;
use stdx::{format_to, split_once};
}
pub(crate) fn handle_completion(
- snap: GlobalStateSnapshot,
+ global_state: &mut GlobalState,
params: lsp_types::CompletionParams,
) -> Result<Option<lsp_types::CompletionResponse>> {
let _p = profile::span("handle_completion");
+ let snap = global_state.snapshot();
let position = from_proto::file_position(&snap, params.text_document_position)?;
let completion_triggered_after_single_colon = {
let mut res = false;
};
let line_index = snap.analysis.file_line_index(position.file_id)?;
let line_endings = snap.file_line_endings(position.file_id);
+ let mut additional_imports = FxHashMap::default();
+
let items: Vec<CompletionItem> = items
.into_iter()
- .flat_map(|item| to_proto::completion_item(&line_index, line_endings, item))
+ .flat_map(|item| {
+ let import_to_add = item.import_to_add().cloned();
+ let new_completion_items = to_proto::completion_item(&line_index, line_endings, item);
+ if let Some(import_to_add) = import_to_add {
+ for new_item in &new_completion_items {
+ additional_imports.insert(new_item.label.clone(), import_to_add.clone());
+ }
+ }
+ new_completion_items
+ })
+ .map(|mut item| {
+ item.data = Some(position.file_id.0.into());
+ item
+ })
.collect();
+ global_state.additional_imports = additional_imports;
+
let completion_list = lsp_types::CompletionList { is_incomplete: true, items };
Ok(Some(completion_list.into()))
}
pub(crate) fn handle_resolve_completion(
- snap: GlobalStateSnapshot,
- original_completion: CompletionItem,
-) -> Result<CompletionItem> {
+ global_state: &mut GlobalState,
+ mut original_completion: lsp_types::CompletionItem,
+) -> Result<lsp_types::CompletionItem> {
+ // TODO kb slow, takes over 130ms
let _p = profile::span("handle_resolve_completion");
- // TODO kb use the field to detect it's for autocompletion and do the insert logic
- let _data = dbg!(original_completion).data;
+
+ if let Some(import_data) =
+ global_state.additional_imports.get(dbg!(original_completion.label.as_str()))
+ {
+ let rewriter = insert_use::insert_use(
+ &import_data.import_scope,
+ mod_path_to_ast(&import_data.import_path),
+ import_data.merge_behaviour,
+ );
+ if let Some((old_ast, file_id)) =
+ // TODO kb for file_id, better use &str and then cast to u32?
+ rewriter
+ .rewrite_root()
+ .zip(original_completion.data.as_ref().and_then(|value| Some(value.as_u64()? as u32)))
+ {
+ let snap = global_state.snapshot();
+ let mut import_insert = TextEdit::builder();
+ algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert);
+ let line_index = snap.analysis.file_line_index(FileId(file_id))?;
+ let line_endings = snap.file_line_endings(FileId(file_id));
+ let text_edit = import_insert.finish();
+
+ let mut new_edits = original_completion.additional_text_edits.unwrap_or_default();
+ for indel in text_edit {
+ new_edits.push(to_proto::text_edit(&line_index, line_endings, indel));
+ }
+ original_completion.additional_text_edits = Some(new_edits);
+ }
+ }
+
Ok(original_completion)
}
mod document;
pub mod lsp_ext;
pub mod config;
+mod completions;
use ide::AnalysisHost;
use serde::de::DeserializeOwned;
handlers::handle_matching_brace(s.snapshot(), p)
})?
.on_sync::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))?
+ .on_sync::<lsp_types::request::Completion>(handlers::handle_completion)?
+ .on_sync::<lsp_types::request::ResolveCompletionItem>(
+ handlers::handle_resolve_completion,
+ )?
.on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
.on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
.on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
.on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition)
.on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation)
.on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
- .on::<lsp_types::request::Completion>(handlers::handle_completion)
- .on::<lsp_types::request::ResolveCompletionItem>(handlers::handle_resolve_completion)
.on::<lsp_types::request::CodeLensRequest>(handlers::handle_code_lens)
.on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve)
.on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range)
None => vec![res],
};
- // TODO kb need to get this logic away and store for the later resolve request
- /*
- let mut label = self.label;
- let mut lookup = self.lookup;
- let mut insert_text = self.insert_text;
- let mut text_edits = TextEdit::builder();
-
- if let Some((import_path, import_scope, merge_behaviour)) = completion_item.import_data.as_ref() {
- let import = mod_path_to_ast(&import_path);
- let mut import_path_without_last_segment = import_path;
- let _ = import_path_without_last_segment.segments.pop();
-
- if !import_path_without_last_segment.segments.is_empty() {
- if lookup.is_none() {
- lookup = Some(label.clone());
- }
- if insert_text.is_none() {
- insert_text = Some(label.clone());
- }
- label = format!("{}::{}", import_path_without_last_segment, label);
- }
-
- let rewriter = insert_use(&import_scope, import, merge_behaviour);
- if let Some(old_ast) = rewriter.rewrite_root() {
- algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits);
- }
- }
- */
-
for mut r in all_results.iter_mut() {
r.insert_text_format = Some(insert_text_format(completion_item.insert_text_format()));
}