实现例化自动补全

This commit is contained in:
锦恢 2024-10-28 18:08:48 +08:00
parent 4bde6263a3
commit 8d733112c4
4 changed files with 120 additions and 4 deletions

View File

@ -1,4 +1,4 @@
use crate::{completion::feature::{get_dot_completion, include_path_completion}, server::LSPServer, sources::LSPSupport, utils::get_language_id_by_uri}; use crate::{completion::feature::{get_dot_completion, include_path_completion}, hover::feature::make_module_profile_code, server::LSPServer, sources::LSPSupport, utils::get_language_id_by_uri};
use log::info; use log::info;
use ropey::{Rope, RopeSlice}; use ropey::{Rope, RopeSlice};
use tower_lsp::lsp_types::*; use tower_lsp::lsp_types::*;
@ -26,6 +26,7 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<Compl
let response = match &params.context { let response = match &params.context {
Some(context) => match context.trigger_kind { Some(context) => match context.trigger_kind {
// 特殊字符触发
CompletionTriggerKind::TRIGGER_CHARACTER => { CompletionTriggerKind::TRIGGER_CHARACTER => {
// info!("trigger character"); // info!("trigger character");
let trigger_character = context.trigger_character.clone().unwrap(); let trigger_character = context.trigger_character.clone().unwrap();
@ -54,6 +55,7 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<Compl
} }
} }
CompletionTriggerKind::TRIGGER_FOR_INCOMPLETE_COMPLETIONS => None, CompletionTriggerKind::TRIGGER_FOR_INCOMPLETE_COMPLETIONS => None,
// 常规触发
CompletionTriggerKind::INVOKED => { CompletionTriggerKind::INVOKED => {
let mut comps = server.srcs.get_completions( let mut comps = server.srcs.get_completions(
&token, &token,
@ -61,6 +63,8 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<Compl
&doc.text_document.uri, &doc.text_document.uri,
)?; )?;
info!("current completion token: {}", token);
// complete keywords // complete keywords
comps.items.extend::<Vec<CompletionItem>>( comps.items.extend::<Vec<CompletionItem>>(
server.key_comps server.key_comps
@ -69,7 +73,15 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<Compl
.cloned() .cloned()
.collect(), .collect(),
); );
// 加入例化自动补全的
comps.items.extend::<Vec<CompletionItem>>(
make_module_completions(server, &token, &language_id)
);
comps.items.dedup_by_key(|i| i.label.clone()); comps.items.dedup_by_key(|i| i.label.clone());
// info!("invoked return comps {:?}", comps); // info!("invoked return comps {:?}", comps);
Some(comps) Some(comps)
} }
@ -107,6 +119,7 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<Compl
.collect(), .collect(),
); );
comps.items.dedup_by_key(|i| i.label.clone()); comps.items.dedup_by_key(|i| i.label.clone());
Some(comps) Some(comps)
} }
} }
@ -186,3 +199,103 @@ fn get_completion_token(text: &Rope, line: RopeSlice, pos: Position) -> String {
} }
} }
fn make_instantiation_code(module: &crate::core::hdlparam::Module) -> String {
// makeVlogParamAssignments 参数信息列表
let mut snippet_codes = Vec::<String>::new();
let mut placeholder_id: u32 = 1;
snippet_codes.push(format!("{} ", module.name));
let params_length = module.params.len();
let ports_length = module.ports.len();
if params_length > 0 {
snippet_codes.push("#(\n".to_string());
let max_name_length = module.params.iter().map(|param| param.name.len()).max().unwrap_or(0);
let max_init_length = module.params.iter().map(|param| param.init.len()).max().unwrap_or(0);
let mut i: usize = 0;
for param in &module.params {
// 写入 .NAME ( INIT ),
let padding_name = format!("{}{}", param.name, " ".repeat(max_name_length - param.name.len() + 1));
snippet_codes.push(format!("\t.{}\t(", padding_name));
snippet_codes.push(format!("${{{}:{}}}", placeholder_id, param.init));
placeholder_id += 1;
snippet_codes.push(format!("{} )", " ".repeat(max_init_length - param.init.len() + 1)));
if i < params_length - 1 {
snippet_codes.push(",\n".to_string());
}
i += 1;
}
snippet_codes.push(")\n".to_string());
}
snippet_codes.push(format!("u_{}", module.name));
if ports_length > 0 {
let max_name_length = module.ports.iter().map(|port| port.name.len()).max().unwrap_or(0);
snippet_codes.push("(\n".to_string());
let mut i: usize = 0;
for port in &module.ports {
let padding_name = format!("{}{}", port.name, " ".repeat(max_name_length - port.name.len() + 1));
snippet_codes.push(format!("\t.{}\t(", padding_name));
snippet_codes.push(format!("${{{}:{}}}", placeholder_id, port.name));
placeholder_id += 1;
snippet_codes.push(format!("{} )", " ".repeat(max_name_length - port.name.len() + 1)));
if i < ports_length - 1 {
snippet_codes.push(",".to_string());
}
snippet_codes.push("\n".to_string());
i += 1;
}
snippet_codes.push(");\n".to_string());
}
snippet_codes.join("")
}
fn make_module_completions(
server: &LSPServer,
token: &str,
language_id: &str
) -> Vec<CompletionItem> {
let mut module_completioms = Vec::<CompletionItem>::new();
let prefix = token.to_string().to_lowercase();
let path_to_files = server.srcs.hdl_param.path_to_hdl_file.read().unwrap();
// 遍历 hdlparam 中所有的 modules
for (_, hdl_file) in path_to_files.iter() {
for module in &hdl_file.fast.content {
if !module.name.to_string().to_lowercase().starts_with(&prefix) {
continue;
}
let insert_text = make_instantiation_code(module);
let module_profile = make_module_profile_code(module);
let module_profile = MarkupContent {
kind: MarkupKind::Markdown,
value: format!("```{}\n{}\n```", language_id, module_profile)
};
let item = CompletionItem {
label: module.name.to_string(),
detail: Some("module instantiation".to_string()),
documentation: Some(Documentation::MarkupContent(module_profile)),
kind: Some(CompletionItemKind::CLASS),
insert_text: Some(insert_text),
insert_text_format: Some(InsertTextFormat::SNIPPET),
..CompletionItem::default()
};
module_completioms.push(item);
}
}
module_completioms
}

View File

@ -1,5 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::RwLock; use std::sync::RwLock;
use std::sync::RwLockReadGuard;
use log::info; use log::info;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -387,6 +388,8 @@ pub struct HdlParam {
pub module_name_to_path: RwLock<HashMap<String, String>> pub module_name_to_path: RwLock<HashMap<String, String>>
} }
impl HdlParam { impl HdlParam {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {

View File

@ -441,7 +441,7 @@ pub fn hover_module_declaration(
/// 根据 module 获取 module 的简单描述代码 /// 根据 module 获取 module 的简单描述代码
fn make_module_profile_code(module: &crate::core::hdlparam::Module) -> String { pub fn make_module_profile_code(module: &crate::core::hdlparam::Module) -> String {
let mut codes = Vec::<String>::new(); let mut codes = Vec::<String>::new();
let param_num = module.params.len(); let param_num = module.params.len();
let port_num = module.ports.len(); let port_num = module.ports.len();