diff options
Diffstat (limited to 'support/texlab/crates/texlab/src/features/completion.rs')
-rw-r--r-- | support/texlab/crates/texlab/src/features/completion.rs | 108 |
1 files changed, 56 insertions, 52 deletions
diff --git a/support/texlab/crates/texlab/src/features/completion.rs b/support/texlab/crates/texlab/src/features/completion.rs index 8e5fa2adbb..5d32588970 100644 --- a/support/texlab/crates/texlab/src/features/completion.rs +++ b/support/texlab/crates/texlab/src/features/completion.rs @@ -1,73 +1,77 @@ -use base_db::{util::RenderedObject, Document, FeatureParams, Workspace}; -use completion::{ - ArgumentData, CompletionItem, CompletionItemData, CompletionParams, EntryTypeData, - FieldTypeData, -}; +use base_db::{util::RenderedObject, Workspace}; +use completion::{ArgumentData, CompletionItem, CompletionItemData, EntryTypeData, FieldTypeData}; use line_index::LineIndex; -use lsp_types::{ClientCapabilities, ClientInfo, CompletionList}; +use rowan::ast::AstNode; use serde::{Deserialize, Serialize}; +use syntax::bibtex; -use crate::util::{ - capabilities::ClientCapabilitiesExt, line_index_ext::LineIndexExt, lsp_enums::Structure, -}; +use crate::util::{from_proto, line_index_ext::LineIndexExt, lsp_enums::Structure, ClientFlags}; pub fn complete( workspace: &Workspace, - params: &lsp_types::CompletionParams, - client_capabilities: &ClientCapabilities, - client_info: Option<&ClientInfo>, -) -> Option<CompletionList> { - let document = workspace.lookup(¶ms.text_document_position.text_document.uri)?; - let feature = FeatureParams::new(workspace, document); - let offset = document - .line_index - .offset_lsp(params.text_document_position.position)?; - - let params = CompletionParams { feature, offset }; + params: lsp_types::CompletionParams, + client_flags: &ClientFlags, +) -> Option<lsp_types::CompletionList> { + let params = from_proto::completion_params(workspace, params)?; let result = completion::complete(¶ms); - let mut list = CompletionList::default(); - let item_builder = ItemBuilder::new(document, client_capabilities); - let always_incomplete = client_info.map_or(false, |info| info.name == "Visual Studio Code"); - list.is_incomplete = always_incomplete || result.items.len() >= completion::LIMIT; - list.items = result + let item_builder = ItemBuilder { + line_index: ¶ms.feature.document.line_index, + client_flags, + }; + + let is_incomplete = + client_flags.completion_always_incomplete || result.items.len() >= completion::LIMIT; + + let items = result .items .into_iter() .enumerate() .filter_map(|(i, item)| item_builder.convert(item, i)) .collect(); - Some(list) + Some(lsp_types::CompletionList { + is_incomplete, + items, + }) +} + +pub fn resolve(workspace: &Workspace, item: &mut lsp_types::CompletionItem) -> Option<()> { + let data = from_proto::completion_resolve_info(item)?; + match data { + ResolveInfo::Package | ResolveInfo::DocumentClass => { + let metadata = completion_data::DATABASE.meta(&item.label)?; + let value = metadata.description.as_deref()?.into(); + item.documentation = Some(lsp_types::Documentation::MarkupContent( + lsp_types::MarkupContent { + kind: lsp_types::MarkupKind::PlainText, + value, + }, + )); + } + ResolveInfo::Citation { uri, key } => { + let data = workspace.lookup(&uri)?.data.as_bib()?; + let root = bibtex::Root::cast(data.root_node())?; + let entry = root.find_entry(&key)?; + let value = citeproc::render(&entry)?; + item.documentation = Some(lsp_types::Documentation::MarkupContent( + lsp_types::MarkupContent { + kind: lsp_types::MarkupKind::Markdown, + value, + }, + )); + } + } + + Some(()) } struct ItemBuilder<'a> { line_index: &'a LineIndex, - item_kinds: &'a [lsp_types::CompletionItemKind], - supports_snippets: bool, - supports_images: bool, + client_flags: &'a ClientFlags, } impl<'a> ItemBuilder<'a> { - pub fn new(document: &'a Document, client_capabilities: &'a ClientCapabilities) -> Self { - let line_index = &document.line_index; - let item_kinds = client_capabilities - .text_document - .as_ref() - .and_then(|cap| cap.completion.as_ref()) - .and_then(|cap| cap.completion_item_kind.as_ref()) - .and_then(|cap| cap.value_set.as_deref()) - .unwrap_or_default(); - - let supports_snippets = client_capabilities.has_snippet_support(); - let supports_images = client_capabilities.has_completion_markdown_support(); - Self { - line_index, - item_kinds, - supports_snippets, - supports_images, - } - } - pub fn convert(&self, item: CompletionItem, index: usize) -> Option<lsp_types::CompletionItem> { let mut result = lsp_types::CompletionItem::default(); let range = self.line_index.line_col_lsp_range(item.range)?; @@ -125,7 +129,7 @@ impl<'a> ItemBuilder<'a> { if result .kind - .is_some_and(|kind| !self.item_kinds.contains(&kind)) + .is_some_and(|kind| !self.client_flags.completion_kinds.contains(&kind)) { result.kind = Some(lsp_types::CompletionItemKind::TEXT); } @@ -166,7 +170,7 @@ impl<'a> ItemBuilder<'a> { result: &mut lsp_types::CompletionItem, range: lsp_types::Range, ) { - if self.supports_snippets { + if self.client_flags.completion_snippets { result.kind = Some(Structure::Snippet.completion_kind()); result.text_edit = Some(lsp_types::TextEdit::new(range, "begin{$1}\n\t$0\n\\end{$1}".into()).into()); @@ -386,7 +390,7 @@ impl<'a> ItemBuilder<'a> { } fn inline_image(&self, name: &str, base64: &str) -> Option<lsp_types::Documentation> { - if self.supports_images { + if self.client_flags.completion_markdown { let kind = lsp_types::MarkupKind::Markdown; let value = format!("![{name}](data:image/png;base64,{base64}|width=48,height=48)"); let content = lsp_types::MarkupContent { kind, value }; |