实现例化自动补全
This commit is contained in:
parent
4bde6263a3
commit
8d733112c4
@ -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 ¶ms.context {
|
let response = match ¶ms.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,12 +55,15 @@ 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,
|
||||||
file.text.pos_to_byte(&doc.position),
|
file.text.pos_to_byte(&doc.position),
|
||||||
&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>>(
|
||||||
@ -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
|
||||||
|
}
|
@ -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 {
|
||||||
@ -450,7 +453,7 @@ impl HdlParam {
|
|||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 遍历 path_string 下的所有 instance,并根据条件返回
|
/// 遍历 path_string 下的所有 instance,并根据条件返回
|
||||||
pub fn walk_instantiation(&self, path_string: &str, condition: impl Fn(&Module, &Instance) -> bool) -> Option<Instance> {
|
pub fn walk_instantiation(&self, path_string: &str, condition: impl Fn(&Module, &Instance) -> bool) -> Option<Instance> {
|
||||||
let path_to_hdl_file = self.path_to_hdl_file.read().unwrap();
|
let path_to_hdl_file = self.path_to_hdl_file.read().unwrap();
|
||||||
|
@ -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();
|
||||||
|
@ -27,7 +27,7 @@ pub fn hover(server: &LSPServer, params: &HoverParams) -> Option<Hover> {
|
|||||||
if let Some(hover) = hover_include(doc, &line_text, pos, &language_id) {
|
if let Some(hover) = hover_include(doc, &line_text, pos, &language_id) {
|
||||||
return Some(hover);
|
return Some(hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
// match macro
|
// match macro
|
||||||
if let Some(hover) = hover_macro(server, &line_text, pos, &language_id) {
|
if let Some(hover) = hover_macro(server, &line_text, pos, &language_id) {
|
||||||
return Some(hover);
|
return Some(hover);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user