Compare commits
11 Commits
7398d742c9
...
2dd7f98d5f
Author | SHA1 | Date | |
---|---|---|---|
2dd7f98d5f | |||
9f50823429 | |||
![]() |
23816af899 | ||
![]() |
e31f8ec8ac | ||
![]() |
0c0ee48ae5 | ||
![]() |
3303b65c3f | ||
82a21ccf34 | |||
8d733112c4 | |||
4bde6263a3 | |||
7f5ed156a5 | |||
![]() |
314540c7e6 |
@ -11,7 +11,7 @@ dirs-next = "2.0"
|
|||||||
bincode = "1.3"
|
bincode = "1.3"
|
||||||
percent-encoding = "2.1.0"
|
percent-encoding = "2.1.0"
|
||||||
log = "0.4.19"
|
log = "0.4.19"
|
||||||
tower-lsp = "0.20.0"
|
tower-lsp = { version = "0.20.0", features = ["proposed"]}
|
||||||
flexi_logger = "0.29.0"
|
flexi_logger = "0.29.0"
|
||||||
ropey = "1.6.0"
|
ropey = "1.6.0"
|
||||||
tokio = { version = "1.29.1", features = ["macros", "io-std", "rt-multi-thread"] }
|
tokio = { version = "1.29.1", features = ["macros", "io-std", "rt-multi-thread"] }
|
||||||
|
@ -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,6 +55,7 @@ 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,
|
||||||
@ -61,6 +63,8 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<Compl
|
|||||||
&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>>(
|
||||||
server.key_comps
|
server.key_comps
|
||||||
@ -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,113 @@ 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 (path_string, 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 path_uri = Url::from_file_path(path_string.to_string()).unwrap().to_string();
|
||||||
|
let def_row = module.range.start.line;
|
||||||
|
let def_col = module.range.start.character;
|
||||||
|
let define_info = 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 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),
|
||||||
|
// 给模块例化自动补全附上最高权重
|
||||||
|
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
|
||||||
|
}
|
@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use tower_lsp::lsp_types::Position as LspPosition;
|
use tower_lsp::lsp_types::Position as LspPosition;
|
||||||
use tower_lsp::lsp_types::Range as LspRange;
|
use tower_lsp::lsp_types::Range as LspRange;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, PartialEq, Deserialize)]
|
#[derive(Debug, Clone, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize)]
|
||||||
pub struct Position {
|
pub struct Position {
|
||||||
pub line: u32,
|
pub line: u32,
|
||||||
pub character: u32
|
pub character: u32
|
||||||
@ -17,9 +17,13 @@ impl Position {
|
|||||||
pub fn to_lsp_position(&self) -> LspPosition {
|
pub fn to_lsp_position(&self) -> LspPosition {
|
||||||
LspPosition { line: self.line, character: self.character }
|
LspPosition { line: self.line, character: self.character }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_lsp_position(pos: &LspPosition) -> Position {
|
||||||
|
Position { line: pos.line, character: pos.character }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, PartialEq, Deserialize)]
|
#[derive(Debug, Clone, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize)]
|
||||||
pub struct Range {
|
pub struct Range {
|
||||||
pub start: Position,
|
pub start: Position,
|
||||||
pub end: Position
|
pub end: Position
|
||||||
@ -34,11 +38,39 @@ impl Range {
|
|||||||
LspRange::new(start_pos, end_pos)
|
LspRange::new(start_pos, end_pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn from_lsp_range(range: &LspRange) -> Range {
|
||||||
|
Range {
|
||||||
|
start: Position {
|
||||||
|
line: range.start.line,
|
||||||
|
character: range.start.character
|
||||||
|
},
|
||||||
|
end: Position {
|
||||||
|
line: range.end.line,
|
||||||
|
character: range.end.character
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 判断输入的 position 是否在当前 range 内
|
/// 判断输入的 position 是否在当前 range 内
|
||||||
pub fn contains(&self, postion: &LspPosition) -> bool {
|
pub fn contains(&self, postion: &LspPosition) -> bool {
|
||||||
compare_pos(&self.start.to_lsp_position(), postion) != 1 && compare_pos(postion, &self.end.to_lsp_position()) != 1
|
compare_pos(&self.start.to_lsp_position(), postion) != 1 && compare_pos(postion, &self.end.to_lsp_position()) != 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn before(&self, range: &Range) -> bool {
|
||||||
|
let current_pos = &self.end.to_lsp_position();
|
||||||
|
let target_pos = &range.start.to_lsp_position();
|
||||||
|
compare_pos(current_pos, target_pos) != 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn after(&self, range: &Range) -> bool {
|
||||||
|
let current_pos = &self.start.to_lsp_position();
|
||||||
|
let target_pos = &range.end.to_lsp_position();
|
||||||
|
compare_pos(current_pos, target_pos) != -1
|
||||||
|
}
|
||||||
|
|
||||||
/// 对所有的 line 或者 所有的 character 进行偏移操作
|
/// 对所有的 line 或者 所有的 character 进行偏移操作
|
||||||
pub fn affine(&mut self, line_offset: i32, character_offset: i32) -> &Range {
|
pub fn affine(&mut self, line_offset: i32, character_offset: i32) -> &Range {
|
||||||
if line_offset > 0 {
|
if line_offset > 0 {
|
||||||
@ -59,8 +91,24 @@ impl Range {
|
|||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.start.line == 0 && self.start.character == 0 && self.end.line == 0 && self.end.character == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_option(&self) -> Option<Range> {
|
||||||
|
if self.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 比较两个 pos 的位置关系
|
||||||
|
/// 1:pos1 在 pos2 后面
|
||||||
|
/// 0:pos1 和 pos2 一样
|
||||||
|
/// -1:pos1 在 pos2 前面
|
||||||
fn compare_pos(pos1: &LspPosition, pos2: &LspPosition) -> i32 {
|
fn compare_pos(pos1: &LspPosition, pos2: &LspPosition) -> i32 {
|
||||||
if pos1.line > pos2.line {
|
if pos1.line > pos2.line {
|
||||||
1
|
1
|
||||||
@ -94,18 +142,27 @@ pub struct Parameter {
|
|||||||
pub range: Range
|
pub range: Range
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize, Clone)]
|
||||||
// pub struct InstPort {
|
pub enum AssignType {
|
||||||
// pub name: String,
|
Named,
|
||||||
// pub range: Range
|
Ordered
|
||||||
// }
|
}
|
||||||
|
|
||||||
// #[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize, Clone)]
|
||||||
// pub struct InstParameter {
|
pub struct InstPort {
|
||||||
// pub name: String,
|
pub port: Option<String>,
|
||||||
// pub value: String,
|
pub assign_val: Option<String>,
|
||||||
// pub range: Range
|
pub assign_type: AssignType,
|
||||||
// }
|
pub range: Range
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize, Clone)]
|
||||||
|
pub struct InstParameter {
|
||||||
|
pub parameter: Option<String>,
|
||||||
|
pub assign_val: Option<String>,
|
||||||
|
pub assign_type: AssignType,
|
||||||
|
pub range: Range
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
@ -113,7 +170,9 @@ pub struct Instance {
|
|||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub inst_type: String,
|
pub inst_type: String,
|
||||||
pub instparams: Option<Range>,
|
pub instparams: Option<Range>,
|
||||||
|
pub intstparam_assignments: Vec<InstParameter>,
|
||||||
pub instports: Option<Range>,
|
pub instports: Option<Range>,
|
||||||
|
pub intstport_assignments: Vec<InstPort>,
|
||||||
pub range: Range
|
pub range: Range
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,6 +200,7 @@ impl Instance {
|
|||||||
self.range.clone()
|
self.range.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
pub fn gen_dot_completion_param_range(&self) -> Range {
|
pub fn gen_dot_completion_param_range(&self) -> Range {
|
||||||
// TODO: 精心调制这个方法
|
// TODO: 精心调制这个方法
|
||||||
if let Some(param_range) = &self.instparams {
|
if let Some(param_range) = &self.instparams {
|
||||||
@ -211,34 +271,23 @@ pub struct FastHdlparam {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FastHdlparam {
|
impl FastHdlparam {
|
||||||
pub fn add_define(&mut self, name: &str, replacement: &str, start_line: u32, start_character: u32,
|
pub fn add_define(&mut self, name: &str, replacement: &str, range: Range, params: Vec<DefineParam>) {
|
||||||
end_line: u32, end_character: u32, params: Vec<DefineParam>) {
|
|
||||||
let define = Define {
|
let define = Define {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
replacement: replacement.to_string(),
|
replacement: replacement.to_string(),
|
||||||
range: Range {
|
range,
|
||||||
start: Position { line: start_line, character: start_character },
|
|
||||||
end: Position { line: end_line, character: end_character }
|
|
||||||
},
|
|
||||||
params
|
params
|
||||||
};
|
};
|
||||||
self.fast_macro.defines.push(define);
|
self.fast_macro.defines.push(define);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_module(&mut self, name: &str, line: u32, character: u32, end_character: u32) {
|
pub fn new_module(&mut self, name: &str, range: Range) {
|
||||||
let module = Module {
|
let module = Module {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
params: Vec::new(),
|
params: Vec::new(),
|
||||||
ports: Vec::new(),
|
ports: Vec::new(),
|
||||||
instances: Vec::new(),
|
instances: Vec::new(),
|
||||||
range: Range {
|
range
|
||||||
start: Position {
|
|
||||||
line, character
|
|
||||||
},
|
|
||||||
end: Position {
|
|
||||||
line, character: end_character
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
self.content.push(module);
|
self.content.push(module);
|
||||||
}
|
}
|
||||||
@ -250,29 +299,20 @@ impl FastHdlparam {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_parameter(&mut self, name: &str, net_type: &str, init: &str,
|
pub fn add_parameter(&mut self, name: &str, net_type: &str, init: &str, range: Range) {
|
||||||
start_line: u32, start_character: u32, end_line: u32, end_character: u32) {
|
|
||||||
if let Some(last_module) = self.content.last_mut() {
|
if let Some(last_module) = self.content.last_mut() {
|
||||||
let parameter = Parameter {
|
let parameter = Parameter {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
net_type: net_type.to_string(),
|
net_type: net_type.to_string(),
|
||||||
init: init.to_string(),
|
init: init.to_string(),
|
||||||
range: Range {
|
range
|
||||||
start: Position {
|
|
||||||
line: start_line, character: start_character
|
|
||||||
},
|
|
||||||
end: Position {
|
|
||||||
line:end_line, character: end_character
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
last_module.params.push(parameter);
|
last_module.params.push(parameter);
|
||||||
last_module.params.dedup();
|
last_module.params.dedup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_port(&mut self, name: &str, dir_type: &str, net_type: &str, width: &str,
|
pub fn add_port(&mut self, name: &str, dir_type: &str, net_type: &str, width: &str, range: Range) {
|
||||||
start_line: u32, start_character: u32, end_line: u32, end_character: u32) {
|
|
||||||
if let Some(last_module) = self.content.last_mut() {
|
if let Some(last_module) = self.content.last_mut() {
|
||||||
let port = Port {
|
let port = Port {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
@ -280,63 +320,24 @@ impl FastHdlparam {
|
|||||||
net_type: net_type.to_string(),
|
net_type: net_type.to_string(),
|
||||||
width: width.to_string(),
|
width: width.to_string(),
|
||||||
signed: "unsigned".to_string(),
|
signed: "unsigned".to_string(),
|
||||||
range: Range {
|
range
|
||||||
start: Position {
|
|
||||||
line: start_line, character: start_character
|
|
||||||
},
|
|
||||||
end: Position {
|
|
||||||
line:end_line, character: end_character
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
last_module.ports.push(port);
|
last_module.ports.push(port);
|
||||||
last_module.ports.dedup();
|
last_module.ports.dedup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_instance(&mut self, name: &str, inst_type: &str, line: u32, character: u32, end_character: u32,
|
pub fn add_instance(&mut self, name: &str, inst_type: &str, range: Range,
|
||||||
param_start_line: u32, param_start_character: u32, param_end_line: u32, param_end_character: u32,
|
param_range: Option<Range>, params_assign: Vec<InstParameter>, port_range: Option<Range>, ports_assign: Vec<InstPort>) {
|
||||||
port_start_line: u32, port_start_character: u32, port_end_line: u32, port_end_character: u32 ) {
|
|
||||||
if let Some(last_module) = self.content.last_mut() {
|
if let Some(last_module) = self.content.last_mut() {
|
||||||
let instance = Instance {
|
let instance = Instance {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
inst_type: inst_type.to_string(),
|
inst_type: inst_type.to_string(),
|
||||||
instparams: if param_start_line == 0 {
|
instparams: param_range,
|
||||||
None
|
intstparam_assignments: params_assign,
|
||||||
} else {
|
instports: port_range,
|
||||||
Some(
|
intstport_assignments: ports_assign,
|
||||||
Range {
|
range
|
||||||
start: Position {
|
|
||||||
line: param_start_line, character: param_start_character
|
|
||||||
},
|
|
||||||
end: Position {
|
|
||||||
line: param_end_line, character: param_end_character
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
instports: if port_start_line == 0 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(
|
|
||||||
Range {
|
|
||||||
start: Position {
|
|
||||||
line: port_start_line, character: port_start_character
|
|
||||||
},
|
|
||||||
end: Position {
|
|
||||||
line: port_end_line, character: port_end_character
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
range: Range {
|
|
||||||
start: Position {
|
|
||||||
line, character
|
|
||||||
},
|
|
||||||
end: Position {
|
|
||||||
line, character: end_character
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
last_module.instances.push(instance);
|
last_module.instances.push(instance);
|
||||||
}
|
}
|
||||||
@ -355,6 +356,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 {
|
||||||
@ -406,6 +409,19 @@ impl HdlParam {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 遍历 path_string 下的所有 module,并根据条件返回
|
||||||
|
pub fn walk_module(&self, path_string: &str, condition: impl Fn(&Module) -> bool) -> Option<Module> {
|
||||||
|
let path_to_hdl_file = self.path_to_hdl_file.read().unwrap();
|
||||||
|
if let Some(hdl_file) = path_to_hdl_file.get(path_string) {
|
||||||
|
for def_module in &hdl_file.fast.content {
|
||||||
|
if condition(def_module) {
|
||||||
|
return Some(def_module.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::BufRead;
|
use std::io::BufRead;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
@ -9,10 +8,11 @@ use ropey::Rope;
|
|||||||
use tower_lsp::lsp_types::Url;
|
use tower_lsp::lsp_types::Url;
|
||||||
use sv_parser::{unwrap_locate, unwrap_node, EventIter, ListOfParamAssignments, Locate, NodeEvent, ParamAssignment, ParameterDeclaration, RefNode, SyntaxTree};
|
use sv_parser::{unwrap_locate, unwrap_node, EventIter, ListOfParamAssignments, Locate, NodeEvent, ParamAssignment, ParameterDeclaration, RefNode, SyntaxTree};
|
||||||
|
|
||||||
use crate::sources::recovery_sv_parse_with_retry;
|
use crate::core::hdlparam::{AssignType, Position, Range};
|
||||||
|
use crate::sources::{recovery_sv_parse_with_retry, LSPSupport};
|
||||||
use crate::utils::to_escape_path;
|
use crate::utils::to_escape_path;
|
||||||
|
|
||||||
use super::hdlparam::{FastHdlparam, Macro};
|
use super::hdlparam::{self, FastHdlparam, InstParameter, InstPort, Macro};
|
||||||
|
|
||||||
macro_rules! advance_until_leave {
|
macro_rules! advance_until_leave {
|
||||||
($tokens:ident, $tree:ident, $event_iter:ident, $node:path) => {{
|
($tokens:ident, $tree:ident, $event_iter:ident, $node:path) => {{
|
||||||
@ -56,22 +56,6 @@ macro_rules! skip_until_enter {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! skip_until_leave {
|
|
||||||
($tree:ident, $event_iter:ident, $node:path) => {
|
|
||||||
while let Some(event) = $event_iter.next() {
|
|
||||||
match event {
|
|
||||||
NodeEvent::Enter(_) => (),
|
|
||||||
NodeEvent::Leave(x) => match x {
|
|
||||||
$node(_) => {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn sv_parser(path: &str) -> Option<FastHdlparam> {
|
pub fn sv_parser(path: &str) -> Option<FastHdlparam> {
|
||||||
// The path of SystemVerilog source file
|
// The path of SystemVerilog source file
|
||||||
@ -114,20 +98,16 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re
|
|||||||
};
|
};
|
||||||
let mut ansi_port_last_dir = "";
|
let mut ansi_port_last_dir = "";
|
||||||
|
|
||||||
// TODO: 搞清楚为什么会出现重复
|
|
||||||
let mut added_param_names = HashSet::<String>::new();
|
|
||||||
|
|
||||||
let content = syntax_tree.text.text().split('\n')
|
|
||||||
.map(|s| s.to_string())
|
|
||||||
.collect::<Vec<String>>();
|
|
||||||
// println!("{:?}", syntax_tree);
|
// println!("{:?}", syntax_tree);
|
||||||
// &SyntaxTree is iterable
|
// &SyntaxTree is iterable
|
||||||
|
let doc = Rope::from_str(syntax_tree.text.text());
|
||||||
|
|
||||||
for node in syntax_tree {
|
for node in syntax_tree {
|
||||||
match node {
|
match node {
|
||||||
RefNode::TextMacroDefinition(x) => {
|
RefNode::TextMacroDefinition(x) => {
|
||||||
if let Some(start) = unwrap_node!(x, TextMacroDefinition) {
|
if let Some(start) = unwrap_node!(x, TextMacroDefinition) {
|
||||||
let start = get_identifier(start).unwrap();
|
let start = get_identifier(start).unwrap();
|
||||||
let (start_line, start_character) = (start.line, get_column_by_offset(&content, start.offset));
|
let start_pos = get_position(&doc, start, 0);
|
||||||
|
|
||||||
let name = if let Some(name) = unwrap_node!(x, TextMacroName) {
|
let name = if let Some(name) = unwrap_node!(x, TextMacroName) {
|
||||||
let name = get_identifier(name).unwrap();
|
let name = get_identifier(name).unwrap();
|
||||||
@ -155,23 +135,28 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (end_line, end_character, replacement) = if let Some(RefNode::MacroText(x)) = unwrap_node!(x, MacroText) {
|
let (end_pos, replacement) = if let Some(RefNode::MacroText(x)) = unwrap_node!(x, MacroText) {
|
||||||
let replacement = x.nodes.0;
|
let replacement = x.nodes.0;
|
||||||
(replacement.line, get_column_by_offset(&content, replacement.offset) + replacement.len, syntax_tree.get_str(&replacement).unwrap())
|
(get_position(&doc, replacement,replacement.len), syntax_tree.get_str(&replacement).unwrap())
|
||||||
} else {
|
} else {
|
||||||
(start_line, start_character + start.len, "unknown")
|
(get_position(&doc, start, start.len), "unknown")
|
||||||
};
|
};
|
||||||
|
let define_range = Range { start: start_pos, end: end_pos };
|
||||||
|
|
||||||
hdlparam.add_define(name, replacement, start_line, start_character as u32, end_line, end_character as u32, params_vec);
|
hdlparam.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 = get_identifier(start_keyword).unwrap();
|
||||||
|
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, 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 (line, character) = (id.line, get_column_by_offset(&content, id.offset) as u32);
|
|
||||||
let end_character = character + id.len as u32;
|
|
||||||
let name = syntax_tree.get_str(&id).unwrap();
|
let name = syntax_tree.get_str(&id).unwrap();
|
||||||
hdlparam.new_module(name, line, character, end_character);
|
hdlparam.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();
|
||||||
@ -179,7 +164,8 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re
|
|||||||
ParameterDeclaration::Param(x) => {
|
ParameterDeclaration::Param(x) => {
|
||||||
let keyword_locate = &x.nodes.0.nodes.0;
|
let keyword_locate = &x.nodes.0.nodes.0;
|
||||||
// println!("keyword {:#?}", keyword_locate);
|
// println!("keyword {:#?}", keyword_locate);
|
||||||
let (start_line, start_character) = (keyword_locate.line, get_column_by_offset(&content, keyword_locate.offset) as u32);
|
let start_pos = get_position(&doc, keyword_locate.clone(), 0);
|
||||||
|
|
||||||
let net_type = match unwrap_node!(RefNode::ParameterDeclarationParam(x), DataType) {
|
let net_type = match unwrap_node!(RefNode::ParameterDeclarationParam(x), DataType) {
|
||||||
Some(RefNode::DataType(data_type)) => {
|
Some(RefNode::DataType(data_type)) => {
|
||||||
let id = unwrap_node!(data_type, SimpleIdentifier, Keyword);
|
let id = unwrap_node!(data_type, SimpleIdentifier, Keyword);
|
||||||
@ -194,13 +180,14 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (index, (name, loc, init)) in list_param_assignment(syntax_tree, &x.nodes.2, &mut event_iter).iter().enumerate() {
|
for (index, (name, loc, init)) in list_param_assignment(syntax_tree, &x.nodes.2, &mut event_iter).iter().enumerate() {
|
||||||
let (start_line, start_character) = if index != 0 {
|
let start_pos = if index != 0 {
|
||||||
(loc.line as u32, get_column_by_offset(&content, loc.offset) as u32)
|
get_position(&doc, loc.clone(), 0)
|
||||||
} else {
|
} else {
|
||||||
(start_line, start_character)
|
start_pos.clone()
|
||||||
};
|
};
|
||||||
let (end_line, end_character) = (loc.line as u32, (get_column_by_offset(&content, loc.offset) + loc.len) as u32);
|
let end_pos = get_position(&doc, loc.clone(), loc.len);
|
||||||
hdlparam.add_parameter(name, net_type, init, start_line, start_character, end_line, end_character);
|
let param_range = Range { start: start_pos, end: end_pos };
|
||||||
|
hdlparam.add_parameter(name, net_type, init, param_range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
@ -211,7 +198,7 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re
|
|||||||
if let Some(id) = unwrap_node!(x, InputDeclaration, OutputDeclaration, InoutDeclaration) {
|
if let Some(id) = unwrap_node!(x, InputDeclaration, OutputDeclaration, InoutDeclaration) {
|
||||||
let id = get_identifier(id).unwrap();
|
let id = get_identifier(id).unwrap();
|
||||||
let dir_type = syntax_tree.get_str(&id).unwrap();
|
let dir_type = syntax_tree.get_str(&id).unwrap();
|
||||||
let (dir_line, dir_character) = (id.line, get_column_by_offset(&content, id.offset) as u32);
|
let start_pos = get_position(&doc, id, 0);
|
||||||
|
|
||||||
let net_type = match unwrap_node!(x, DataType, ImplicitDataType) {
|
let net_type = match unwrap_node!(x, DataType, ImplicitDataType) {
|
||||||
Some(RefNode::DataType(x)) => {
|
Some(RefNode::DataType(x)) => {
|
||||||
@ -241,11 +228,9 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re
|
|||||||
let id = unwrap_node!(x, Identifier).unwrap();
|
let id = unwrap_node!(x, Identifier).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();
|
||||||
let (start_line, start_character, end_line, end_character) =
|
let port_range = Range { start: start_pos.clone(), end: get_position(&doc, id, id.len) };
|
||||||
(dir_line, dir_character, id.line, (get_column_by_offset(&content, id.offset) + id.len) as u32);
|
|
||||||
|
|
||||||
hdlparam.add_port(name, dir_type, net_type, width.as_str(), start_line, start_character,
|
hdlparam.add_port(name, dir_type, net_type, width.as_str(), port_range);
|
||||||
end_line, end_character);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,17 +240,17 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re
|
|||||||
if let Some(id) = unwrap_node!(x, PortIdentifier) {
|
if let Some(id) = unwrap_node!(x, PortIdentifier) {
|
||||||
let name_locate = get_identifier(id).unwrap();
|
let name_locate = get_identifier(id).unwrap();
|
||||||
let name = syntax_tree.get_str(&name_locate).unwrap();
|
let name = syntax_tree.get_str(&name_locate).unwrap();
|
||||||
let character = get_column_by_offset(&content, name_locate.offset);
|
// let character = get_column_by_offset(&content, name_locate.offset);
|
||||||
let (end_line, end_character) = (name_locate.line, (character + name_locate.len) as u32);
|
let end_pos = get_position(&doc, name_locate, name_locate.len);
|
||||||
|
|
||||||
let id = unwrap_node!(x, PortDirection);
|
let id = unwrap_node!(x, PortDirection);
|
||||||
let (start_line, start_character) = if id != None {
|
let port_range = if id != None {
|
||||||
let id = id.unwrap();
|
let id = id.unwrap();
|
||||||
let dir_locate = get_identifier(id).unwrap();
|
let dir_locate = get_identifier(id).unwrap();
|
||||||
ansi_port_last_dir = syntax_tree.get_str(&dir_locate).unwrap();
|
ansi_port_last_dir = syntax_tree.get_str(&dir_locate).unwrap();
|
||||||
(dir_locate.line, get_column_by_offset(&content, dir_locate.offset) as u32)
|
Range { start: get_position(&doc, dir_locate, 0), end: end_pos }
|
||||||
} else {
|
} else {
|
||||||
(name_locate.line, character as u32)
|
Range { start: get_position(&doc, name_locate, 0), end: end_pos }
|
||||||
};
|
};
|
||||||
|
|
||||||
let net_type = if unwrap_node!(x, AnsiPortDeclarationVariable) != None {
|
let net_type = if unwrap_node!(x, AnsiPortDeclarationVariable) != None {
|
||||||
@ -294,35 +279,42 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re
|
|||||||
_ => "1".to_string()
|
_ => "1".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
hdlparam.add_port(name, ansi_port_last_dir, net_type, width.as_str(), start_line, start_character, end_line, end_character);
|
hdlparam.add_port(name, ansi_port_last_dir, net_type, width.as_str(), port_range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RefNode::ModuleInstantiation(x) => {
|
RefNode::ModuleInstantiation(x) => {
|
||||||
if let Some(id) = unwrap_node!(x, ModuleIdentifier) {
|
if let Some(id) = unwrap_node!(x, ModuleIdentifier) {
|
||||||
let id = get_identifier(id).unwrap();
|
let id = get_identifier(id).unwrap();
|
||||||
let inst_type = syntax_tree.get_str(&id).unwrap();
|
let inst_type = syntax_tree.get_str(&id).unwrap();
|
||||||
|
let start_pos = get_position(&doc, id, 0);
|
||||||
|
let range = get_pp_range(&doc, RefNode::ModuleInstantiation(x));
|
||||||
|
let inst_range = Range { start: start_pos, end: range.end };
|
||||||
|
|
||||||
if let Some(id) = unwrap_node!(x, HierarchicalInstance) {
|
if let Some(id) = unwrap_node!(x, HierarchicalInstance) {
|
||||||
let hier_node = id.clone();
|
let hier_node = id.clone();
|
||||||
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();
|
||||||
let (line, character) = (id.line, get_column_by_offset(&content, id.offset) as u32);
|
|
||||||
let end_character = character + id.len as u32;
|
|
||||||
|
|
||||||
let (param_start_line, param_start_character,
|
let param_range = match unwrap_node!(x, ParameterValueAssignment) {
|
||||||
param_end_line, param_end_character) = match unwrap_node!(x, ParameterValueAssignment) {
|
|
||||||
Some(inst_node) => {
|
Some(inst_node) => {
|
||||||
get_port_parameter_range(&content, inst_node)
|
get_pp_range(&doc, inst_node).to_option()
|
||||||
}
|
}
|
||||||
_ => (0, 0, 0, 0)
|
_ => None
|
||||||
};
|
};
|
||||||
|
|
||||||
let (port_start_line, port_start_character,
|
let inst_param_assignments = if let Some(param_node) = unwrap_node!(x, ParameterValueAssignment) {
|
||||||
port_end_line, port_end_character) = get_port_parameter_range(&content, hier_node);
|
get_instance_params(syntax_tree, &doc, param_node)
|
||||||
|
} else {
|
||||||
|
Vec::<InstParameter>::new()
|
||||||
|
};
|
||||||
|
|
||||||
hdlparam.add_instance(name, inst_type, line, character, end_character,
|
let inst_port_assignments = get_instance_ports(&syntax_tree, &doc, hier_node.clone());
|
||||||
param_start_line, param_start_character, param_end_line, param_end_character,
|
let port_range = get_pp_range(&doc, hier_node).to_option();
|
||||||
port_start_line, port_start_character, port_end_line, port_end_character
|
|
||||||
|
hdlparam.add_instance(
|
||||||
|
name, inst_type, inst_range,
|
||||||
|
param_range, inst_param_assignments,
|
||||||
|
port_range, inst_port_assignments
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,22 +323,24 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re
|
|||||||
let id = unwrap_node!(x, GateInstantiation).unwrap();
|
let id = unwrap_node!(x, GateInstantiation).unwrap();
|
||||||
let id = get_identifier(id).unwrap();
|
let id = get_identifier(id).unwrap();
|
||||||
let inst_type = syntax_tree.get_str(&id).unwrap();
|
let inst_type = syntax_tree.get_str(&id).unwrap();
|
||||||
|
let start_pos = get_position(&doc, id, 0);
|
||||||
|
let range = get_pp_range(&doc, RefNode::GateInstantiation(x));
|
||||||
|
let inst_range = Range { start: start_pos, end: range.end };
|
||||||
|
|
||||||
match unwrap_node!(x, NInputGateInstance, NOutputGateInstance) {
|
match unwrap_node!(x, NInputGateInstance, NOutputGateInstance) {
|
||||||
Some(id) => {
|
Some(id) => {
|
||||||
let gate_node = id.clone();
|
let gate_node = id.clone();
|
||||||
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();
|
||||||
let (line, character) = (id.line, get_column_by_offset(&content, id.offset) as u32);
|
|
||||||
let end_character = character + id.len as u32;
|
|
||||||
|
|
||||||
let (param_start_line, param_start_character, param_end_line, param_end_character) = (0, 0, 0, 0);
|
let param_range = None;
|
||||||
let (port_start_line, port_start_character,
|
let inst_port_assignments = get_instance_ports(&syntax_tree, &doc, gate_node.clone());
|
||||||
port_end_line, port_end_character) = get_port_parameter_range(&content, gate_node);
|
let port_range = get_pp_range(&doc, gate_node).to_option();
|
||||||
|
|
||||||
hdlparam.add_instance(name, inst_type, line, character, end_character,
|
hdlparam.add_instance(
|
||||||
param_start_line, param_start_character, param_end_line, param_end_character,
|
name, inst_type, inst_range,
|
||||||
port_start_line, port_start_character, port_end_line, port_end_character
|
param_range, Vec::<InstParameter>::new(),
|
||||||
|
port_range, inst_port_assignments
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
@ -361,15 +355,16 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re
|
|||||||
Ok(hdlparam)
|
Ok(hdlparam)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_port_parameter_range(content: &[String], node: RefNode) -> (u32, u32, u32, u32) {
|
// 获取 port 或者 param 的 range
|
||||||
let locate = get_first_last_locate(node);
|
/// 返回的四元组:(start_line, start_character, end_line, end_character)
|
||||||
if locate.is_none() {
|
fn get_pp_range(doc: &Rope, node: RefNode) -> Range {
|
||||||
(0,0,0,0)
|
if let Some(locate) = get_first_last_locate(node) {
|
||||||
|
Range {
|
||||||
|
start: get_position(doc, locate.0, 0),
|
||||||
|
end: get_position(doc, locate.1, locate.1.len)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
(
|
Range { start: Position { line: 0, character: 0}, end: Position { line: 0, character: 0} }
|
||||||
locate.unwrap().0.line, get_column_by_offset(&content, locate.unwrap().0.offset) as u32,
|
|
||||||
locate.unwrap().1.line, (get_column_by_offset(&content, locate.unwrap().1.offset) + locate.unwrap().1.len) as u32
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,14 +373,11 @@ fn get_first_last_locate(node: RefNode) -> Option<(Locate, Locate)> {
|
|||||||
let mut last_locate = Locate { offset: 0, line: 0, len: 0 };
|
let mut last_locate = Locate { offset: 0, line: 0, len: 0 };
|
||||||
|
|
||||||
for n in node {
|
for n in node {
|
||||||
match n {
|
if let RefNode::Symbol(x) = n {
|
||||||
RefNode::Symbol(x) => {
|
|
||||||
let locate = x.nodes.0;
|
let locate = x.nodes.0;
|
||||||
if locate != last_locate { last_locate = locate; }
|
if locate != last_locate { last_locate = locate; }
|
||||||
if first_locate.offset == 0 { first_locate = locate; };
|
if first_locate.offset == 0 { first_locate = locate; };
|
||||||
}
|
}
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if last_locate.offset == 0 {
|
if last_locate.offset == 0 {
|
||||||
@ -395,6 +387,170 @@ fn get_first_last_locate(node: RefNode) -> Option<(Locate, Locate)> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_instance_params(syntax_tree: &SyntaxTree, doc: &Rope, node: RefNode) -> Vec<InstParameter> {
|
||||||
|
let mut parameters = Vec::new();
|
||||||
|
|
||||||
|
for list in node {
|
||||||
|
match unwrap_node!(list, ListOfParameterAssignmentsNamed, ListOfParameterAssignmentsOrdered) {
|
||||||
|
Some(RefNode::ListOfParameterAssignmentsNamed(x)) => {
|
||||||
|
for assign in x {
|
||||||
|
if let RefNode::NamedParameterAssignment(ident) = assign {
|
||||||
|
let param_range = get_pp_range(doc, assign);
|
||||||
|
let param_name_locate = get_identifier(RefNode::ParameterIdentifier(&(ident.nodes.1)));
|
||||||
|
let param_name = syntax_tree.get_str(¶m_name_locate).unwrap();
|
||||||
|
let name = if let (_, Some(name_expr), _) = ident.nodes.2.nodes.clone() {
|
||||||
|
if let Some(RefNode::Expression(name_expr)) = unwrap_node!(name_expr.into_iter(), Expression) {
|
||||||
|
let expr = sv_parser::NeedParseExpression::Expression(name_expr.clone());
|
||||||
|
let (expr, _) = parse_expression(syntax_tree, &expr);
|
||||||
|
Some(expr)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let param = InstParameter {
|
||||||
|
parameter: Some(param_name.to_string()),
|
||||||
|
assign_val: name,
|
||||||
|
assign_type: AssignType::Named,
|
||||||
|
range: param_range
|
||||||
|
};
|
||||||
|
parameters.push(param);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(RefNode::ListOfParameterAssignmentsOrdered(x)) => {
|
||||||
|
for assign in x {
|
||||||
|
if let RefNode::OrderedParameterAssignment(ident) = assign {
|
||||||
|
let expr = ident.nodes.0.clone();
|
||||||
|
if let Some(RefNode::Expression(expr)) = unwrap_node!(expr.into_iter(), Expression) {
|
||||||
|
let start_locate = get_identifier(RefNode::Expression(expr));
|
||||||
|
let expr = sv_parser::NeedParseExpression::Expression(expr.clone());
|
||||||
|
let (expr, end_locate) = parse_expression(syntax_tree, &expr);
|
||||||
|
let start_locate = start_locate.unwrap_or(Locate { offset: 0, line: 0, len: 0 });
|
||||||
|
let end_locate = end_locate.unwrap_or(start_locate);
|
||||||
|
let param = InstParameter {
|
||||||
|
parameter: None,
|
||||||
|
assign_val: Some(expr),
|
||||||
|
assign_type: AssignType::Ordered,
|
||||||
|
range: Range {
|
||||||
|
start: get_position(doc, start_locate, 0),
|
||||||
|
end: get_position(doc, end_locate, end_locate.len)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
parameters.push(param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters.sort_by_key(|p| p.range.clone());
|
||||||
|
parameters.dedup_by_key(|p| p.range.clone());
|
||||||
|
parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_instance_ports(syntax_tree: &SyntaxTree, doc: &Rope, node: RefNode) -> Vec<InstPort> {
|
||||||
|
let mut ports = Vec::new();
|
||||||
|
for list in node {
|
||||||
|
match unwrap_node!(list, ListOfPortConnectionsNamed, ListOfPortConnectionsOrdered, InputTerminal, OutputTerminal) {
|
||||||
|
Some(RefNode::ListOfPortConnectionsNamed(x)) => {
|
||||||
|
for connect in x {
|
||||||
|
if let RefNode::NamedPortConnectionIdentifier(ident) = connect {
|
||||||
|
let port_range = get_pp_range(doc, connect);
|
||||||
|
let port_name_locate = get_identifier(RefNode::PortIdentifier(&(ident.nodes.2)));
|
||||||
|
let port_name = syntax_tree.get_str(&port_name_locate).unwrap();
|
||||||
|
let name = if ident.nodes.3.is_some() {
|
||||||
|
if let (_, Some(name_expr), _) = ident.nodes.3.clone().unwrap().nodes {
|
||||||
|
let expr = sv_parser::NeedParseExpression::Expression(name_expr);
|
||||||
|
let (expr, _) = parse_expression(syntax_tree, &expr);
|
||||||
|
Some(expr)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let port = InstPort {
|
||||||
|
port: Some(port_name.to_string()),
|
||||||
|
assign_val: name,
|
||||||
|
assign_type: AssignType::Named,
|
||||||
|
range: port_range
|
||||||
|
};
|
||||||
|
ports.push(port);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(RefNode::ListOfPortConnectionsOrdered(x)) => {
|
||||||
|
for connect in x {
|
||||||
|
if let RefNode::OrderedPortConnection(ident) = connect {
|
||||||
|
if let Some(expr) = ident.nodes.1.clone() {
|
||||||
|
let start_locate = get_identifier(RefNode::Expression(&expr));
|
||||||
|
let expr = sv_parser::NeedParseExpression::Expression(expr);
|
||||||
|
let (expr, end_locate) = parse_expression(syntax_tree, &expr);
|
||||||
|
let start_locate = start_locate.unwrap_or(Locate { offset: 0, line: 0, len: 0 });
|
||||||
|
let end_locate = end_locate.unwrap_or(start_locate);
|
||||||
|
let port = InstPort {
|
||||||
|
port: None,
|
||||||
|
assign_val: Some(expr),
|
||||||
|
assign_type: AssignType::Ordered,
|
||||||
|
range: Range {
|
||||||
|
start: get_position(doc, start_locate, 0),
|
||||||
|
end: get_position(doc, end_locate, end_locate.len)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ports.push(port);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(RefNode::InputTerminal(x)) => {
|
||||||
|
let expr = x.nodes.0.clone();
|
||||||
|
let start_locate = get_identifier(RefNode::Expression(&expr));
|
||||||
|
let expr = sv_parser::NeedParseExpression::Expression(expr);
|
||||||
|
let (expr, end_locate) = parse_expression(syntax_tree, &expr);
|
||||||
|
let start_locate = start_locate.unwrap_or(Locate { offset: 0, line: 0, len: 0 });
|
||||||
|
let end_locate = end_locate.unwrap_or(start_locate);
|
||||||
|
let port = InstPort {
|
||||||
|
port: None,
|
||||||
|
assign_val: Some(expr),
|
||||||
|
assign_type: AssignType::Ordered,
|
||||||
|
range: Range {
|
||||||
|
start: get_position(doc, start_locate, 0),
|
||||||
|
end: get_position(doc, end_locate, end_locate.len)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ports.push(port);
|
||||||
|
}
|
||||||
|
Some(RefNode::OutputTerminal(x)) => {
|
||||||
|
let expr = x.nodes.0.clone();
|
||||||
|
let start_locate = get_identifier(RefNode::NetLvalue(&expr));
|
||||||
|
let expr = sv_parser::NeedParseExpression::NetValue(expr);
|
||||||
|
let (expr, end_locate) = parse_expression(syntax_tree, &expr);
|
||||||
|
let start_locate = start_locate.unwrap_or(Locate { offset: 0, line: 0, len: 0 });
|
||||||
|
let end_locate = end_locate.unwrap_or(start_locate);
|
||||||
|
let port = InstPort {
|
||||||
|
port: None,
|
||||||
|
assign_val: Some(expr),
|
||||||
|
assign_type: AssignType::Ordered,
|
||||||
|
range: Range {
|
||||||
|
start: get_position(doc, start_locate, 0),
|
||||||
|
end: get_position(doc, end_locate, end_locate.len)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ports.push(port);
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ports.sort_by_key(|p| p.range.clone());
|
||||||
|
ports.dedup_by_key(|p| p.range.clone());
|
||||||
|
ports
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_expression(syntax_tree: &SyntaxTree, x: &sv_parser::NeedParseExpression) -> (String, Option<Locate>) {
|
fn parse_expression(syntax_tree: &SyntaxTree, x: &sv_parser::NeedParseExpression) -> (String, Option<Locate>) {
|
||||||
let mut last_locate = Locate { offset: 0, line: 0, len: 0 };
|
let mut last_locate = Locate { offset: 0, line: 0, len: 0 };
|
||||||
let mut expression = String::new();
|
let mut expression = String::new();
|
||||||
@ -489,6 +645,12 @@ fn get_identifier(node: RefNode) -> Option<Locate> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_position(doc: &Rope, locate: Locate, offset: usize) -> Position {
|
||||||
|
let byte = locate.offset + offset;
|
||||||
|
let pos = doc.byte_to_pos(byte);
|
||||||
|
hdlparam::Position::from_lsp_position(&pos)
|
||||||
|
}
|
||||||
|
|
||||||
fn get_includes(path: &PathBuf) -> Vec<crate::core::hdlparam::Include> {
|
fn get_includes(path: &PathBuf) -> Vec<crate::core::hdlparam::Include> {
|
||||||
let mut includes = Vec::new();
|
let mut includes = Vec::new();
|
||||||
|
|
||||||
@ -568,22 +730,6 @@ fn update_module_range(path: &PathBuf, hdlparam: &mut FastHdlparam) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_column_by_offset(content: &[String], offset: usize) -> usize {
|
|
||||||
let mut current_offset = 0;
|
|
||||||
|
|
||||||
for line_content in content {
|
|
||||||
let line_length = line_content.len() + 1; // +1 for newline character
|
|
||||||
// println!("now line {} len {}", line_content, line_length);
|
|
||||||
// println!("now offset {} offset {}", current_offset + line_length, offset);
|
|
||||||
if current_offset + line_length > offset {
|
|
||||||
return offset - current_offset + 1;
|
|
||||||
}
|
|
||||||
current_offset += line_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
1 // if offset over the file lentgh,return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn param_assignment(
|
fn param_assignment(
|
||||||
tree: &SyntaxTree,
|
tree: &SyntaxTree,
|
||||||
_: &ParamAssignment,
|
_: &ParamAssignment,
|
||||||
|
@ -206,6 +206,8 @@ fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> {
|
|||||||
inst_type: get_value(&tokens[i+1]),
|
inst_type: get_value(&tokens[i+1]),
|
||||||
instports: None,
|
instports: None,
|
||||||
instparams: None,
|
instparams: None,
|
||||||
|
intstport_assignments: Vec::new(),
|
||||||
|
intstparam_assignments: Vec::new(),
|
||||||
range: Range {
|
range: Range {
|
||||||
start: Position {
|
start: Position {
|
||||||
line: tokens[i-1].pos.range.start.line + 1,
|
line: tokens[i-1].pos.range.start.line + 1,
|
||||||
@ -226,6 +228,8 @@ fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> {
|
|||||||
inst_type: get_value(&tokens[i+2]),
|
inst_type: get_value(&tokens[i+2]),
|
||||||
instports: None,
|
instports: None,
|
||||||
instparams: None,
|
instparams: None,
|
||||||
|
intstport_assignments: Vec::new(),
|
||||||
|
intstparam_assignments: Vec::new(),
|
||||||
range: Range {
|
range: Range {
|
||||||
start: Position {
|
start: Position {
|
||||||
line: tokens[i-1].pos.range.start.line + 1,
|
line: tokens[i-1].pos.range.start.line + 1,
|
||||||
@ -257,6 +261,8 @@ fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> {
|
|||||||
inst_type,
|
inst_type,
|
||||||
instports: None,
|
instports: None,
|
||||||
instparams: None,
|
instparams: None,
|
||||||
|
intstport_assignments: Vec::new(),
|
||||||
|
intstparam_assignments: Vec::new(),
|
||||||
range: Range {
|
range: Range {
|
||||||
start: Position {
|
start: Position {
|
||||||
line: tokens[i-1].pos.range.start.line + 1,
|
line: tokens[i-1].pos.range.start.line + 1,
|
||||||
|
@ -123,11 +123,8 @@ fn goto_instantiation<'a>(
|
|||||||
if token_name == param.name {
|
if token_name == param.name {
|
||||||
let def_path = server.srcs.hdl_param.find_module_definition_path(&module.name).unwrap();
|
let def_path = server.srcs.hdl_param.find_module_definition_path(&module.name).unwrap();
|
||||||
let target_uri = Url::from_file_path(def_path).unwrap();
|
let target_uri = Url::from_file_path(def_path).unwrap();
|
||||||
let mut target_range = param.range.to_lsp_range();
|
let target_range = param.range.clone();
|
||||||
target_range.start.line -= 1;
|
let target_range = target_range.to_lsp_range();
|
||||||
target_range.start.character -= 1;
|
|
||||||
target_range.end.line -= 1;
|
|
||||||
target_range.end.character -= 1;
|
|
||||||
|
|
||||||
let link = vec");
|
let define_info = format!("Go to [Definition]({path_uri}#L{def_row}:{def_col})");
|
||||||
|
|
||||||
let port_num = module.ports.len();
|
let port_num = module.ports.len();
|
||||||
let param_num = module.params.len();
|
let param_num = module.params.len();
|
||||||
@ -417,7 +389,6 @@ pub fn hover_module_declaration(
|
|||||||
let mut markdowns = Vec::<MarkedString>::new();
|
let mut markdowns = Vec::<MarkedString>::new();
|
||||||
markdowns.push(MarkedString::String(port_desc));
|
markdowns.push(MarkedString::String(port_desc));
|
||||||
markdowns.push(MarkedString::String(io_desc));
|
markdowns.push(MarkedString::String(io_desc));
|
||||||
markdowns.push(MarkedString::String("".to_string()));
|
|
||||||
markdowns.push(MarkedString::String(define_info));
|
markdowns.push(MarkedString::String(define_info));
|
||||||
markdowns.push(MarkedString::String("---".to_string()));
|
markdowns.push(MarkedString::String("---".to_string()));
|
||||||
|
|
||||||
@ -441,18 +412,21 @@ 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();
|
||||||
|
|
||||||
if module.params.len() > 0 {
|
if module.params.len() > 0 {
|
||||||
codes.push(format!("module {} #(", module.name));
|
codes.push(format!("module {} #(", module.name));
|
||||||
|
|
||||||
|
let max_param_name_length = module.params.iter().map(|param| param.name.len()).max().unwrap_or(0);
|
||||||
|
|
||||||
for (i, param) in module.params.iter().enumerate() {
|
for (i, param) in module.params.iter().enumerate() {
|
||||||
let mut param_desc_array = Vec::<String>::new();
|
let mut param_desc_array = Vec::<String>::new();
|
||||||
param_desc_array.push(format!("parameter {}", param.name));
|
param_desc_array.push(format!("parameter {}{}", param.name, " ".repeat(max_param_name_length - param.name.len())));
|
||||||
if param.init != "unknown" {
|
if param.init != "unknown" {
|
||||||
param_desc_array.push(param.init.to_string());
|
param_desc_array.push(format!(" = {}", param.init.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let param_desc = param_desc_array.join(" ");
|
let param_desc = param_desc_array.join(" ");
|
||||||
@ -468,22 +442,65 @@ fn make_module_profile_code(module: &crate::core::hdlparam::Module) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if module.ports.len() > 0 {
|
if module.ports.len() > 0 {
|
||||||
|
|
||||||
|
let net_mapper = |net_type: &str| {
|
||||||
|
if net_type == "unknown" {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
net_type.len()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let sign_mapper = |signed: &str| {
|
||||||
|
if signed == "unsigned" {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
"signed".len()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let width_mapper = |width: &str| {
|
||||||
|
if width == "1" {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
width.len()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let max_net_length = module.ports.iter().map(|port| net_mapper(&port.net_type)).max().unwrap_or(0);
|
||||||
|
let max_sign_length = module.ports.iter().map(|port| sign_mapper(&port.signed)).max().unwrap_or(0);
|
||||||
|
let max_width_length = module.ports.iter().map(|port| width_mapper(&port.width)).max().unwrap_or(0);
|
||||||
|
let max_dir_length = module.ports.iter().map(|port| port.dir_type.len()).max().unwrap_or(0);
|
||||||
|
|
||||||
for (i, port) in module.ports.iter().enumerate() {
|
for (i, port) in module.ports.iter().enumerate() {
|
||||||
let mut port_desc_array = Vec::<String>::new();
|
let mut port_desc_array = Vec::<String>::new();
|
||||||
|
|
||||||
|
// input, output, inout
|
||||||
port_desc_array.push(port.dir_type.to_string());
|
port_desc_array.push(port.dir_type.to_string());
|
||||||
|
port_desc_array.push(" ".repeat(max_dir_length - port.dir_type.len() + 1));
|
||||||
|
|
||||||
|
// reg, wire
|
||||||
if port.net_type != "unknown" {
|
if port.net_type != "unknown" {
|
||||||
port_desc_array.push(port.net_type.to_string());
|
port_desc_array.push(port.net_type.to_string());
|
||||||
}
|
}
|
||||||
|
port_desc_array.push(" ".repeat(max_net_length - net_mapper(&port.net_type) + 1));
|
||||||
|
|
||||||
|
|
||||||
|
// signed, unsigned
|
||||||
if port.signed != "unsigned" {
|
if port.signed != "unsigned" {
|
||||||
port_desc_array.push("signed".to_string());
|
port_desc_array.push("signed".to_string());
|
||||||
}
|
}
|
||||||
|
port_desc_array.push(" ".repeat(max_sign_length - sign_mapper(&port.signed) + 1));
|
||||||
|
|
||||||
|
// [3:0]
|
||||||
if port.width != "1" {
|
if port.width != "1" {
|
||||||
port_desc_array.push(port.width.to_string());
|
port_desc_array.push(port.width.to_string());
|
||||||
}
|
}
|
||||||
|
port_desc_array.push(" ".repeat(max_width_length - width_mapper(&port.width) + 1));
|
||||||
|
|
||||||
|
// port 的名字
|
||||||
port_desc_array.push(port.name.to_string());
|
port_desc_array.push(port.name.to_string());
|
||||||
|
|
||||||
let port_desc = port_desc_array.join("");
|
let port_desc = port_desc_array.join("");
|
||||||
if i == port_num - 1 {
|
if i == port_num - 1 {
|
||||||
codes.push(format!("\t{port_desc}"));
|
codes.push(format!("\t{port_desc}"));
|
||||||
|
@ -33,16 +33,21 @@ pub fn hover(server: &LSPServer, params: &HoverParams) -> Option<Hover> {
|
|||||||
return Some(hover);
|
return Some(hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// info!("enter hover_position_port_param");
|
||||||
// match positional port param
|
// match positional port param
|
||||||
if let Some(hover) = hover_position_port_param(server, &line_text, doc, pos, &language_id) {
|
if let Some(hover) = hover_position_port_param(server, &line_text, doc, pos, &language_id) {
|
||||||
return Some(hover);
|
return Some(hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// info!("enter hover_module_declaration");
|
||||||
// match module name
|
// match module name
|
||||||
if let Some(hover) = hover_module_declaration(server, &token, &language_id) {
|
if let Some(hover) = hover_module_declaration(server, &token, &language_id) {
|
||||||
|
// info!("[LSPServer] in hover: get module hover");
|
||||||
|
if hover_for_module(server, pos, doc) {
|
||||||
|
// info!("[LSPServer] in hover: it is instance");
|
||||||
return Some(hover);
|
return Some(hover);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// match digit 5'b00110
|
// match digit 5'b00110
|
||||||
if let Some(hover) = hover_format_digit(&line_text, pos, &language_id) {
|
if let Some(hover) = hover_format_digit(&line_text, pos, &language_id) {
|
||||||
@ -290,3 +295,28 @@ fn hover_common_symbol(
|
|||||||
make_hover_with_comment(&file.text, def_line, &language_id, false)
|
make_hover_with_comment(&file.text, def_line, &language_id, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hover_for_module(server: &LSPServer, pos: Position, doc: &Url) -> bool {
|
||||||
|
let pathbuf = PathBuf::from_str(doc.path()).unwrap();
|
||||||
|
let pathbuf = to_escape_path(&pathbuf);
|
||||||
|
let path_string = pathbuf.to_str().unwrap().replace("\\", "/");
|
||||||
|
let hdlparam = server.srcs.hdl_param.clone();
|
||||||
|
|
||||||
|
let find_instance_range = |_: &Module, instance: &Instance| {
|
||||||
|
// info!("instance start pos: {:#?}", instance.range.start);
|
||||||
|
pos.line == instance.range.start.line
|
||||||
|
};
|
||||||
|
let find_module_range = |module: &Module| {
|
||||||
|
pos.line == module.range.start.line
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(_) = hdlparam.walk_module(&path_string, find_module_range) {
|
||||||
|
// info!("[LSPServer] in hover: it is module");
|
||||||
|
true
|
||||||
|
} else if let Some(_) = hdlparam.walk_instantiation(&path_string, find_instance_range) {
|
||||||
|
// info!("[LSPServer] in hover: it is instance");
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
// info!("[LSPServer] in hover: it is not instance");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
27
src/inlay_hint/mod.rs
Normal file
27
src/inlay_hint/mod.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use crate::server::LSPServer;
|
||||||
|
use crate::utils::*;
|
||||||
|
#[allow(unused)]
|
||||||
|
use log::info;
|
||||||
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
|
mod sv;
|
||||||
|
mod vhdl;
|
||||||
|
|
||||||
|
impl LSPServer {
|
||||||
|
pub fn inlay_hint(&self, params: InlayHintParams) -> Option<Vec<InlayHint>> {
|
||||||
|
let language_id = get_language_id_by_uri(¶ms.text_document.uri);
|
||||||
|
match language_id.as_str() {
|
||||||
|
"vhdl" => vhdl::inlay_hint(
|
||||||
|
self,
|
||||||
|
¶ms
|
||||||
|
),
|
||||||
|
|
||||||
|
"verilog" | "systemverilog" => sv::inlay_hint(
|
||||||
|
self,
|
||||||
|
¶ms
|
||||||
|
),
|
||||||
|
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
110
src/inlay_hint/sv.rs
Normal file
110
src/inlay_hint/sv.rs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
use std::{path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
|
use crate::{core, server::LSPServer};
|
||||||
|
#[allow(unused)]
|
||||||
|
use log::info;
|
||||||
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
|
use super::to_escape_path;
|
||||||
|
|
||||||
|
pub fn inlay_hint(server: &LSPServer, params: &InlayHintParams) -> Option<Vec<InlayHint>> {
|
||||||
|
let uri = ¶ms.text_document.uri;
|
||||||
|
let path = PathBuf::from_str(uri.path()).unwrap();
|
||||||
|
let path = to_escape_path(&path);
|
||||||
|
let path_string = path.to_str().unwrap();
|
||||||
|
let visible_range = core::hdlparam::Range::from_lsp_range(¶ms.range);
|
||||||
|
|
||||||
|
info!("enter hints");
|
||||||
|
|
||||||
|
let fast_map = server.srcs.hdl_param.path_to_hdl_file.read().unwrap();
|
||||||
|
// 先找到 当前 所在的 hdlfile
|
||||||
|
if let Some(hdl_file) = &fast_map.get(path_string) {
|
||||||
|
info!("enter some");
|
||||||
|
|
||||||
|
let fast = &hdl_file.fast;
|
||||||
|
let mut hints = Vec::<InlayHint>::new();
|
||||||
|
// 制作例化模块的 hint
|
||||||
|
for module in &fast.content {
|
||||||
|
for instance in &module.instances {
|
||||||
|
// 根据在可见视图外面的 range 就不管了
|
||||||
|
if is_visible_range(&instance.instparams, &visible_range) {
|
||||||
|
hints.extend(make_instparam_hints(params, instance));
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_visible_range(&instance.instports, &visible_range) {
|
||||||
|
hints.extend(make_instport_hints(params, instance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(hints);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_visible_range(
|
||||||
|
target_range: &Option<core::hdlparam::Range>,
|
||||||
|
visible_range: &core::hdlparam::Range
|
||||||
|
) -> bool {
|
||||||
|
if let Some(target_range) = target_range {
|
||||||
|
if target_range.before(visible_range) || target_range.after(visible_range) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_instparam_hints(
|
||||||
|
params: &InlayHintParams,
|
||||||
|
instance: &core::hdlparam::Instance
|
||||||
|
) -> Vec<InlayHint> {
|
||||||
|
let mut hints = Vec::<InlayHint>::new();
|
||||||
|
|
||||||
|
|
||||||
|
hints
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_instport_hints(
|
||||||
|
params: &InlayHintParams,
|
||||||
|
instance: &core::hdlparam::Instance
|
||||||
|
) -> Vec<InlayHint> {
|
||||||
|
let mut hints = Vec::<InlayHint>::new();
|
||||||
|
for port_assigment in &instance.intstport_assignments {
|
||||||
|
let port_desc = MarkupContent {
|
||||||
|
kind: MarkupKind::Markdown,
|
||||||
|
value: format!("```verilog\n{:?}\n```", port_assigment.port)
|
||||||
|
};
|
||||||
|
|
||||||
|
let hint = InlayHint {
|
||||||
|
position: port_assigment.range.to_lsp_range().start,
|
||||||
|
label: InlayHintLabel::String("start".to_string()),
|
||||||
|
padding_left: Some(true),
|
||||||
|
padding_right: Some(true),
|
||||||
|
kind: Some(InlayHintKind::PARAMETER),
|
||||||
|
text_edits: None,
|
||||||
|
tooltip: Some(InlayHintTooltip::MarkupContent(port_desc)),
|
||||||
|
data: None
|
||||||
|
};
|
||||||
|
hints.push(hint);
|
||||||
|
|
||||||
|
let port_desc = MarkupContent {
|
||||||
|
kind: MarkupKind::Markdown,
|
||||||
|
value: format!("```verilog\n{:?}\n```", port_assigment.port)
|
||||||
|
};
|
||||||
|
let hint = InlayHint {
|
||||||
|
position: port_assigment.range.to_lsp_range().end,
|
||||||
|
label: InlayHintLabel::String("end".to_string()),
|
||||||
|
padding_left: Some(true),
|
||||||
|
padding_right: Some(true),
|
||||||
|
kind: Some(InlayHintKind::PARAMETER),
|
||||||
|
text_edits: None,
|
||||||
|
tooltip: Some(InlayHintTooltip::MarkupContent(port_desc)),
|
||||||
|
data: None
|
||||||
|
};
|
||||||
|
hints.push(hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
hints
|
||||||
|
}
|
8
src/inlay_hint/vhdl.rs
Normal file
8
src/inlay_hint/vhdl.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
use crate::server::LSPServer;
|
||||||
|
#[allow(unused)]
|
||||||
|
use log::info;
|
||||||
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
|
pub fn inlay_hint(server: &LSPServer, params: &InlayHintParams) -> Option<Vec<InlayHint>> {
|
||||||
|
None
|
||||||
|
}
|
@ -18,6 +18,9 @@ pub mod document_symbol;
|
|||||||
// 语法高亮
|
// 语法高亮
|
||||||
pub mod document_highlight;
|
pub mod document_highlight;
|
||||||
|
|
||||||
|
// 内部提示
|
||||||
|
pub mod inlay_hint;
|
||||||
|
|
||||||
// 诊断
|
// 诊断
|
||||||
pub mod diagnostics;
|
pub mod diagnostics;
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ mod definition;
|
|||||||
mod hover;
|
mod hover;
|
||||||
mod document_symbol;
|
mod document_symbol;
|
||||||
mod document_highlight;
|
mod document_highlight;
|
||||||
|
mod inlay_hint;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod diagnostics;
|
mod diagnostics;
|
||||||
mod format;
|
mod format;
|
||||||
@ -33,7 +34,7 @@ async fn main() {
|
|||||||
.start()
|
.start()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
info!("launch Digital LSP");
|
info!("launch Digital LSP, version: 0.4.0");
|
||||||
|
|
||||||
let stdin = tokio::io::stdin();
|
let stdin = tokio::io::stdin();
|
||||||
let stdout = tokio::io::stdout();
|
let stdout = tokio::io::stdout();
|
||||||
|
@ -4,7 +4,6 @@ use crate::completion::keyword::*;
|
|||||||
use flexi_logger::LoggerHandle;
|
use flexi_logger::LoggerHandle;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::{debug, info, warn};
|
use log::{debug, info, warn};
|
||||||
use notification::DidDeleteFiles;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
use std::sync::{Mutex, RwLock};
|
use std::sync::{Mutex, RwLock};
|
||||||
@ -214,12 +213,13 @@ impl LanguageServer for Backend {
|
|||||||
completion_provider: Some(completion_provider),
|
completion_provider: Some(completion_provider),
|
||||||
definition_provider: Some(OneOf::Left(true)),
|
definition_provider: Some(OneOf::Left(true)),
|
||||||
hover_provider: Some(HoverProviderCapability::Simple(true)),
|
hover_provider: Some(HoverProviderCapability::Simple(true)),
|
||||||
|
// inlay_hint_provider: Some(OneOf::Left(true)),
|
||||||
document_symbol_provider: Some(OneOf::Left(true)),
|
document_symbol_provider: Some(OneOf::Left(true)),
|
||||||
document_highlight_provider: Some(OneOf::Left(true)),
|
document_highlight_provider: Some(OneOf::Left(true)),
|
||||||
..ServerCapabilities::default()
|
..ServerCapabilities::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(InitializeResult { server_info, capabilities })
|
Ok(InitializeResult::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn initialized(&self, _: InitializedParams) {
|
async fn initialized(&self, _: InitializedParams) {
|
||||||
@ -280,13 +280,6 @@ impl LanguageServer for Backend {
|
|||||||
Ok(self.server.hover(params))
|
Ok(self.server.hover(params))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn document_symbol(
|
|
||||||
&self,
|
|
||||||
params: DocumentSymbolParams,
|
|
||||||
) -> Result<Option<DocumentSymbolResponse>> {
|
|
||||||
Ok(self.server.document_symbol(params))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn formatting(&self, params: DocumentFormattingParams) -> Result<Option<Vec<TextEdit>>> {
|
async fn formatting(&self, params: DocumentFormattingParams) -> Result<Option<Vec<TextEdit>>> {
|
||||||
Ok(self.server.formatting(params))
|
Ok(self.server.formatting(params))
|
||||||
}
|
}
|
||||||
@ -298,10 +291,27 @@ impl LanguageServer for Backend {
|
|||||||
Ok(self.server.range_formatting(params))
|
Ok(self.server.range_formatting(params))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn document_symbol(
|
||||||
|
&self,
|
||||||
|
params: DocumentSymbolParams,
|
||||||
|
) -> Result<Option<DocumentSymbolResponse>> {
|
||||||
|
info!("enter document");
|
||||||
|
Ok(self.server.document_symbol(params))
|
||||||
|
}
|
||||||
|
|
||||||
async fn document_highlight(
|
async fn document_highlight(
|
||||||
&self,
|
&self,
|
||||||
params: DocumentHighlightParams,
|
params: DocumentHighlightParams,
|
||||||
) -> Result<Option<Vec<DocumentHighlight>>> {
|
) -> Result<Option<Vec<DocumentHighlight>>> {
|
||||||
|
info!("enter highlight");
|
||||||
Ok(self.server.document_highlight(params))
|
Ok(self.server.document_highlight(params))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn inlay_hint(
|
||||||
|
&self,
|
||||||
|
params: InlayHintParams
|
||||||
|
) -> Result<Option<Vec<InlayHint>>> {
|
||||||
|
info!("enter inlay_hint");
|
||||||
|
Ok(self.server.inlay_hint(params))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 21f3e497e88a108d15be75ea7e2f0f1a409c6e1d
|
Subproject commit b6ae8b8a1ff22609e2a837b12dd798226f299f71
|
Loading…
x
Reference in New Issue
Block a user