use crate::error::Result;
use crate::lsp::LanguageServerManager;
use crate::tools::{ensure_document_open, make_position};
use lsp_types::{CompletionItem, CompletionItemKind, CompletionResponse};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Serialize, Deserialize)]
pub struct CompletionItemInfo {
pub label: String,
pub kind: Option<String>,
pub detail: Option<String>,
pub documentation: Option<String>,
pub insert_text: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CompletionResult {
pub items: Vec<CompletionItemInfo>,
pub is_incomplete: bool,
}
pub fn completion(
manager: &LanguageServerManager,
file_path: &str,
line: u32,
character: u32,
trigger_character: Option<String>,
) -> Result<CompletionResult> {
let path = PathBuf::from(file_path);
let (client, uri) = ensure_document_open(manager, &path)?;
let position = make_position(line, character);
let response = client.completion(&uri, position, trigger_character)?;
let (items, is_incomplete) = match response {
Some(CompletionResponse::Array(items)) => (items, false),
Some(CompletionResponse::List(list)) => (list.items, list.is_incomplete),
None => (vec![], false),
};
let completion_items: Vec<CompletionItemInfo> = items
.into_iter()
.map(convert_completion_item)
.collect();
Ok(CompletionResult {
items: completion_items,
is_incomplete,
})
}
fn convert_completion_item(item: CompletionItem) -> CompletionItemInfo {
CompletionItemInfo {
label: item.label,
kind: item.kind.map(completion_kind_to_string),
detail: item.detail,
documentation: item.documentation.map(|doc| match doc {
lsp_types::Documentation::String(s) => s,
lsp_types::Documentation::MarkupContent(m) => m.value,
}),
insert_text: item.insert_text.or_else(|| item.text_edit.map(|edit| {
match edit {
lsp_types::CompletionTextEdit::Edit(e) => e.new_text,
lsp_types::CompletionTextEdit::InsertAndReplace(e) => e.new_text,
}
})),
}
}
fn completion_kind_to_string(kind: CompletionItemKind) -> String {
match kind {
CompletionItemKind::TEXT => "text",
CompletionItemKind::METHOD => "method",
CompletionItemKind::FUNCTION => "function",
CompletionItemKind::CONSTRUCTOR => "constructor",
CompletionItemKind::FIELD => "field",
CompletionItemKind::VARIABLE => "variable",
CompletionItemKind::CLASS => "class",
CompletionItemKind::INTERFACE => "interface",
CompletionItemKind::MODULE => "module",
CompletionItemKind::PROPERTY => "property",
CompletionItemKind::UNIT => "unit",
CompletionItemKind::VALUE => "value",
CompletionItemKind::ENUM => "enum",
CompletionItemKind::KEYWORD => "keyword",
CompletionItemKind::SNIPPET => "snippet",
CompletionItemKind::COLOR => "color",
CompletionItemKind::FILE => "file",
CompletionItemKind::REFERENCE => "reference",
CompletionItemKind::FOLDER => "folder",
CompletionItemKind::ENUM_MEMBER => "enum_member",
CompletionItemKind::CONSTANT => "constant",
CompletionItemKind::STRUCT => "struct",
CompletionItemKind::EVENT => "event",
CompletionItemKind::OPERATOR => "operator",
CompletionItemKind::TYPE_PARAMETER => "type_parameter",
_ => "unknown",
}
.to_string()
}