实现 endmodule 的 inlay hints
This commit is contained in:
parent
1142aa324f
commit
9688a330bf
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1459,6 +1459,7 @@ dependencies = [
|
|||||||
name = "sv-parser-pp"
|
name = "sv-parser-pp"
|
||||||
version = "0.13.3"
|
version = "0.13.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"log",
|
||||||
"nom",
|
"nom",
|
||||||
"nom-greedyerror",
|
"nom-greedyerror",
|
||||||
"sv-parser-error",
|
"sv-parser-error",
|
||||||
|
@ -227,7 +227,9 @@ endmodule
|
|||||||
// resetall 也常用于开始
|
// resetall 也常用于开始
|
||||||
// 1834-2005中指出,建议的用法是将 `resetall 放在每个源文本文件的开头,后面紧跟着文件中所需的指令。
|
// 1834-2005中指出,建议的用法是将 `resetall 放在每个源文本文件的开头,后面紧跟着文件中所需的指令。
|
||||||
// 通常可用于源文本开头,避免该文件受到其他文件代码的影响。或放置在末尾,避免编译器设置的进一步传递
|
// 通常可用于源文本开头,避免该文件受到其他文件代码的影响。或放置在末尾,避免编译器设置的进一步传递
|
||||||
r#"`resetall` 用于重置所有编译器设置为默认值。它通常用于在模块或文件的末尾清除所有编译器设置,以确保后续代码不受之前设置的影响。
|
r#"`resetall` 用于重置所有编译器设置为默认值。通常可用于源文本开头,避免该文件受到其他文件代码的影响。或放置在末尾,避免编译器设置的进一步传递。
|
||||||
|
|
||||||
|
1834-2005中指出,建议的用法是将 `resetall 放在每个源文本文件的开头,后面紧跟着文件中所需的指令。
|
||||||
|
|
||||||
```verilog
|
```verilog
|
||||||
`timescale 1ns/1ps // 设置时间单位和精度
|
`timescale 1ns/1ps // 设置时间单位和精度
|
||||||
@ -273,7 +275,7 @@ endmodule
|
|||||||
// 也即是,仿真时间单位必须大于等于时间精度
|
// 也即是,仿真时间单位必须大于等于时间精度
|
||||||
// `timescale 1ns/1ns不会报错,但是`timescale 1ps/1ns会报错
|
// `timescale 1ns/1ns不会报错,但是`timescale 1ps/1ns会报错
|
||||||
// [Synth 8-522] parsing error: error in timescale or timeprecision statement. <timeprecision> must be at least as precise as <timeunit>
|
// [Synth 8-522] parsing error: error in timescale or timeprecision statement. <timeprecision> must be at least as precise as <timeunit>
|
||||||
r#"设置时间单位和精度,设置时间单位和精度,格式为 <code> `timescale </code> 仿真时间单位/时间精度,<code>仿真时间单位</code> 必须大于 <code>时间精度</code>,例如
|
r#"设置时间单位和精度,设置时间单位和精度,格式为 <code> `timescale </code> 仿真时间单位/时间精度,<code>仿真时间单位</code> 必须大于等于 <code>时间精度</code>,例如
|
||||||
```verilog
|
```verilog
|
||||||
`timescale 1ns/1ps
|
`timescale 1ns/1ps
|
||||||
|
|
||||||
@ -343,7 +345,7 @@ r#"`nounconnected_drive` 和 `unconnected_drive` 是配合使用的编译指令
|
|||||||
"begin_keywords",
|
"begin_keywords",
|
||||||
"`begin_keywords\n$1\n`end_keywords ",
|
"`begin_keywords\n$1\n`end_keywords ",
|
||||||
// begin_keywords并不是指定Verilog的编译版本,而是指定使用的Verilog关键字版本
|
// begin_keywords并不是指定Verilog的编译版本,而是指定使用的Verilog关键字版本
|
||||||
r#"`begin_keywords` 和 `end_keywords` 是用于指定 Verilog 语言版本的编译指令。它们允许设计者在同一个文件中使用不同版本的 Verilog 语法,从而实现兼容性或逐步迁移到新版本。
|
r#"`begin_keywords` 和 `end_keywords` 是用于指定 Verilog 关键字版本的编译指令。它们允许设计者在同一个文件中使用不同版本的 Verilog 关键字语法,从而实现兼容性或逐步迁移到新版本。
|
||||||
|
|
||||||
`begin_keywords` 支持以下 Verilog 版本:
|
`begin_keywords` 支持以下 Verilog 版本:
|
||||||
|
|
||||||
|
@ -76,8 +76,8 @@ pub fn sv_parser(path: &str) -> Option<FastHdlparam> {
|
|||||||
// println!("result: {result:?}");
|
// println!("result: {result:?}");
|
||||||
|
|
||||||
if let Some(syntax_tree) = result {
|
if let Some(syntax_tree) = result {
|
||||||
if let Ok(hdlparam) = make_fast_from_syntaxtree(&syntax_tree, &path) {
|
if let Ok(fast) = make_fast_from_syntaxtree(&syntax_tree, &path) {
|
||||||
return Some(hdlparam);
|
return Some(fast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ pub fn make_fast_from_syntaxtree(
|
|||||||
// 对不同操作系统文件路径的支持
|
// 对不同操作系统文件路径的支持
|
||||||
let path = to_escape_path(path);
|
let path = to_escape_path(path);
|
||||||
|
|
||||||
let mut hdlparam = FastHdlparam {
|
let mut fast: FastHdlparam = FastHdlparam {
|
||||||
fast_macro: Macro {
|
fast_macro: Macro {
|
||||||
defines: Vec::new(),
|
defines: Vec::new(),
|
||||||
errors: Vec::new(),
|
errors: Vec::new(),
|
||||||
@ -103,10 +103,11 @@ pub fn make_fast_from_syntaxtree(
|
|||||||
};
|
};
|
||||||
let mut ansi_port_last_dir = "";
|
let mut ansi_port_last_dir = "";
|
||||||
|
|
||||||
// println!("{:?}", syntax_tree);
|
|
||||||
// &SyntaxTree is iterable
|
// &SyntaxTree is iterable
|
||||||
let doc = Rope::from_str(syntax_tree.text.text());
|
let doc = Rope::from_str(syntax_tree.text.text());
|
||||||
|
|
||||||
|
// 上一个 module 可以在 fast 的 content 的最后一个中找到
|
||||||
|
|
||||||
for node in syntax_tree {
|
for node in syntax_tree {
|
||||||
match node {
|
match node {
|
||||||
RefNode::TextMacroDefinition(x) => {
|
RefNode::TextMacroDefinition(x) => {
|
||||||
@ -148,20 +149,20 @@ pub fn make_fast_from_syntaxtree(
|
|||||||
};
|
};
|
||||||
let define_range = Range { start: start_pos, end: end_pos };
|
let define_range = Range { start: start_pos, end: end_pos };
|
||||||
|
|
||||||
hdlparam.add_define(name, replacement, define_range, params_vec);
|
fast.add_define(name, replacement, define_range, params_vec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RefNode::ModuleDeclaration(x) => {
|
RefNode::ModuleDeclaration(x) => {
|
||||||
let start_keyword = unwrap_node!(x, Keyword).unwrap();
|
let start_keyword = unwrap_node!(x, Keyword).unwrap();
|
||||||
let start_keyword = get_identifier(start_keyword).unwrap();
|
let start_keyword = get_identifier(start_keyword).unwrap();
|
||||||
let start_pos = get_position(&doc, start_keyword, 0);
|
let start_pos = get_position(&doc, start_keyword, 0);
|
||||||
let module_range = get_pp_range(&doc, RefNode::ModuleDeclaration(x));
|
let module_range = Range { start: start_pos.clone(), end: start_pos };
|
||||||
let module_range = Range { start: start_pos, end: module_range.end };
|
|
||||||
|
|
||||||
let id = unwrap_node!(x, ModuleIdentifier).unwrap();
|
let id = unwrap_node!(x, ModuleIdentifier).unwrap();
|
||||||
let id = get_identifier(id).unwrap();
|
let id = get_identifier(id).unwrap();
|
||||||
let name = syntax_tree.get_str(&id).unwrap();
|
let name = syntax_tree.get_str(&id).unwrap();
|
||||||
hdlparam.new_module(name, module_range);
|
|
||||||
|
fast.new_module(name, module_range);
|
||||||
}
|
}
|
||||||
RefNode::ParameterDeclaration(param_dec) => {
|
RefNode::ParameterDeclaration(param_dec) => {
|
||||||
let mut event_iter = param_dec.into_iter().event();
|
let mut event_iter = param_dec.into_iter().event();
|
||||||
@ -192,7 +193,7 @@ pub fn make_fast_from_syntaxtree(
|
|||||||
};
|
};
|
||||||
let end_pos = get_position(&doc, loc.clone(), loc.len);
|
let end_pos = get_position(&doc, loc.clone(), loc.len);
|
||||||
let param_range = Range { start: start_pos, end: end_pos };
|
let param_range = Range { start: start_pos, end: end_pos };
|
||||||
hdlparam.add_parameter(name, net_type, init, param_range);
|
fast.add_parameter(name, net_type, init, param_range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
@ -235,7 +236,7 @@ pub fn make_fast_from_syntaxtree(
|
|||||||
let name = syntax_tree.get_str(&id).unwrap();
|
let name = syntax_tree.get_str(&id).unwrap();
|
||||||
let port_range = Range { start: start_pos.clone(), end: get_position(&doc, id, id.len) };
|
let port_range = Range { start: start_pos.clone(), end: get_position(&doc, id, id.len) };
|
||||||
|
|
||||||
hdlparam.add_port(name, dir_type, net_type, width.as_str(), port_range);
|
fast.add_port(name, dir_type, net_type, width.as_str(), port_range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,7 +285,7 @@ pub fn make_fast_from_syntaxtree(
|
|||||||
_ => "1".to_string()
|
_ => "1".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
hdlparam.add_port(name, ansi_port_last_dir, net_type, width.as_str(), port_range);
|
fast.add_port(name, ansi_port_last_dir, net_type, width.as_str(), port_range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RefNode::ModuleInstantiation(x) => {
|
RefNode::ModuleInstantiation(x) => {
|
||||||
@ -316,7 +317,7 @@ pub fn make_fast_from_syntaxtree(
|
|||||||
let inst_port_assignments = get_instance_ports(&syntax_tree, &doc, hier_node.clone());
|
let inst_port_assignments = get_instance_ports(&syntax_tree, &doc, hier_node.clone());
|
||||||
let port_range = get_pp_range(&doc, hier_node).to_option();
|
let port_range = get_pp_range(&doc, hier_node).to_option();
|
||||||
|
|
||||||
hdlparam.add_instance(
|
fast.add_instance(
|
||||||
name, inst_type, inst_range,
|
name, inst_type, inst_range,
|
||||||
param_range, inst_param_assignments,
|
param_range, inst_param_assignments,
|
||||||
port_range, inst_port_assignments
|
port_range, inst_port_assignments
|
||||||
@ -342,7 +343,7 @@ pub fn make_fast_from_syntaxtree(
|
|||||||
let inst_port_assignments = get_instance_ports(&syntax_tree, &doc, gate_node.clone());
|
let inst_port_assignments = get_instance_ports(&syntax_tree, &doc, gate_node.clone());
|
||||||
let port_range = get_pp_range(&doc, gate_node).to_option();
|
let port_range = get_pp_range(&doc, gate_node).to_option();
|
||||||
|
|
||||||
hdlparam.add_instance(
|
fast.add_instance(
|
||||||
name, inst_type, inst_range,
|
name, inst_type, inst_range,
|
||||||
param_range, Vec::<InstParameter>::new(),
|
param_range, Vec::<InstParameter>::new(),
|
||||||
port_range, inst_port_assignments
|
port_range, inst_port_assignments
|
||||||
@ -351,13 +352,31 @@ pub fn make_fast_from_syntaxtree(
|
|||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RefNode::Keyword(x) => {
|
||||||
|
let id = x.nodes.0;
|
||||||
|
let name = syntax_tree.get_str(&id).unwrap();
|
||||||
|
let pos = get_position(&doc, id, name.len());
|
||||||
|
|
||||||
|
// 根据关键词进行特殊处理
|
||||||
|
// 比如找到 endmodule 的位置来确定目前的这个 module 的 end
|
||||||
|
match name {
|
||||||
|
"endmodule" => {
|
||||||
|
// 尝试获取 content 最后一个元素的可变引用,该引用如果存在,说明已经创建了一个 module
|
||||||
|
if let Some(last_module) = fast.content.last_mut() {
|
||||||
|
last_module.range.end.line = pos.line;
|
||||||
|
last_module.range.end.character = pos.line;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update_module_range(&path, &mut hdlparam);
|
// update_module_range(&path, &mut hdlparam);
|
||||||
|
|
||||||
Ok(hdlparam)
|
Ok(fast)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取 port 或者 param 的 range
|
// 获取 port 或者 param 的 range
|
||||||
@ -705,7 +724,7 @@ fn get_includes(path: &PathBuf) -> Vec<crate::core::hdlparam::Include> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn update_module_range(path: &PathBuf, hdlparam: &mut FastHdlparam) {
|
fn update_module_range(path: &PathBuf, fast: &mut FastHdlparam) {
|
||||||
let file = File::open(path).unwrap();
|
let file = File::open(path).unwrap();
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
|
|
||||||
@ -725,7 +744,7 @@ fn update_module_range(path: &PathBuf, hdlparam: &mut FastHdlparam) {
|
|||||||
module_stack.push(module_name.clone());
|
module_stack.push(module_name.clone());
|
||||||
} else if re_endmodule.is_match(&line) {
|
} else if re_endmodule.is_match(&line) {
|
||||||
if let Some(module_name) = module_stack.pop() {
|
if let Some(module_name) = module_stack.pop() {
|
||||||
hdlparam.update_module_range(&module_name, (line_number + 1) as u32, current_offset as u32);
|
fast.update_module_range(&module_name, (line_number + 1) as u32, current_offset as u32);
|
||||||
// println!("Module {} ends.", module_name);
|
// println!("Module {} ends.", module_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,16 +33,26 @@ pub fn inlay_hint(server: &LspServer, params: &InlayHintParams) -> Option<Vec<In
|
|||||||
for module in &fast.content {
|
for module in &fast.content {
|
||||||
for instance in &module.instances {
|
for instance in &module.instances {
|
||||||
// 根据在可见视图外面的 range 就不管了
|
// 根据在可见视图外面的 range 就不管了
|
||||||
if is_visible_range(&instance.instparams, &visible_range) {
|
if let Some(range) = &instance.instparams {
|
||||||
hints.extend(make_instparam_hints(server, params, instance, rope));
|
if is_visible_range(&range, &visible_range) {
|
||||||
|
hints.extend(make_instparam_hints(server, params, instance, rope));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(range) = &instance.instports {
|
||||||
if is_visible_range(&instance.instports, &visible_range) {
|
if is_visible_range(range, &visible_range) {
|
||||||
hints.extend(make_instport_hints(server, params, instance, rope));
|
hints.extend(make_instport_hints(server, params, instance, rope));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 在 endmodule 后面添加 module xxx
|
||||||
|
if is_visible_range(&module.range, &visible_range) {
|
||||||
|
hints.extend(make_endmodule_hints(module));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return Some(hints);
|
return Some(hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,16 +60,46 @@ pub fn inlay_hint(server: &LspServer, params: &InlayHintParams) -> Option<Vec<In
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_visible_range(
|
fn is_visible_range(
|
||||||
target_range: &Option<core::hdlparam::Range>,
|
target_range: &core::hdlparam::Range,
|
||||||
visible_range: &core::hdlparam::Range
|
visible_range: &core::hdlparam::Range
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Some(target_range) = target_range {
|
if target_range.before(visible_range) || target_range.after(visible_range) {
|
||||||
if target_range.before(visible_range) || target_range.after(visible_range) {
|
false
|
||||||
return false;
|
} else {
|
||||||
}
|
true
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
false
|
}
|
||||||
|
|
||||||
|
fn make_endmodule_hints(
|
||||||
|
module: &core::hdlparam::Module
|
||||||
|
) -> Vec<InlayHint> {
|
||||||
|
let mut hints = Vec::<InlayHint>::new();
|
||||||
|
let end_pos = &module.range.end;
|
||||||
|
let start_pos = &module.range.start;
|
||||||
|
if end_pos.character == start_pos.character && end_pos.line == start_pos.line {
|
||||||
|
// 说明解析器没有找到 endmodule
|
||||||
|
return hints;
|
||||||
|
}
|
||||||
|
|
||||||
|
let module_desc = MarkupContent {
|
||||||
|
kind: MarkupKind::Markdown,
|
||||||
|
value: format!("module {}", module.name)
|
||||||
|
};
|
||||||
|
|
||||||
|
let hint = InlayHint {
|
||||||
|
position: end_pos.to_lsp_position(),
|
||||||
|
label: InlayHintLabel::String(format!("module {}", module.name)),
|
||||||
|
padding_left: Some(true),
|
||||||
|
padding_right: Some(true),
|
||||||
|
kind: Some(InlayHintKind::PARAMETER),
|
||||||
|
text_edits: None,
|
||||||
|
tooltip: Some(InlayHintTooltip::MarkupContent(module_desc)),
|
||||||
|
data: None
|
||||||
|
};
|
||||||
|
|
||||||
|
hints.push(hint);
|
||||||
|
|
||||||
|
hints
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_instparam_hints(
|
fn make_instparam_hints(
|
||||||
@ -112,6 +152,7 @@ fn find_instport_inlay_hints_position(
|
|||||||
|
|
||||||
fn make_instport_hints(
|
fn make_instport_hints(
|
||||||
server: &LspServer,
|
server: &LspServer,
|
||||||
|
#[allow(unused)]
|
||||||
params: &InlayHintParams,
|
params: &InlayHintParams,
|
||||||
instance: &core::hdlparam::Instance,
|
instance: &core::hdlparam::Instance,
|
||||||
rope: &Rope
|
rope: &Rope
|
||||||
|
Loading…
x
Reference in New Issue
Block a user