use lsp_types::CompletionItem;
use lsp_types::CompletionItemKind;
use crate::lsp::workspace::{SymbolKind, WorkspaceState};
pub fn is_in_import_context(text_before: &str) -> bool {
let lines: Vec<&str> = text_before.lines().collect();
if let Some(last_line) = lines.last() {
let trimmed = last_line.trim();
if trimmed.contains(';') {
return false;
}
if trimmed == "import" || trimmed.starts_with("import ") {
return true;
}
}
false
}
pub fn get_workspace_completions(
workspace: &WorkspaceState,
is_import_context: bool,
) -> Vec<CompletionItem> {
let mut items = Vec::new();
let mut seen = std::collections::HashSet::new();
for symbol in workspace.find_symbols("") {
if !seen.insert(&symbol.qualified_name) {
continue;
}
match symbol.kind {
SymbolKind::Component | SymbolKind::Parameter | SymbolKind::Constant => continue,
_ => {}
}
if !is_import_context && symbol.qualified_name.contains('.') {
continue;
}
let kind = symbol_kind_to_completion_kind(symbol.kind);
let simple_name = symbol
.qualified_name
.rsplit('.')
.next()
.unwrap_or(&symbol.qualified_name);
if is_import_context {
items.push(CompletionItem {
label: symbol.qualified_name.clone(),
kind: Some(kind),
detail: symbol.detail.clone(),
..Default::default()
});
} else {
items.push(CompletionItem {
label: simple_name.to_string(),
kind: Some(kind),
detail: Some(symbol.qualified_name.clone()),
filter_text: Some(format!("{} {}", simple_name, symbol.qualified_name)),
..Default::default()
});
}
}
if is_import_context {
items.extend(get_modelica_path_packages(workspace));
}
items
}
fn get_modelica_path_packages(workspace: &WorkspaceState) -> Vec<CompletionItem> {
let mut items = Vec::new();
let mut seen = std::collections::HashSet::new();
for symbol in workspace.find_symbols("") {
let top_level = symbol
.qualified_name
.split('.')
.next()
.unwrap_or(&symbol.qualified_name);
if seen.insert(top_level.to_string()) {
items.push(CompletionItem {
label: top_level.to_string(),
kind: Some(CompletionItemKind::MODULE),
detail: Some("Package".to_string()),
..Default::default()
});
}
}
items
}
pub fn get_workspace_member_completions(
workspace: &WorkspaceState,
prefix: &str,
) -> Vec<CompletionItem> {
let mut items = Vec::new();
let prefix_with_dot = format!("{}.", prefix);
for symbol in workspace.find_symbols("") {
if symbol.qualified_name.starts_with(&prefix_with_dot) {
let remainder = &symbol.qualified_name[prefix_with_dot.len()..];
if !remainder.contains('.') {
let kind = symbol_kind_to_completion_kind(symbol.kind);
items.push(CompletionItem {
label: remainder.to_string(),
kind: Some(kind),
detail: symbol.detail.clone(),
..Default::default()
});
}
}
}
items
}
fn symbol_kind_to_completion_kind(kind: SymbolKind) -> CompletionItemKind {
match kind {
SymbolKind::Package => CompletionItemKind::MODULE,
SymbolKind::Model => CompletionItemKind::CLASS,
SymbolKind::Class => CompletionItemKind::CLASS,
SymbolKind::Block => CompletionItemKind::CLASS,
SymbolKind::Connector => CompletionItemKind::INTERFACE,
SymbolKind::Record => CompletionItemKind::STRUCT,
SymbolKind::Type => CompletionItemKind::TYPE_PARAMETER,
SymbolKind::Function => CompletionItemKind::FUNCTION,
SymbolKind::Operator => CompletionItemKind::OPERATOR,
SymbolKind::Component => CompletionItemKind::FIELD,
SymbolKind::Parameter => CompletionItemKind::CONSTANT,
SymbolKind::Constant => CompletionItemKind::CONSTANT,
}
}