修复 system task 中几个未转义的命令 | 所有自动补全增加 label_details
This commit is contained in:
parent
20500a55ca
commit
aad333783e
10
.vscode/lsp.code-snippets
vendored
10
.vscode/lsp.code-snippets
vendored
@ -44,5 +44,15 @@
|
|||||||
"\t$2",
|
"\t$2",
|
||||||
"}"
|
"}"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"CompletionItemLabelDetails Snippet": {
|
||||||
|
"prefix": "label_details",
|
||||||
|
"body": [
|
||||||
|
"let label_details = CompletionItemLabelDetails {",
|
||||||
|
" description: Some(\"${1:port description}\".to_string()),",
|
||||||
|
" ..Default::default()",
|
||||||
|
"};"
|
||||||
|
],
|
||||||
|
"description": "Create a CompletionItemLabelDetails with description."
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,7 +2,7 @@ use std::{fs, path::PathBuf, str::FromStr};
|
|||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use ropey::RopeSlice;
|
use ropey::RopeSlice;
|
||||||
use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind, CompletionItemLabelDetails, CompletionList, Position, Url};
|
use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind, CompletionItemLabelDetails, CompletionList, Documentation, MarkupContent, Position, Url};
|
||||||
|
|
||||||
use crate::{server::LspServer, utils::{is_character_ordered_match, resolve_path, to_escape_path}};
|
use crate::{server::LspServer, utils::{is_character_ordered_match, resolve_path, to_escape_path}};
|
||||||
|
|
||||||
@ -63,16 +63,26 @@ pub fn include_path_completion(
|
|||||||
let file_name = file_name.unwrap();
|
let file_name = file_name.unwrap();
|
||||||
|
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
|
let label_details = CompletionItemLabelDetails {
|
||||||
|
description: Some("directory".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
completion_items.push(CompletionItem {
|
completion_items.push(CompletionItem {
|
||||||
label: file_name.to_string(),
|
label: file_name.to_string(),
|
||||||
|
label_details: Some(label_details),
|
||||||
kind: Some(CompletionItemKind::FOLDER),
|
kind: Some(CompletionItemKind::FOLDER),
|
||||||
..CompletionItem::default()
|
..CompletionItem::default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if path.is_file() {
|
if path.is_file() {
|
||||||
|
let label_details = CompletionItemLabelDetails {
|
||||||
|
description: Some("file".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
completion_items.push(CompletionItem {
|
completion_items.push(CompletionItem {
|
||||||
label: file_name.to_string(),
|
label: file_name.to_string(),
|
||||||
|
label_details: Some(label_details),
|
||||||
kind: Some(CompletionItemKind::FILE),
|
kind: Some(CompletionItemKind::FILE),
|
||||||
..CompletionItem::default()
|
..CompletionItem::default()
|
||||||
});
|
});
|
||||||
@ -92,6 +102,7 @@ pub fn include_path_completion(
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// 补全宏
|
/// 补全宏
|
||||||
pub fn vlog_directives_completion(
|
pub fn vlog_directives_completion(
|
||||||
token: &str,
|
token: &str,
|
||||||
@ -108,11 +119,22 @@ pub fn vlog_directives_completion(
|
|||||||
for hdl_file in path_to_hdl_file.values() {
|
for hdl_file in path_to_hdl_file.values() {
|
||||||
for define in &hdl_file.fast.fast_macro.defines {
|
for define in &hdl_file.fast.fast_macro.defines {
|
||||||
if is_character_ordered_match(token, &define.name) {
|
if is_character_ordered_match(token, &define.name) {
|
||||||
|
let label_details = CompletionItemLabelDetails {
|
||||||
|
description: Some("`define".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let documentation = Documentation::MarkupContent(MarkupContent {
|
||||||
|
kind: tower_lsp::lsp_types::MarkupKind::Markdown,
|
||||||
|
value: format!("```verilog\n`define {} {}\n```", define.name, define.replacement)
|
||||||
|
});
|
||||||
completion_items.push(CompletionItem {
|
completion_items.push(CompletionItem {
|
||||||
label: define.name.to_string(),
|
label: define.name.to_string(),
|
||||||
kind: Some(CompletionItemKind::CONSTANT),
|
kind: Some(CompletionItemKind::CONSTANT),
|
||||||
|
detail: Some("macro".to_string()),
|
||||||
// 用户定义的宏默认最高优先级
|
// 用户定义的宏默认最高优先级
|
||||||
sort_text: Some("0001".to_string()),
|
sort_text: Some("0".to_string()),
|
||||||
|
label_details: Some(label_details),
|
||||||
|
documentation: Some(documentation),
|
||||||
..CompletionItem::default()
|
..CompletionItem::default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -125,6 +147,48 @@ pub fn vlog_directives_completion(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 不是由 ` 触发的宏补全
|
||||||
|
pub fn vlog_directives_completion_without_prefix(
|
||||||
|
token: &str,
|
||||||
|
server: &LspServer
|
||||||
|
) -> Vec<CompletionItem> {
|
||||||
|
// 先把固定宏定义比如 include, define 这种的放入其中
|
||||||
|
let mut completion_items = server.vlog_directives.clone();
|
||||||
|
|
||||||
|
// 再从每个文件中搜集定义的宏
|
||||||
|
let hdl_param = server.srcs.hdl_param.clone();
|
||||||
|
let path_to_hdl_file = hdl_param.path_to_hdl_file.read().unwrap();
|
||||||
|
|
||||||
|
// 遍历所有的 defines
|
||||||
|
for hdl_file in path_to_hdl_file.values() {
|
||||||
|
for define in &hdl_file.fast.fast_macro.defines {
|
||||||
|
if is_character_ordered_match(token, &define.name) {
|
||||||
|
let label_details = CompletionItemLabelDetails {
|
||||||
|
description: Some("`define".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let documentation = Documentation::MarkupContent(MarkupContent {
|
||||||
|
kind: tower_lsp::lsp_types::MarkupKind::Markdown,
|
||||||
|
value: format!("```verilog\n`define {} {}\n```", define.name, define.replacement)
|
||||||
|
});
|
||||||
|
completion_items.push(CompletionItem {
|
||||||
|
label: define.name.to_string(),
|
||||||
|
kind: Some(CompletionItemKind::CONSTANT),
|
||||||
|
insert_text: Some(format!("`{}", define.name)),
|
||||||
|
detail: Some("macro".to_string()),
|
||||||
|
label_details: Some(label_details),
|
||||||
|
documentation: Some(documentation),
|
||||||
|
// 用户定义的宏默认最高优先级
|
||||||
|
sort_text: Some("0".to_string()),
|
||||||
|
..CompletionItem::default()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
completion_items
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_dot_completion(
|
pub fn get_dot_completion(
|
||||||
server: &LspServer,
|
server: &LspServer,
|
||||||
line: &RopeSlice,
|
line: &RopeSlice,
|
||||||
@ -209,14 +273,14 @@ fn get_position_port_param_completion(
|
|||||||
"primitives" => {
|
"primitives" => {
|
||||||
if let Some(primitives_inst) = inst_module.instances.first() {
|
if let Some(primitives_inst) = inst_module.instances.first() {
|
||||||
for param_assignment in &primitives_inst.intstparam_assignments {
|
for param_assignment in &primitives_inst.intstparam_assignments {
|
||||||
let label_details = CompletionItemLabelDetails {
|
|
||||||
detail: None,
|
|
||||||
..CompletionItemLabelDetails::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let name = param_assignment.parameter.clone().unwrap();
|
let name = param_assignment.parameter.clone().unwrap();
|
||||||
let param_desc = format!("parameter {}", name);
|
let param_desc = format!("parameter {}", name);
|
||||||
|
|
||||||
|
let label_details = CompletionItemLabelDetails {
|
||||||
|
description: Some("parameter".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
let c_item = CompletionItem {
|
let c_item = CompletionItem {
|
||||||
label: name,
|
label: name,
|
||||||
detail: Some(param_desc),
|
detail: Some(param_desc),
|
||||||
@ -231,8 +295,8 @@ fn get_position_port_param_completion(
|
|||||||
_ => {
|
_ => {
|
||||||
for param in inst_module.params {
|
for param in inst_module.params {
|
||||||
let label_details = CompletionItemLabelDetails {
|
let label_details = CompletionItemLabelDetails {
|
||||||
detail: None,
|
description: Some("parameter".to_string()),
|
||||||
..CompletionItemLabelDetails::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let param_desc = match file_type.as_str() {
|
let param_desc = match file_type.as_str() {
|
||||||
@ -276,7 +340,7 @@ fn get_position_port_param_completion(
|
|||||||
if let Some(primitives_inst) = inst_module.instances.first() {
|
if let Some(primitives_inst) = inst_module.instances.first() {
|
||||||
for port_assignment in &primitives_inst.intstport_assignments {
|
for port_assignment in &primitives_inst.intstport_assignments {
|
||||||
let label_details = CompletionItemLabelDetails {
|
let label_details = CompletionItemLabelDetails {
|
||||||
detail: None,
|
detail: Some("port".to_string()),
|
||||||
..CompletionItemLabelDetails::default()
|
..CompletionItemLabelDetails::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -297,8 +361,8 @@ fn get_position_port_param_completion(
|
|||||||
_ => {
|
_ => {
|
||||||
for port in inst_module.ports {
|
for port in inst_module.ports {
|
||||||
let label_details = CompletionItemLabelDetails {
|
let label_details = CompletionItemLabelDetails {
|
||||||
detail: None,
|
description: Some("port".to_string()),
|
||||||
..CompletionItemLabelDetails::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let port_desc = match file_type.as_str() {
|
let port_desc = match file_type.as_str() {
|
||||||
|
@ -4,9 +4,14 @@ use tower_lsp::lsp_types::*;
|
|||||||
pub fn keyword_completions(keywords: &[(&str, &str)]) -> Vec<CompletionItem> {
|
pub fn keyword_completions(keywords: &[(&str, &str)]) -> Vec<CompletionItem> {
|
||||||
let mut items: Vec<CompletionItem> = Vec::new();
|
let mut items: Vec<CompletionItem> = Vec::new();
|
||||||
for key in keywords {
|
for key in keywords {
|
||||||
|
let label_details = CompletionItemLabelDetails {
|
||||||
|
description: Some("keyword".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
if key.1.is_empty() {
|
if key.1.is_empty() {
|
||||||
items.push(CompletionItem {
|
items.push(CompletionItem {
|
||||||
label: key.0.to_string(),
|
label: key.0.to_string(),
|
||||||
|
label_details: Some(label_details),
|
||||||
kind: Some(CompletionItemKind::KEYWORD),
|
kind: Some(CompletionItemKind::KEYWORD),
|
||||||
..CompletionItem::default()
|
..CompletionItem::default()
|
||||||
});
|
});
|
||||||
@ -14,6 +19,7 @@ pub fn keyword_completions(keywords: &[(&str, &str)]) -> Vec<CompletionItem> {
|
|||||||
items.push(CompletionItem {
|
items.push(CompletionItem {
|
||||||
label: key.0.to_string(),
|
label: key.0.to_string(),
|
||||||
kind: Some(CompletionItemKind::KEYWORD),
|
kind: Some(CompletionItemKind::KEYWORD),
|
||||||
|
label_details: Some(label_details),
|
||||||
insert_text: Some(key.1.to_string()),
|
insert_text: Some(key.1.to_string()),
|
||||||
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
||||||
..CompletionItem::default()
|
..CompletionItem::default()
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use crate::{completion::feature::{get_dot_completion, include_path_completion}, core, hover::feature::make_module_profile_code, server::LspServer, sources::LSPSupport, utils::{get_definition_token, get_language_id_by_uri, is_character_ordered_match}};
|
use crate::{completion::feature::{get_dot_completion, include_path_completion}, core, hover::feature::make_module_profile_code, server::LspServer, sources::LSPSupport, utils::{get_definition_token, get_language_id_by_uri, is_character_ordered_match}};
|
||||||
use log::info;
|
use log::info;
|
||||||
use ropey::{Rope, RopeSlice};
|
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
use super::feature::vlog_directives_completion;
|
use super::feature::{vlog_directives_completion, vlog_directives_completion_without_prefix};
|
||||||
|
|
||||||
|
|
||||||
pub fn completion(server: &LspServer, params: &CompletionParams) -> Option<CompletionResponse> {
|
pub fn completion(server: &LspServer, params: &CompletionParams) -> Option<CompletionResponse> {
|
||||||
@ -62,13 +61,14 @@ pub fn completion(server: &LspServer, params: &CompletionParams) -> Option<Compl
|
|||||||
// 常规触发
|
// 常规触发
|
||||||
CompletionTriggerKind::INVOKED => {
|
CompletionTriggerKind::INVOKED => {
|
||||||
// 1. 先根据 AST 获取上下文补全项
|
// 1. 先根据 AST 获取上下文补全项
|
||||||
|
// 去除如下几种情况:module textmacro
|
||||||
let mut completion_items = 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);
|
||||||
|
|
||||||
// 2. 根据 token 加入关键词
|
// 2. 根据 token 加入关键词
|
||||||
// TODO: 考虑使用前缀树进行优化
|
// TODO: 考虑使用前缀树进行优化
|
||||||
@ -95,6 +95,11 @@ pub fn completion(server: &LspServer, params: &CompletionParams) -> Option<Compl
|
|||||||
make_module_completions(server, &token, &language_id)
|
make_module_completions(server, &token, &language_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 5. 加入宏的自动补全
|
||||||
|
completion_items.items.extend::<Vec<CompletionItem>>(
|
||||||
|
vlog_directives_completion_without_prefix(&token, server)
|
||||||
|
);
|
||||||
|
|
||||||
// 不知道为什么会有重复,去重就完事
|
// 不知道为什么会有重复,去重就完事
|
||||||
completion_items.items.dedup_by_key(|i| i.label.clone());
|
completion_items.items.dedup_by_key(|i| i.label.clone());
|
||||||
|
|
||||||
@ -260,15 +265,19 @@ fn make_module_completions(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let detail = format!("module instantiation ({})", file_type);
|
let detail = format!("module instantiation ({})", file_type);
|
||||||
|
let label_details = CompletionItemLabelDetails {
|
||||||
|
description: Some("module instantiation".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
let item = CompletionItem {
|
let item = CompletionItem {
|
||||||
label: module.name.to_string(),
|
label: module.name.to_string(),
|
||||||
detail: Some(detail),
|
detail: Some(detail),
|
||||||
|
label_details: Some(label_details),
|
||||||
documentation: Some(Documentation::MarkupContent(module_profile)),
|
documentation: Some(Documentation::MarkupContent(module_profile)),
|
||||||
kind: Some(CompletionItemKind::CLASS),
|
kind: Some(CompletionItemKind::CLASS),
|
||||||
insert_text: Some(insert_text),
|
insert_text: Some(insert_text),
|
||||||
// 给模块例化自动补全附上最高权重
|
// 给模块例化自动补全附上最高权重
|
||||||
sort_text: Some("0001".to_string()),
|
sort_text: Some("0".to_string()),
|
||||||
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
||||||
insert_text_mode: Some(InsertTextMode::ADJUST_INDENTATION),
|
insert_text_mode: Some(InsertTextMode::ADJUST_INDENTATION),
|
||||||
..CompletionItem::default()
|
..CompletionItem::default()
|
||||||
|
@ -187,27 +187,27 @@ pub const VLOG_STOP_TASKS: &[(&str, &str, &str)] = &[
|
|||||||
/// Array types tasks IEEE 1364-2005 17.5.1
|
/// Array types tasks IEEE 1364-2005 17.5.1
|
||||||
/// (&str, &str, &str): (label, snippet, description)
|
/// (&str, &str, &str): (label, snippet, description)
|
||||||
pub const VLOG_ARRAY_TYPES_TASKS: &[(&str, &str, &str)] = &[
|
pub const VLOG_ARRAY_TYPES_TASKS: &[(&str, &str, &str)] = &[
|
||||||
("async$and$array", "\\$async$and$array($1, $2);", "对数组进行异步与操作。\n```verilog\n$async$and$array(array1, array2);\n```"),
|
("async$and$array", "\\$async\\$and\\$array($1, $2);", "对数组进行异步与操作。\n```verilog\n$async$and$array(array1, array2);\n```"),
|
||||||
("async$nand$array", "\\$async$nand$array($1, $2);", "对数组进行异步与非操作。\n```verilog\n$async$nand$array(array1, array2);\n```"),
|
("async$nand$array", "\\$async\\$nand\\$array($1, $2);", "对数组进行异步与非操作。\n```verilog\n$async$nand$array(array1, array2);\n```"),
|
||||||
("async$or$array", "\\$async$or$array($1, $2);", "对数组进行异步或操作。\n```verilog\n$async$or$array(array1, array2);\n```"),
|
("async$or$array", "\\$async\\$or\\$array($1, $2);", "对数组进行异步或操作。\n```verilog\n$async$or$array(array1, array2);\n```"),
|
||||||
("async$nor$array", "\\$async$nor$array($1, $2);", "对数组进行异步或非操作。\n```verilog\n$async$nor$array(array1, array2);\n```"),
|
("async$nor$array", "\\$async\\$nor\\$array($1, $2);", "对数组进行异步或非操作。\n```verilog\n$async$nor$array(array1, array2);\n```"),
|
||||||
("sync$and$array", "\\$sync$and$array($1, $2);", "对数组进行同步与操作。\n```verilog\n$sync$and$array(array1, array2);\n```"),
|
("sync$and$array", "\\$sync\\$and\\$array($1, $2);", "对数组进行同步与操作。\n```verilog\n$sync$and$array(array1, array2);\n```"),
|
||||||
("sync$nand$array", "\\$sync$nand$array($1, $2);", "对数组进行同步与非操作。\n```verilog\n$sync$nand$array(array1, array2);\n```"),
|
("sync$nand$array", "\\$sync\\$nand\\$array($1, $2);", "对数组进行同步与非操作。\n```verilog\n$sync$nand$array(array1, array2);\n```"),
|
||||||
("sync$or$array", "\\$sync$or$array($1, $2);", "对数组进行同步或操作。\n```verilog\n$sync$or$array(array1, array2);\n```"),
|
("sync$or$array", "\\$sync\\$or\\$array($1, $2);", "对数组进行同步或操作。\n```verilog\n$sync$or$array(array1, array2);\n```"),
|
||||||
("sync$nor$array", "\\$sync$nor$array($1, $2);", "对数组进行同步或非操作。\n```verilog\n$sync$nor$array(array1, array2);\n```"),
|
("sync$nor$array", "\\$sync\\$nor\\$array($1, $2);", "对数组进行同步或非操作。\n```verilog\n$sync$nor$array(array1, array2);\n```"),
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Array logic types tasks IEEE 1364-2005 17.5.2
|
/// Array logic types tasks IEEE 1364-2005 17.5.2
|
||||||
/// (&str, &str, &str): (label, snippet, description)
|
/// (&str, &str, &str): (label, snippet, description)
|
||||||
pub const VLOG_ARRAY_LOGIC_TYPES_TASKS: &[(&str, &str, &str)] = &[
|
pub const VLOG_ARRAY_LOGIC_TYPES_TASKS: &[(&str, &str, &str)] = &[
|
||||||
("async$and$plane", "\\$async$and$plane($1, $2);", "对数组平面进行异步与操作。\n```verilog\n$async$and$plane(plane1, plane2);\n```"),
|
("async$and$plane", "\\$async\\$and\\$plane($1, $2);", "对数组平面进行异步与操作。\n```verilog\n$async$and$plane(plane1, plane2);\n```"),
|
||||||
("async$nand$plane", "\\$async$nand$plane($1, $2);", "对数组平面进行异步与非操作。\n```verilog\n$async$nand$plane(plane1, plane2);\n```"),
|
("async$nand$plane", "\\$async\\$nand\\$plane($1, $2);", "对数组平面进行异步与非操作。\n```verilog\n$async$nand$plane(plane1, plane2);\n```"),
|
||||||
("async$or$plane", "\\$async$or$plane($1, $2);", "对数组平面进行异步或操作。\n```verilog\n$async$or$plane(plane1, plane2);\n```"),
|
("async$or$plane", "\\$async\\$or\\$plane($1, $2);", "对数组平面进行异步或操作。\n```verilog\n$async$or$plane(plane1, plane2);\n```"),
|
||||||
("async$nor$plane", "\\$async$nor$plane($1, $2);", "对数组平面进行异步或非操作。\n```verilog\n$async$nor$plane(plane1, plane2);\n```"),
|
("async$nor$plane", "\\$async\\$nor\\$plane($1, $2);", "对数组平面进行异步或非操作。\n```verilog\n$async$nor$plane(plane1, plane2);\n```"),
|
||||||
("sync$and$plane", "\\$sync$and$plane($1, $2);", "对数组平面进行同步与操作。\n```verilog\n$sync$and$plane(plane1, plane2);\n```"),
|
("sync$and$plane", "\\$sync\\$and\\$plane($1, $2);", "对数组平面进行同步与操作。\n```verilog\n$sync$and$plane(plane1, plane2);\n```"),
|
||||||
("sync$nand$plane", "\\$sync$nand$plane($1, $2);", "对数组平面进行同步与非操作。\n```verilog\n$sync$nand$plane(plane1, plane2);\n```"),
|
("sync$nand$plane", "\\$sync\\$nand\\$plane($1, $2);", "对数组平面进行同步与非操作。\n```verilog\n$sync$nand$plane(plane1, plane2);\n```"),
|
||||||
("sync$or$plane", "\\$sync$or$plane($1, $2);", "对数组平面进行同步或操作。\n```verilog\n$sync$or$plane(plane1, plane2);\n```"),
|
("sync$or$plane", "\\$sync\\$or\\$plane($1, $2);", "对数组平面进行同步或操作。\n```verilog\n$sync$or$plane(plane1, plane2);\n```"),
|
||||||
("sync$nor$plane", "\\$sync$nor$plane($1, $2);", "对数组平面进行同步或非操作。\n```verilog\n$sync$nor$plane(plane1, plane2);\n```"),
|
("sync$nor$plane", "\\$sync\\$nor\\$plane($1, $2);", "对数组平面进行同步或非操作。\n```verilog\n$sync$nor$plane(plane1, plane2);\n```"),
|
||||||
];
|
];
|
||||||
|
|
||||||
/// $q_initialize tasks IEEE 1364-2005 17.6.1
|
/// $q_initialize tasks IEEE 1364-2005 17.6.1
|
||||||
@ -291,13 +291,13 @@ pub const VLOG_DIST_FUNCTIONS_TASKS: &[(&str, &str, &str)] = &[
|
|||||||
/// $test$plusargs (string) tasks IEEE 1364-2005 17.10.1
|
/// $test$plusargs (string) tasks IEEE 1364-2005 17.10.1
|
||||||
/// (&str, &str, &str): (label, snippet, description)
|
/// (&str, &str, &str): (label, snippet, description)
|
||||||
pub const VLOG_TEST_PLUSARGS_TASKS: &[(&str, &str, &str)] = &[
|
pub const VLOG_TEST_PLUSARGS_TASKS: &[(&str, &str, &str)] = &[
|
||||||
("test$plusargs", "\\$test$plusargs($1);", "检查仿真命令行参数中是否包含指定的字符串。\n```verilog\ninteger result;\nresult = $test$plusargs(\"test_string\");\n```\n\n示例代码:\n```verilog\ninitial begin\n\tif ($test$plusargs(\"HELLO\")) $display(\"Hello argument found.\");\n\tif ($test$plusargs(\"HE\")) $display(\"The HE subset string is detected.\");\n\tif ($test$plusargs(\"H\")) $display(\"Argument starting with H found.\");\n\tif ($test$plusargs(\"HELLO_HERE\")) $display(\"Long argument.\");\n\tif ($test$plusargs(\"HI\")) $display(\"Simple greeting.\");\n\tif ($test$plusargs(\"LO\")) $display(\"Does not match.\");\nend\n```"),
|
("test$plusargs", "\\$test\\$plusargs($1);", "检查仿真命令行参数中是否包含指定的字符串。\n```verilog\ninteger result;\nresult = $test$plusargs(\"test_string\");\n```\n\n示例代码:\n```verilog\ninitial begin\n\tif ($test$plusargs(\"HELLO\")) $display(\"Hello argument found.\");\n\tif ($test$plusargs(\"HE\")) $display(\"The HE subset string is detected.\");\n\tif ($test$plusargs(\"H\")) $display(\"Argument starting with H found.\");\n\tif ($test$plusargs(\"HELLO_HERE\")) $display(\"Long argument.\");\n\tif ($test$plusargs(\"HI\")) $display(\"Simple greeting.\");\n\tif ($test$plusargs(\"LO\")) $display(\"Does not match.\");\nend\n```"),
|
||||||
];
|
];
|
||||||
|
|
||||||
/// $value$plusargs (user_string, variable) tasks IEEE 1364-2005 17.10.2
|
/// $value$plusargs (user_string, variable) tasks IEEE 1364-2005 17.10.2
|
||||||
/// (&str, &str, &str): (label, snippet, description)
|
/// (&str, &str, &str): (label, snippet, description)
|
||||||
pub const VLOG_VALUE_PLUSARGS_TASKS: &[(&str, &str, &str)] = &[
|
pub const VLOG_VALUE_PLUSARGS_TASKS: &[(&str, &str, &str)] = &[
|
||||||
("value$plusargs", "\\$value$plusargs($1, $2);", "从仿真命令行参数中提取值并赋给变量。\n```verilog\ninteger result;\nresult = $value$plusargs(\"test_string=\", value);\n```\n\n示例代码:\n```verilog\n`define STRING reg [1024 * 8:1]\nmodule goodtasks;\n\t`STRING str;\n\tinteger int;\n\treg [31:0] vect;\n\treal realvar;\n\tinitial\n\tbegin\n\t\tif ($value$plusargs(\"TEST=%d\", int))\n\t\t\t$display(\"value was %d\", int);\n\t\telse\n\t\t\t$display(\"+TEST= not found\");\n\t\t#100 $finish;\n\tend\nendmodule\n```"),
|
("value$plusargs", "\\$value\\$plusargs($1, $2);", "从仿真命令行参数中提取值并赋给变量。\n```verilog\ninteger result;\nresult = $value$plusargs(\"test_string=\", value);\n```\n\n示例代码:\n```verilog\n`define STRING reg [1024 * 8:1]\nmodule goodtasks;\n\t`STRING str;\n\tinteger int;\n\treg [31:0] vect;\n\treal realvar;\n\tinitial\n\tbegin\n\t\tif ($value$plusargs(\"TEST=%d\", int))\n\t\t\t$display(\"value was %d\", int);\n\t\telse\n\t\t\t$display(\"+TEST= not found\");\n\t\t#100 $finish;\n\tend\nendmodule\n```"),
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Integer math functions tasks IEEE 1364-2005 17.11.1
|
/// Integer math functions tasks IEEE 1364-2005 17.11.1
|
||||||
@ -449,9 +449,14 @@ fn update_task_completions(
|
|||||||
) {
|
) {
|
||||||
for (label, snippet_code, description) in tasks {
|
for (label, snippet_code, description) in tasks {
|
||||||
let function_profile = make_function_profile(section, description);
|
let function_profile = make_function_profile(section, description);
|
||||||
|
let label_details = CompletionItemLabelDetails {
|
||||||
|
description: Some("system task".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
items.push(CompletionItem {
|
items.push(CompletionItem {
|
||||||
label: label.to_string(),
|
label: label.to_string(),
|
||||||
detail: Some(section.to_string()),
|
detail: Some(section.to_string()),
|
||||||
|
label_details: Some(label_details),
|
||||||
documentation: Some(Documentation::MarkupContent(function_profile)),
|
documentation: Some(Documentation::MarkupContent(function_profile)),
|
||||||
kind: Some(CompletionItemKind::FUNCTION),
|
kind: Some(CompletionItemKind::FUNCTION),
|
||||||
insert_text: Some(snippet_code.to_string()),
|
insert_text: Some(snippet_code.to_string()),
|
||||||
|
@ -262,7 +262,7 @@ fn make_module_completions(
|
|||||||
kind: Some(CompletionItemKind::CLASS),
|
kind: Some(CompletionItemKind::CLASS),
|
||||||
insert_text: Some(insert_text),
|
insert_text: Some(insert_text),
|
||||||
// 给模块例化自动补全附上最高权重
|
// 给模块例化自动补全附上最高权重
|
||||||
sort_text: Some("0001".to_string()),
|
sort_text: Some("0".to_string()),
|
||||||
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
||||||
insert_text_mode: Some(InsertTextMode::ADJUST_INDENTATION),
|
insert_text_mode: Some(InsertTextMode::ADJUST_INDENTATION),
|
||||||
..CompletionItem::default()
|
..CompletionItem::default()
|
||||||
|
@ -4,7 +4,7 @@ use ropey::Rope;
|
|||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
use vhdl_lang::Project;
|
use vhdl_lang::Project;
|
||||||
|
|
||||||
use crate::sources::LSPSupport;
|
use crate::{sources::LSPSupport, utils::is_character_ordered_match};
|
||||||
|
|
||||||
/// cleanup the text of a definition so it can be included in completions
|
/// cleanup the text of a definition so it can be included in completions
|
||||||
pub fn clean_type_str(type_str: &str, ident: &str) -> String {
|
pub fn clean_type_str(type_str: &str, ident: &str) -> String {
|
||||||
@ -122,14 +122,31 @@ pub trait Scope: std::fmt::Debug + Definition + Sync + Send {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自动补全时,忽略大小写
|
// let completion_idents: Vec<String> = completions.iter().map(|x| x.label.clone()).collect();
|
||||||
let lower_case_token = token.to_lowercase();
|
|
||||||
let completion_idents: Vec<String> = completions.iter().map(|x| x.label.clone()).collect();
|
|
||||||
|
|
||||||
// 寻找前缀相同的 symbol
|
// 寻找前缀相同的 symbol
|
||||||
for def in self.defs() {
|
// 这里面并没有 macro
|
||||||
if !completion_idents.contains(&def.ident()) && def.ident().to_lowercase().starts_with(&lower_case_token) {
|
for symbol in self.defs() {
|
||||||
completions.push(def.completion());
|
// 此处的去重会在外部完成
|
||||||
|
let symbol_name = symbol.ident();
|
||||||
|
// 此处仍然会给出 module 的补全,但是此处的只是名字的补全,而不是自动例化
|
||||||
|
match &symbol.def_type() {
|
||||||
|
DefinitionType::Port => {},
|
||||||
|
DefinitionType::Net => {},
|
||||||
|
DefinitionType::Macro => {
|
||||||
|
// 对于 TextMacro 类型的,因为是全局属性的,不进行补全
|
||||||
|
// 对于它的补全请参考 vlog_directives_completion & vlog_directives_completion_without_prefix
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
DefinitionType::Data => {},
|
||||||
|
DefinitionType::Modport => {},
|
||||||
|
DefinitionType::Subroutine => {},
|
||||||
|
DefinitionType::ModuleInstantiation => {},
|
||||||
|
DefinitionType::GenericScope => {},
|
||||||
|
DefinitionType::Class => {},
|
||||||
|
};
|
||||||
|
if is_character_ordered_match(token, &symbol_name) {
|
||||||
|
completions.push(symbol.completion());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 寻找前缀相同的 scope
|
// 寻找前缀相同的 scope
|
||||||
@ -142,42 +159,6 @@ pub trait Scope: std::fmt::Debug + Definition + Sync + Send {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// return a dot completion from the scope tree, this function should be called on the global
|
|
||||||
/// scope
|
|
||||||
fn get_dot_completion(
|
|
||||||
&self,
|
|
||||||
token: &str,
|
|
||||||
byte_idx: usize,
|
|
||||||
url: &Url,
|
|
||||||
scope_tree: &GenericScope,
|
|
||||||
) -> Vec<CompletionItem> {
|
|
||||||
// first we need to go down the scope tree, to the scope the user is invoking a completion
|
|
||||||
// in
|
|
||||||
for scope in self.scopes() {
|
|
||||||
if &scope.url() == url && scope.start() <= byte_idx && byte_idx <= scope.end() {
|
|
||||||
let result = scope.get_dot_completion(token, byte_idx, url, scope_tree);
|
|
||||||
if !result.is_empty() {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// now that we are in the users scope, we can attempt to find the relevant definition
|
|
||||||
// we proceed back upwards through the scope tree, and if a definition matches our token,
|
|
||||||
// we invoke dot completion on that definition and pass it the syntax tree
|
|
||||||
for def in self.defs() {
|
|
||||||
if def.starts_with(token) {
|
|
||||||
return def.dot_completion(scope_tree);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for scope in self.scopes() {
|
|
||||||
if scope.starts_with(token) {
|
|
||||||
return scope.dot_completion(scope_tree);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// 根据输入的 token,计算出这个 token 在 scope 中的定义
|
/// 根据输入的 token,计算出这个 token 在 scope 中的定义
|
||||||
/// 比如输入 clock,则返回 clock 这个变量在哪里被定义,没有则返回 None
|
/// 比如输入 clock,则返回 clock 这个变量在哪里被定义,没有则返回 None
|
||||||
/// - `token`: 需要查找定义的完整的单词
|
/// - `token`: 需要查找定义的完整的单词
|
||||||
@ -360,9 +341,14 @@ impl Definition for PortDec {
|
|||||||
self.ident.starts_with(token)
|
self.ident.starts_with(token)
|
||||||
}
|
}
|
||||||
fn completion(&self) -> CompletionItem {
|
fn completion(&self) -> CompletionItem {
|
||||||
|
let label_details = CompletionItemLabelDetails {
|
||||||
|
description: Some("port desciption".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: self.ident.clone(),
|
label: self.ident.clone(),
|
||||||
detail: Some(clean_type_str(&self.type_str, &self.ident)),
|
detail: Some(clean_type_str(&self.type_str, &self.ident)),
|
||||||
|
label_details: Some(label_details),
|
||||||
kind: Some(self.completion_kind),
|
kind: Some(self.completion_kind),
|
||||||
..CompletionItem::default()
|
..CompletionItem::default()
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use super::common::*;
|
use super::common::*;
|
||||||
use super::match_definitions;
|
use super::match_definitions;
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
use sv_parser::*;
|
use sv_parser::*;
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
|
@ -71,6 +71,9 @@ impl AbstractLinterConfiguration for VivadoConfiguration {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// vivado 比较特殊,需要先分析出当前文件用了哪些其他文件的宏,然后把那部分宏所在的文件加入编译参数中
|
||||||
|
|
||||||
|
|
||||||
let child = Command::new(&invoke_name)
|
let child = Command::new(&invoke_name)
|
||||||
.current_dir(cwd)
|
.current_dir(cwd)
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
@ -184,35 +187,9 @@ fn find_vivado_suitable_range(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// 过滤 vivado 给出的一些报错
|
|
||||||
fn filter_diagnostic_result(
|
|
||||||
diagnostics: Vec<Diagnostic>,
|
|
||||||
server: &LspServer,
|
|
||||||
language_id: &str
|
|
||||||
) -> Vec<Diagnostic> {
|
|
||||||
match language_id {
|
|
||||||
// vhdl
|
|
||||||
"vhdl" => {
|
|
||||||
filter_xvhdl_diagnostic_result(diagnostics, server)
|
|
||||||
}
|
|
||||||
// vlog & svlog
|
|
||||||
_ => {
|
|
||||||
filter_xvlog_diagnostic_result(diagnostics, server)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn filter_xvhdl_diagnostic_result(
|
|
||||||
diagnostics: Vec<Diagnostic>,
|
|
||||||
#[allow(unused)]
|
|
||||||
server: &LspServer,
|
|
||||||
) -> Vec<Diagnostic> {
|
|
||||||
diagnostics
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 判断是否为类似于 xxx ignored 的错误
|
/// 判断是否为类似于 xxx ignored 的错误
|
||||||
/// ERROR: [VRFC 10-8530] module 'main' is ignored due to previous errors [/home/dide/project/Digital-Test/Digital-macro/user/src/main.v:1]
|
/// ERROR: [VRFC 10-8530] module 'main' is ignored due to previous errors [/home/dide/project/Digital-Test/Digital-macro/user/src/main.v:1]
|
||||||
|
#[allow(unused)]
|
||||||
fn is_ignore_type(diag: &Diagnostic) -> bool {
|
fn is_ignore_type(diag: &Diagnostic) -> bool {
|
||||||
// 获取 vrfc 编码
|
// 获取 vrfc 编码
|
||||||
let vrfc_code = if let Some(NumberOrString::String(code)) = &diag.code {
|
let vrfc_code = if let Some(NumberOrString::String(code)) = &diag.code {
|
||||||
@ -231,19 +208,3 @@ fn is_ignore_type(diag: &Diagnostic) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_xvlog_diagnostic_result(
|
|
||||||
diagnostics: Vec<Diagnostic>,
|
|
||||||
#[allow(unused)]
|
|
||||||
server: &LspServer,
|
|
||||||
) -> Vec<Diagnostic> {
|
|
||||||
// 第一级过滤, 去除所有的 ignore 类型的
|
|
||||||
let diagnostics = diagnostics.into_iter().filter(|diag| !is_ignore_type(diag)).collect();
|
|
||||||
|
|
||||||
|
|
||||||
// 第二级过滤, 对于 xxx not found, 需要先根据 fast 查看是否存在, 如果存在,还需要把同一行的某些特定错误一并去除
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
diagnostics
|
|
||||||
}
|
|
@ -465,7 +465,6 @@ impl Sources {
|
|||||||
byte_idx: usize,
|
byte_idx: usize,
|
||||||
url: &Url,
|
url: &Url,
|
||||||
) -> Option<CompletionList> {
|
) -> Option<CompletionList> {
|
||||||
debug!("retrieving identifier completion for token: {}", &token);
|
|
||||||
Some(CompletionList {
|
Some(CompletionList {
|
||||||
is_incomplete: false,
|
is_incomplete: false,
|
||||||
items: self
|
items: self
|
||||||
@ -477,22 +476,6 @@ impl Sources {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// compute dot completions
|
|
||||||
pub fn get_dot_completions(
|
|
||||||
&self,
|
|
||||||
token: &str,
|
|
||||||
byte_idx: usize,
|
|
||||||
url: &Url,
|
|
||||||
) -> Option<CompletionList> {
|
|
||||||
debug!("retrieving dot completion for token: {}", &token);
|
|
||||||
let tree = self.scope_tree.read().ok()?;
|
|
||||||
Some(CompletionList {
|
|
||||||
is_incomplete: false,
|
|
||||||
items: tree
|
|
||||||
.as_ref()?
|
|
||||||
.get_dot_completion(token, byte_idx, url, tree.as_ref()?),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn get_lsp_configuration_string_value(&self, name: &str) -> Option<String> {
|
pub fn get_lsp_configuration_string_value(&self, name: &str) -> Option<String> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user