完成了 vhdl 的自动补全(关键词自动补全 + 自动例化)
This commit is contained in:
parent
3f9d5ff1cc
commit
c40e66f3df
@ -34,7 +34,7 @@ pub fn other_completions(tasks: &[&str]) -> Vec<CompletionItem> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const KEYWORDS: &[(&str, &str)] = &[
|
pub const VLOG_KEYWORDS: &[(&str, &str)] = &[
|
||||||
("accept_on", ""),
|
("accept_on", ""),
|
||||||
("alias", ""),
|
("alias", ""),
|
||||||
("always", "always @($1) begin\nend"),
|
("always", "always @($1) begin\nend"),
|
||||||
@ -465,3 +465,103 @@ pub const DIRECTIVES: &[&str] = &[
|
|||||||
"delay_mode_unit",
|
"delay_mode_unit",
|
||||||
"delay_mode_zero",
|
"delay_mode_zero",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub const VHDL_KEYWORDS: &[(&str, &str)] = &[
|
||||||
|
("abs", ""),
|
||||||
|
("access", ""),
|
||||||
|
("after", ""),
|
||||||
|
("alias", "alias $1 is $2;"),
|
||||||
|
("all", ""),
|
||||||
|
("and", ""),
|
||||||
|
("architecture", "architecture $1 of $2 is\nbegin\n\t$3\nend $1;"),
|
||||||
|
("array", "array $1 is $2;"),
|
||||||
|
("assert", "assert $1 report $2 severity $3;"),
|
||||||
|
("attribute", "attribute $1 : $2;"),
|
||||||
|
("begin", "begin\n\t$1\nend;"),
|
||||||
|
("block", "block ($1) is\nbegin\n\t$2\nend block;"),
|
||||||
|
("body", "body $1 is\nbegin\n\t$2\nend $1;"),
|
||||||
|
("buffer", ""),
|
||||||
|
("bus", ""),
|
||||||
|
("case", "case $1 is\n\twhen $2 => $3;\nend case;"),
|
||||||
|
("component", "component $1 is\n\tport (\n\t\t$2\n\t);\nend component;"),
|
||||||
|
("configuration", "configuration $1 of $2 is\nfor $3\n\t$4\nend for;\nend $1;"),
|
||||||
|
("constant", "constant $1 : $2 := $3;"),
|
||||||
|
("disconnect", "disconnect $1 after $2;"),
|
||||||
|
("downto", ""),
|
||||||
|
("else", ""),
|
||||||
|
("elsif", ""),
|
||||||
|
("end", ""),
|
||||||
|
("entity", "entity $1 is\n\tport (\n\t\t$2\n\t);\nend $1;"),
|
||||||
|
("exit", "exit $1 when $2;"),
|
||||||
|
("file", "file $1 : $2;"),
|
||||||
|
("for", "for $1 in $2 loop\n\t$3\nend loop;"),
|
||||||
|
("function", "function $1 return $2 is\nbegin\n\t$3\nend $1;"),
|
||||||
|
("generate", "generate\n\t$1\nend generate;"),
|
||||||
|
("generic", "generic (\n\t$1\n);"),
|
||||||
|
("group", "group $1 : $2 ($3);"),
|
||||||
|
("guarded", ""),
|
||||||
|
("if", "if $1 then\n\t$2\nend if;"),
|
||||||
|
("impure", ""),
|
||||||
|
("in", ""),
|
||||||
|
("inertial", ""),
|
||||||
|
("inout", ""),
|
||||||
|
("is", ""),
|
||||||
|
("label", ""),
|
||||||
|
("library", "library $1;"),
|
||||||
|
("linkage", ""),
|
||||||
|
("literal", ""),
|
||||||
|
("loop", "loop\n\t$1\nend loop;"),
|
||||||
|
("map", "map ($1 => $2);"),
|
||||||
|
("mod", ""),
|
||||||
|
("nand", ""),
|
||||||
|
("new", ""),
|
||||||
|
("next", "next $1 when $2;"),
|
||||||
|
("nor", ""),
|
||||||
|
("not", ""),
|
||||||
|
("null", "null;"),
|
||||||
|
("of", ""),
|
||||||
|
("on", ""),
|
||||||
|
("open", ""),
|
||||||
|
("or", ""),
|
||||||
|
("others", ""),
|
||||||
|
("out", ""),
|
||||||
|
("package", "package $1 is\n\t$2\nend $1;"),
|
||||||
|
("port", "port (\n\t$1\n);"),
|
||||||
|
("postponed", ""),
|
||||||
|
("procedure", "procedure $1 is\nbegin\n\t$2\nend $1;"),
|
||||||
|
("process", "process ($1) is\nbegin\n\t$2\nend process;"),
|
||||||
|
("pure", ""),
|
||||||
|
("range", ""),
|
||||||
|
("record", "record\n\t$1\nend record;"),
|
||||||
|
("register", ""),
|
||||||
|
("reject", ""),
|
||||||
|
("rem", ""),
|
||||||
|
("report", "report $1 severity $2;"),
|
||||||
|
("return", "return $1;"),
|
||||||
|
("rol", ""),
|
||||||
|
("ror", ""),
|
||||||
|
("select", "select\n\t$1\nend select;"),
|
||||||
|
("severity", ""),
|
||||||
|
("signal", "signal $1 : $2 := $3;"),
|
||||||
|
("shared", ""),
|
||||||
|
("sla", ""),
|
||||||
|
("sll", ""),
|
||||||
|
("sra", ""),
|
||||||
|
("srl", ""),
|
||||||
|
("subtype", "subtype $1 is $2;"),
|
||||||
|
("then", ""),
|
||||||
|
("to", ""),
|
||||||
|
("transport", ""),
|
||||||
|
("type", "type $1 is $2;"),
|
||||||
|
("unaffected", ""),
|
||||||
|
("units", "units $1;\n\t$2\nend units;"),
|
||||||
|
("until", ""),
|
||||||
|
("use", "use $1;"),
|
||||||
|
("variable", "variable $1 : $2 := $3;"),
|
||||||
|
("wait", "wait on $1;"),
|
||||||
|
("when", ""),
|
||||||
|
("while", "while $1 loop\n\t$2\nend loop;"),
|
||||||
|
("with", "with $1 select\n\t$2\nend select;"),
|
||||||
|
("xnor", ""),
|
||||||
|
("xor", ""),
|
||||||
|
];
|
@ -6,7 +6,6 @@ pub mod feature;
|
|||||||
|
|
||||||
mod vhdl;
|
mod vhdl;
|
||||||
mod sv;
|
mod sv;
|
||||||
|
|
||||||
impl LSPServer {
|
impl LSPServer {
|
||||||
pub fn completion(&self, params: CompletionParams) -> Option<CompletionResponse> {
|
pub fn completion(&self, params: CompletionParams) -> Option<CompletionResponse> {
|
||||||
let language_id = get_language_id_by_uri(¶ms.text_document_position.text_document.uri);
|
let language_id = get_language_id_by_uri(¶ms.text_document_position.text_document.uri);
|
||||||
|
@ -59,7 +59,8 @@ 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(
|
// 1. 先根据 AST 获取上下文补全项
|
||||||
|
let mut completion_items = 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,
|
||||||
@ -67,25 +68,25 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<Compl
|
|||||||
|
|
||||||
info!("current completion token: {}", token);
|
info!("current completion token: {}", token);
|
||||||
|
|
||||||
// complete keywords
|
// 2. 根据 token 再加入关键词
|
||||||
comps.items.extend::<Vec<CompletionItem>>(
|
completion_items.items.extend::<Vec<CompletionItem>>(
|
||||||
server.key_comps
|
server.vlog_keyword_completion_items
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|x| x.label.starts_with(&token))
|
.filter(|x| x.label.starts_with(&token))
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// 加入例化自动补全的
|
// 3. 加入例化自动补全的
|
||||||
comps.items.extend::<Vec<CompletionItem>>(
|
completion_items.items.extend::<Vec<CompletionItem>>(
|
||||||
make_module_completions(server, &token, &language_id)
|
make_module_completions(server, &token, &language_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
comps.items.dedup_by_key(|i| i.label.clone());
|
completion_items.items.dedup_by_key(|i| i.label.clone());
|
||||||
|
|
||||||
|
|
||||||
// info!("invoked return comps {:?}", comps);
|
// info!("invoked return completion_items {:?}", completion_items);
|
||||||
Some(comps)
|
Some(completion_items)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
@ -106,23 +107,23 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<Compl
|
|||||||
items: server.directives.clone(),
|
items: server.directives.clone(),
|
||||||
}),
|
}),
|
||||||
_ => {
|
_ => {
|
||||||
let mut comps = server.srcs.get_completions(
|
let mut completion_items = 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);
|
// info!("current completion token: {}", token);
|
||||||
|
|
||||||
comps.items.extend::<Vec<CompletionItem>>(
|
completion_items.items.extend::<Vec<CompletionItem>>(
|
||||||
server.key_comps
|
server.vlog_keyword_completion_items
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|x| x.label.starts_with(&token))
|
.filter(|x| x.label.starts_with(&token))
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
comps.items.dedup_by_key(|i| i.label.clone());
|
completion_items.items.dedup_by_key(|i| i.label.clone());
|
||||||
|
|
||||||
Some(comps)
|
Some(completion_items)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,18 @@
|
|||||||
use log::info;
|
use log::info;
|
||||||
use ropey::{Rope, RopeSlice};
|
use ropey::{Rope, RopeSlice};
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
use crate::hover::feature::make_vhdl_module_profile_code;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use crate::{server::LSPServer, sources::LSPSupport, utils::get_language_id_by_uri};
|
use crate::{server::LSPServer, sources::LSPSupport, utils::get_language_id_by_uri};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Called when the client requests a completion.
|
/// Called when the client requests a completion.
|
||||||
/// This function looks in the source code to find suitable options and then returns them
|
/// This function looks in the source code to find suitable options and then returns them
|
||||||
pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<CompletionResponse> {
|
pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<CompletionResponse> {
|
||||||
let doc = ¶ms.text_document_position;
|
let doc = ¶ms.text_document_position;
|
||||||
let uri = ¶ms.text_document_position.text_document.uri;
|
let uri = ¶ms.text_document_position.text_document.uri;
|
||||||
// let pos = doc.position;
|
let language_id = get_language_id_by_uri(uri);
|
||||||
// let language_id = get_language_id_by_uri(uri);
|
|
||||||
|
|
||||||
let file_id = server.srcs.get_id(uri).to_owned();
|
let file_id = server.srcs.get_id(uri).to_owned();
|
||||||
server.srcs.wait_parse_ready(file_id, false);
|
server.srcs.wait_parse_ready(file_id, false);
|
||||||
@ -24,55 +26,48 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<Compl
|
|||||||
doc.position,
|
doc.position,
|
||||||
);
|
);
|
||||||
|
|
||||||
// info!("trigger completion token: {}", token);
|
|
||||||
// let line_text = file.text.line(pos.line as usize);
|
|
||||||
|
|
||||||
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 => {
|
||||||
// let trigger_character = context.trigger_character.clone().unwrap();
|
let trigger_character = context.trigger_character.clone().unwrap();
|
||||||
// match trigger_character.as_str() {
|
match trigger_character.as_str() {
|
||||||
// "." => {
|
// 按下 . 时需要触发的补全效果
|
||||||
// info!("trigger dot completion");
|
"." => {
|
||||||
// get_dot_completion(server, &line_text, uri, &pos, &language_id)
|
info!("trigger vhdl dot completion");
|
||||||
// },
|
None
|
||||||
// "$" => Some(CompletionList {
|
},
|
||||||
// is_incomplete: false,
|
_ => None,
|
||||||
// items: server.sys_tasks.clone(),
|
}
|
||||||
// }),
|
}
|
||||||
// "`" => Some(CompletionList {
|
CompletionTriggerKind::TRIGGER_FOR_INCOMPLETE_COMPLETIONS => None,
|
||||||
// is_incomplete: false,
|
|
||||||
// items: server.directives.clone(),
|
// 一般情况下根据字符触发的补全项目
|
||||||
// }),
|
|
||||||
// "/" => {
|
|
||||||
// info!("trigger include");
|
|
||||||
// include_path_completion(&doc.text_document.uri, &line_text, pos)
|
|
||||||
// },
|
|
||||||
// "\"" => {
|
|
||||||
// info!("trigger include");
|
|
||||||
// include_path_completion(&doc.text_document.uri, &line_text, pos)
|
|
||||||
// }
|
|
||||||
// _ => None,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// CompletionTriggerKind::TRIGGER_FOR_INCOMPLETE_COMPLETIONS => None,
|
|
||||||
CompletionTriggerKind::INVOKED => {
|
CompletionTriggerKind::INVOKED => {
|
||||||
let mut comps = server.srcs.get_completions(
|
// 1. 先根据 AST 获取上下文补全项
|
||||||
|
let mut completion_items = 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,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// complete keywords
|
// 2. 根据 token 再加入关键词
|
||||||
comps.items.extend::<Vec<CompletionItem>>(
|
completion_items.items.extend::<Vec<CompletionItem>>(
|
||||||
server.key_comps
|
server.vhdl_keyword_completiom_items
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|x| x.label.starts_with(&token))
|
.filter(|x| x.label.starts_with(&token))
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
comps.items.dedup_by_key(|i| i.label.clone());
|
|
||||||
Some(comps)
|
// 3. 加入例化自动补全的
|
||||||
|
completion_items.items.extend::<Vec<CompletionItem>>(
|
||||||
|
make_module_completions(server, &token, &language_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 去重
|
||||||
|
completion_items.items.dedup_by_key(|i| i.label.to_string());
|
||||||
|
Some(completion_items)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
@ -99,7 +94,7 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<Compl
|
|||||||
&doc.text_document.uri,
|
&doc.text_document.uri,
|
||||||
)?;
|
)?;
|
||||||
comps.items.extend::<Vec<CompletionItem>>(
|
comps.items.extend::<Vec<CompletionItem>>(
|
||||||
server.key_comps
|
server.vhdl_keyword_completiom_items
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|x| x.label.starts_with(&token))
|
.filter(|x| x.label.starts_with(&token))
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -181,3 +176,115 @@ fn get_completion_token(text: &Rope, line: RopeSlice, pos: Position) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_module_completions(
|
||||||
|
server: &LSPServer,
|
||||||
|
token: &str,
|
||||||
|
language_id: &str
|
||||||
|
) -> Vec<CompletionItem> {
|
||||||
|
let mut module_completioms = Vec::<CompletionItem>::new();
|
||||||
|
let hdl_param = server.srcs.hdl_param.clone();
|
||||||
|
|
||||||
|
let prefix = token.to_string().to_lowercase();
|
||||||
|
let module_name_to_path = hdl_param.module_name_to_path.read().unwrap();
|
||||||
|
|
||||||
|
// 遍历 hdlparam 中所有的 modules,匹配符合 prefix 前缀的(不区分大小写)
|
||||||
|
for module_name in module_name_to_path.keys() {
|
||||||
|
if !module_name.to_string().to_lowercase().starts_with(&prefix) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some((module, file_type, def_path)) = hdl_param.find_module_context_by_name(&module_name) {
|
||||||
|
let mut insert_text = Vec::<String>::new();
|
||||||
|
|
||||||
|
let (insert_text, module_profile, define_info) = if file_type == "primitives" {
|
||||||
|
// TODO: 支持原语
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
insert_text.push(make_instantiation_code(&module));
|
||||||
|
let path_uri = Url::from_file_path(def_path).unwrap().to_string();
|
||||||
|
let def_row = module.range.start.line;
|
||||||
|
let def_col = module.range.start.character;
|
||||||
|
|
||||||
|
(
|
||||||
|
insert_text.join("\n"),
|
||||||
|
make_vhdl_module_profile_code(&module),
|
||||||
|
format!("Go to [Definition]({path_uri}#L{def_row}:{def_col})")
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let module_profile = MarkupContent {
|
||||||
|
kind: MarkupKind::Markdown,
|
||||||
|
value: format!("```{}\n{}\n```\n{}", language_id, module_profile, define_info)
|
||||||
|
};
|
||||||
|
|
||||||
|
let detail = format!("module instantiation ({})", file_type);
|
||||||
|
|
||||||
|
let item = CompletionItem {
|
||||||
|
label: module.name.to_string(),
|
||||||
|
detail: Some(detail),
|
||||||
|
documentation: Some(Documentation::MarkupContent(module_profile)),
|
||||||
|
kind: Some(CompletionItemKind::CLASS),
|
||||||
|
insert_text: Some(insert_text),
|
||||||
|
// 给模块例化自动补全附上最高权重
|
||||||
|
sort_text: Some("0001".to_string()),
|
||||||
|
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
||||||
|
insert_text_mode: Some(InsertTextMode::ADJUST_INDENTATION),
|
||||||
|
..CompletionItem::default()
|
||||||
|
};
|
||||||
|
module_completioms.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module_completioms
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 实现 vhdl 例化补全的代码片段
|
||||||
|
fn make_instantiation_code(module: &crate::core::hdlparam::Module) -> String {
|
||||||
|
// TODO: 显性和隐性例化
|
||||||
|
let mut snippet_codes = Vec::<String>::new();
|
||||||
|
let mut placeholder_id: u32 = 1;
|
||||||
|
|
||||||
|
snippet_codes.push(format!("u_{} : {}\n", module.name, module.name));
|
||||||
|
|
||||||
|
// 2001 style,先计算出 generic 和 port,然后加入总体例化样板中
|
||||||
|
let params_length = module.params.len();
|
||||||
|
let ports_length = module.ports.len();
|
||||||
|
|
||||||
|
if params_length > 0 {
|
||||||
|
snippet_codes.push("generic map(\n".to_string());
|
||||||
|
|
||||||
|
let max_param_name = module.params.iter().map(|param| param.name.len()).max().unwrap_or(0);
|
||||||
|
let mut i: usize = 0;
|
||||||
|
for generic in &module.params {
|
||||||
|
let n_padding = " ".repeat(max_param_name - generic.name.len() + 1);
|
||||||
|
let placeholder_init = format!("${{{}:{}}}", placeholder_id, generic.init);
|
||||||
|
snippet_codes.push(format!("\t{}{} => {}", generic.name, n_padding, placeholder_init));
|
||||||
|
placeholder_id += 1;
|
||||||
|
if i < params_length - 1 {
|
||||||
|
snippet_codes.push(",\n".to_string());
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
snippet_codes.push(")\n".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ports_length > 0 {
|
||||||
|
snippet_codes.push("port map(\n\t-- ports\n".to_string());
|
||||||
|
|
||||||
|
let max_port_name = module.ports.iter().map(|port| port.name.len()).max().unwrap_or(0);
|
||||||
|
let mut i: usize = 0;
|
||||||
|
|
||||||
|
for port in &module.ports {
|
||||||
|
let n_padding = " ".repeat(max_port_name - port.name.len() + 1);
|
||||||
|
let placeholder_name = format!("${{{}:{}}}", placeholder_id, port.name);
|
||||||
|
snippet_codes.push(format!("\t{}{} => {}", port.name, n_padding, placeholder_name));
|
||||||
|
placeholder_id += 1;
|
||||||
|
if i < ports_length - 1 {
|
||||||
|
snippet_codes.push(",\n".to_string());
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
snippet_codes.push(");\n".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
snippet_codes.join("")
|
||||||
|
}
|
@ -740,6 +740,50 @@ pub fn make_module_profile_code(module: &crate::core::hdlparam::Module) -> Strin
|
|||||||
profile_string
|
profile_string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn make_vhdl_module_profile_code(module: &crate::core::hdlparam::Module) -> String {
|
||||||
|
let mut snippet_codes = Vec::<String>::new();
|
||||||
|
|
||||||
|
snippet_codes.push(format!("u_{} : {}\n", module.name, module.name));
|
||||||
|
|
||||||
|
// 2001 style,先计算出 generic 和 port,然后加入总体例化样板中
|
||||||
|
let params_length = module.params.len();
|
||||||
|
let ports_length = module.ports.len();
|
||||||
|
|
||||||
|
if params_length > 0 {
|
||||||
|
snippet_codes.push("generic map(\n".to_string());
|
||||||
|
|
||||||
|
let max_param_name = module.params.iter().map(|param| param.name.len()).max().unwrap_or(0);
|
||||||
|
let mut i: usize = 0;
|
||||||
|
for generic in &module.params {
|
||||||
|
let n_padding = " ".repeat(max_param_name - generic.name.len() + 1);
|
||||||
|
snippet_codes.push(format!("\t{}{} => {}", generic.name, n_padding, generic.init));
|
||||||
|
if i < params_length - 1 {
|
||||||
|
snippet_codes.push(",\n".to_string());
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
snippet_codes.push(")\n".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ports_length > 0 {
|
||||||
|
snippet_codes.push("port map(\n\t-- ports\n".to_string());
|
||||||
|
|
||||||
|
let max_port_name = module.ports.iter().map(|port| port.name.len()).max().unwrap_or(0);
|
||||||
|
let mut i: usize = 0;
|
||||||
|
|
||||||
|
for port in &module.ports {
|
||||||
|
let n_padding = " ".repeat(max_port_name - port.name.len() + 1);
|
||||||
|
snippet_codes.push(format!("\t{}{} => {}", port.name, n_padding, port.name));
|
||||||
|
if i < ports_length - 1 {
|
||||||
|
snippet_codes.push(",\n".to_string());
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
snippet_codes.push(");\n".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
snippet_codes.join("")
|
||||||
|
}
|
||||||
|
|
||||||
/// vhdl 的 entity 的 profile
|
/// vhdl 的 entity 的 profile
|
||||||
pub fn make_entity_profile_code(module: &crate::core::hdlparam::Module) -> String {
|
pub fn make_entity_profile_code(module: &crate::core::hdlparam::Module) -> String {
|
||||||
|
@ -13,7 +13,8 @@ use tower_lsp::{Client, LanguageServer};
|
|||||||
pub struct LSPServer {
|
pub struct LSPServer {
|
||||||
pub srcs: Sources,
|
pub srcs: Sources,
|
||||||
pub cache: CacheManager,
|
pub cache: CacheManager,
|
||||||
pub key_comps: Vec<CompletionItem>,
|
pub vlog_keyword_completion_items: Vec<CompletionItem>,
|
||||||
|
pub vhdl_keyword_completiom_items: Vec<CompletionItem>,
|
||||||
pub sys_tasks: Vec<CompletionItem>,
|
pub sys_tasks: Vec<CompletionItem>,
|
||||||
pub directives: Vec<CompletionItem>,
|
pub directives: Vec<CompletionItem>,
|
||||||
pub conf: Arc<RwLock<ProjectConfig>>,
|
pub conf: Arc<RwLock<ProjectConfig>>,
|
||||||
@ -28,7 +29,8 @@ impl LSPServer {
|
|||||||
LSPServer {
|
LSPServer {
|
||||||
srcs: Sources::new(),
|
srcs: Sources::new(),
|
||||||
cache: CacheManager::new(dide_home),
|
cache: CacheManager::new(dide_home),
|
||||||
key_comps: keyword_completions(KEYWORDS),
|
vlog_keyword_completion_items: keyword_completions(VLOG_KEYWORDS),
|
||||||
|
vhdl_keyword_completiom_items: keyword_completions(VHDL_KEYWORDS),
|
||||||
sys_tasks: other_completions(SYS_TASKS),
|
sys_tasks: other_completions(SYS_TASKS),
|
||||||
directives: other_completions(DIRECTIVES),
|
directives: other_completions(DIRECTIVES),
|
||||||
conf: Arc::new(RwLock::new(ProjectConfig::default())),
|
conf: Arc::new(RwLock::new(ProjectConfig::default())),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user