From 8d733112c46f7a2c2a47deaf6f3086c7b145ac62 Mon Sep 17 00:00:00 2001 From: LSTM-Kirigaya <1193466151@qq.com> Date: Mon, 28 Oct 2024 18:08:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=BE=8B=E5=8C=96=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=A1=A5=E5=85=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/completion/sv.rs | 115 ++++++++++++++++++++++++++++++++++++++++++- src/core/hdlparam.rs | 5 +- src/hover/feature.rs | 2 +- src/hover/sv.rs | 2 +- 4 files changed, 120 insertions(+), 4 deletions(-) diff --git a/src/completion/sv.rs b/src/completion/sv.rs index 1a8c106..669dee0 100644 --- a/src/completion/sv.rs +++ b/src/completion/sv.rs @@ -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 ropey::{Rope, RopeSlice}; use tower_lsp::lsp_types::*; @@ -26,6 +26,7 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option match context.trigger_kind { + // 特殊字符触发 CompletionTriggerKind::TRIGGER_CHARACTER => { // info!("trigger character"); let trigger_character = context.trigger_character.clone().unwrap(); @@ -54,12 +55,15 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option None, + // 常规触发 CompletionTriggerKind::INVOKED => { let mut comps = server.srcs.get_completions( &token, file.text.pos_to_byte(&doc.position), &doc.text_document.uri, )?; + + info!("current completion token: {}", token); // complete keywords comps.items.extend::>( @@ -69,7 +73,15 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option>( + make_module_completions(server, &token, &language_id) + ); + comps.items.dedup_by_key(|i| i.label.clone()); + + // info!("invoked return comps {:?}", comps); Some(comps) } @@ -107,6 +119,7 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option String { } } + + +fn make_instantiation_code(module: &crate::core::hdlparam::Module) -> String { + // makeVlogParamAssignments 参数信息列表 + let mut snippet_codes = Vec::::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 { + let mut module_completioms = Vec::::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 +} \ No newline at end of file diff --git a/src/core/hdlparam.rs b/src/core/hdlparam.rs index 163e90b..e38788a 100644 --- a/src/core/hdlparam.rs +++ b/src/core/hdlparam.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::sync::RwLock; +use std::sync::RwLockReadGuard; use log::info; use serde::{Deserialize, Serialize}; @@ -387,6 +388,8 @@ pub struct HdlParam { pub module_name_to_path: RwLock> } + + impl HdlParam { pub fn new() -> Self { Self { @@ -450,7 +453,7 @@ impl HdlParam { } None } - + /// 遍历 path_string 下的所有 instance,并根据条件返回 pub fn walk_instantiation(&self, path_string: &str, condition: impl Fn(&Module, &Instance) -> bool) -> Option { let path_to_hdl_file = self.path_to_hdl_file.read().unwrap(); diff --git a/src/hover/feature.rs b/src/hover/feature.rs index 462feef..d3ca398 100644 --- a/src/hover/feature.rs +++ b/src/hover/feature.rs @@ -441,7 +441,7 @@ pub fn hover_module_declaration( /// 根据 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::::new(); let param_num = module.params.len(); let port_num = module.ports.len(); diff --git a/src/hover/sv.rs b/src/hover/sv.rs index f19790a..093e5c8 100644 --- a/src/hover/sv.rs +++ b/src/hover/sv.rs @@ -27,7 +27,7 @@ pub fn hover(server: &LSPServer, params: &HoverParams) -> Option { if let Some(hover) = hover_include(doc, &line_text, pos, &language_id) { return Some(hover); } - + // match macro if let Some(hover) = hover_macro(server, &line_text, pos, &language_id) { return Some(hover);