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"
|
||||
percent-encoding = "2.1.0"
|
||||
log = "0.4.19"
|
||||
tower-lsp = "0.20.0"
|
||||
tower-lsp = { version = "0.20.0", features = ["proposed"]}
|
||||
flexi_logger = "0.29.0"
|
||||
ropey = "1.6.0"
|
||||
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 ropey::{Rope, RopeSlice};
|
||||
use tower_lsp::lsp_types::*;
|
||||
@ -26,6 +26,7 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<Compl
|
||||
|
||||
let response = match ¶ms.context {
|
||||
Some(context) => match context.trigger_kind {
|
||||
// 特殊字符触发
|
||||
CompletionTriggerKind::TRIGGER_CHARACTER => {
|
||||
// info!("trigger character");
|
||||
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::INVOKED => {
|
||||
let mut comps = server.srcs.get_completions(
|
||||
&token,
|
||||
@ -61,6 +63,8 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<Compl
|
||||
&doc.text_document.uri,
|
||||
)?;
|
||||
|
||||
info!("current completion token: {}", token);
|
||||
|
||||
// complete keywords
|
||||
comps.items.extend::<Vec<CompletionItem>>(
|
||||
server.key_comps
|
||||
@ -69,7 +73,15 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<Compl
|
||||
.cloned()
|
||||
.collect(),
|
||||
);
|
||||
|
||||
// 加入例化自动补全的
|
||||
comps.items.extend::<Vec<CompletionItem>>(
|
||||
make_module_completions(server, &token, &language_id)
|
||||
);
|
||||
|
||||
comps.items.dedup_by_key(|i| i.label.clone());
|
||||
|
||||
|
||||
// info!("invoked return comps {:?}", comps);
|
||||
Some(comps)
|
||||
}
|
||||
@ -107,6 +119,7 @@ pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<Compl
|
||||
.collect(),
|
||||
);
|
||||
comps.items.dedup_by_key(|i| i.label.clone());
|
||||
|
||||
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::Range as LspRange;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, PartialEq, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize)]
|
||||
pub struct Position {
|
||||
pub line: u32,
|
||||
pub character: u32
|
||||
@ -17,9 +17,13 @@ impl Position {
|
||||
pub fn to_lsp_position(&self) -> LspPosition {
|
||||
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 start: Position,
|
||||
pub end: Position
|
||||
@ -34,11 +38,39 @@ impl Range {
|
||||
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 内
|
||||
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
|
||||
}
|
||||
|
||||
#[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 进行偏移操作
|
||||
pub fn affine(&mut self, line_offset: i32, character_offset: i32) -> &Range {
|
||||
if line_offset > 0 {
|
||||
@ -59,8 +91,24 @@ impl Range {
|
||||
|
||||
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 {
|
||||
if pos1.line > pos2.line {
|
||||
1
|
||||
@ -94,18 +142,27 @@ pub struct Parameter {
|
||||
pub range: Range
|
||||
}
|
||||
|
||||
// #[derive(Debug, Serialize)]
|
||||
// pub struct InstPort {
|
||||
// pub name: String,
|
||||
// pub range: Range
|
||||
// }
|
||||
#[derive(Debug, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize, Clone)]
|
||||
pub enum AssignType {
|
||||
Named,
|
||||
Ordered
|
||||
}
|
||||
|
||||
// #[derive(Debug, Serialize)]
|
||||
// pub struct InstParameter {
|
||||
// pub name: String,
|
||||
// pub value: String,
|
||||
// pub range: Range
|
||||
// }
|
||||
#[derive(Debug, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize, Clone)]
|
||||
pub struct InstPort {
|
||||
pub port: Option<String>,
|
||||
pub assign_val: Option<String>,
|
||||
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)]
|
||||
pub struct Instance {
|
||||
@ -113,7 +170,9 @@ pub struct Instance {
|
||||
#[serde(rename = "type")]
|
||||
pub inst_type: String,
|
||||
pub instparams: Option<Range>,
|
||||
pub intstparam_assignments: Vec<InstParameter>,
|
||||
pub instports: Option<Range>,
|
||||
pub intstport_assignments: Vec<InstPort>,
|
||||
pub range: Range
|
||||
}
|
||||
|
||||
@ -141,6 +200,7 @@ impl Instance {
|
||||
self.range.clone()
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn gen_dot_completion_param_range(&self) -> Range {
|
||||
// TODO: 精心调制这个方法
|
||||
if let Some(param_range) = &self.instparams {
|
||||
@ -211,34 +271,23 @@ pub struct FastHdlparam {
|
||||
}
|
||||
|
||||
impl FastHdlparam {
|
||||
pub fn add_define(&mut self, name: &str, replacement: &str, start_line: u32, start_character: u32,
|
||||
end_line: u32, end_character: u32, params: Vec<DefineParam>) {
|
||||
pub fn add_define(&mut self, name: &str, replacement: &str, range: Range, params: Vec<DefineParam>) {
|
||||
let define = Define {
|
||||
name: name.to_string(),
|
||||
replacement: replacement.to_string(),
|
||||
range: Range {
|
||||
start: Position { line: start_line, character: start_character },
|
||||
end: Position { line: end_line, character: end_character }
|
||||
},
|
||||
range,
|
||||
params
|
||||
};
|
||||
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 {
|
||||
name: name.to_string(),
|
||||
params: Vec::new(),
|
||||
ports: Vec::new(),
|
||||
instances: Vec::new(),
|
||||
range: Range {
|
||||
start: Position {
|
||||
line, character
|
||||
},
|
||||
end: Position {
|
||||
line, character: end_character
|
||||
}
|
||||
}
|
||||
range
|
||||
};
|
||||
self.content.push(module);
|
||||
}
|
||||
@ -250,29 +299,20 @@ impl FastHdlparam {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_parameter(&mut self, name: &str, net_type: &str, init: &str,
|
||||
start_line: u32, start_character: u32, end_line: u32, end_character: u32) {
|
||||
pub fn add_parameter(&mut self, name: &str, net_type: &str, init: &str, range: Range) {
|
||||
if let Some(last_module) = self.content.last_mut() {
|
||||
let parameter = Parameter {
|
||||
name: name.to_string(),
|
||||
net_type: net_type.to_string(),
|
||||
init: init.to_string(),
|
||||
range: Range {
|
||||
start: Position {
|
||||
line: start_line, character: start_character
|
||||
},
|
||||
end: Position {
|
||||
line:end_line, character: end_character
|
||||
}
|
||||
}
|
||||
range
|
||||
};
|
||||
last_module.params.push(parameter);
|
||||
last_module.params.dedup();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_port(&mut self, name: &str, dir_type: &str, net_type: &str, width: &str,
|
||||
start_line: u32, start_character: u32, end_line: u32, end_character: u32) {
|
||||
pub fn add_port(&mut self, name: &str, dir_type: &str, net_type: &str, width: &str, range: Range) {
|
||||
if let Some(last_module) = self.content.last_mut() {
|
||||
let port = Port {
|
||||
name: name.to_string(),
|
||||
@ -280,63 +320,24 @@ impl FastHdlparam {
|
||||
net_type: net_type.to_string(),
|
||||
width: width.to_string(),
|
||||
signed: "unsigned".to_string(),
|
||||
range: Range {
|
||||
start: Position {
|
||||
line: start_line, character: start_character
|
||||
},
|
||||
end: Position {
|
||||
line:end_line, character: end_character
|
||||
}
|
||||
}
|
||||
range
|
||||
};
|
||||
last_module.ports.push(port);
|
||||
last_module.ports.dedup();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_instance(&mut self, name: &str, inst_type: &str, line: u32, character: u32, end_character: u32,
|
||||
param_start_line: u32, param_start_character: u32, param_end_line: u32, param_end_character: u32,
|
||||
port_start_line: u32, port_start_character: u32, port_end_line: u32, port_end_character: u32 ) {
|
||||
pub fn add_instance(&mut self, name: &str, inst_type: &str, range: Range,
|
||||
param_range: Option<Range>, params_assign: Vec<InstParameter>, port_range: Option<Range>, ports_assign: Vec<InstPort>) {
|
||||
if let Some(last_module) = self.content.last_mut() {
|
||||
let instance = Instance {
|
||||
name: name.to_string(),
|
||||
inst_type: inst_type.to_string(),
|
||||
instparams: if param_start_line == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
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
|
||||
}
|
||||
}
|
||||
instparams: param_range,
|
||||
intstparam_assignments: params_assign,
|
||||
instports: port_range,
|
||||
intstport_assignments: ports_assign,
|
||||
range
|
||||
};
|
||||
last_module.instances.push(instance);
|
||||
}
|
||||
@ -355,6 +356,8 @@ pub struct HdlParam {
|
||||
pub module_name_to_path: RwLock<HashMap<String, String>>
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl HdlParam {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
@ -406,6 +409,19 @@ impl HdlParam {
|
||||
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,并根据条件返回
|
||||
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();
|
||||
|
@ -1,4 +1,3 @@
|
||||
use std::collections::HashSet;
|
||||
use std::fs::{self, File};
|
||||
use std::io::BufRead;
|
||||
use std::io::BufReader;
|
||||
@ -9,10 +8,11 @@ use ropey::Rope;
|
||||
use tower_lsp::lsp_types::Url;
|
||||
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 super::hdlparam::{FastHdlparam, Macro};
|
||||
use super::hdlparam::{self, FastHdlparam, InstParameter, InstPort, Macro};
|
||||
|
||||
macro_rules! advance_until_leave {
|
||||
($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)]
|
||||
pub fn sv_parser(path: &str) -> Option<FastHdlparam> {
|
||||
// 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 = "";
|
||||
|
||||
// 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);
|
||||
// &SyntaxTree is iterable
|
||||
let doc = Rope::from_str(syntax_tree.text.text());
|
||||
|
||||
for node in syntax_tree {
|
||||
match node {
|
||||
RefNode::TextMacroDefinition(x) => {
|
||||
if let Some(start) = unwrap_node!(x, TextMacroDefinition) {
|
||||
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 = 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;
|
||||
(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 {
|
||||
(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) => {
|
||||
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 = 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();
|
||||
hdlparam.new_module(name, line, character, end_character);
|
||||
hdlparam.new_module(name, module_range);
|
||||
}
|
||||
RefNode::ParameterDeclaration(param_dec) => {
|
||||
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) => {
|
||||
let keyword_locate = &x.nodes.0.nodes.0;
|
||||
// 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) {
|
||||
Some(RefNode::DataType(data_type)) => {
|
||||
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() {
|
||||
let (start_line, start_character) = if index != 0 {
|
||||
(loc.line as u32, get_column_by_offset(&content, loc.offset) as u32)
|
||||
let start_pos = if index != 0 {
|
||||
get_position(&doc, loc.clone(), 0)
|
||||
} 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);
|
||||
hdlparam.add_parameter(name, net_type, init, start_line, start_character, end_line, end_character);
|
||||
let end_pos = get_position(&doc, loc.clone(), loc.len);
|
||||
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) {
|
||||
let id = get_identifier(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) {
|
||||
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 = get_identifier(id).unwrap();
|
||||
let name = syntax_tree.get_str(&id).unwrap();
|
||||
let (start_line, start_character, end_line, end_character) =
|
||||
(dir_line, dir_character, id.line, (get_column_by_offset(&content, id.offset) + id.len) as u32);
|
||||
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(), start_line, start_character,
|
||||
end_line, end_character);
|
||||
hdlparam.add_port(name, dir_type, net_type, width.as_str(), port_range);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -255,17 +240,17 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re
|
||||
if let Some(id) = unwrap_node!(x, PortIdentifier) {
|
||||
let name_locate = get_identifier(id).unwrap();
|
||||
let name = syntax_tree.get_str(&name_locate).unwrap();
|
||||
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 character = get_column_by_offset(&content, name_locate.offset);
|
||||
let end_pos = get_position(&doc, name_locate, name_locate.len);
|
||||
|
||||
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 dir_locate = get_identifier(id).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 {
|
||||
(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 {
|
||||
@ -294,35 +279,42 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re
|
||||
_ => "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) => {
|
||||
if let Some(id) = unwrap_node!(x, ModuleIdentifier) {
|
||||
let id = get_identifier(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) {
|
||||
let hier_node = id.clone();
|
||||
let id = get_identifier(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) = match unwrap_node!(x, ParameterValueAssignment) {
|
||||
let param_range = match unwrap_node!(x, ParameterValueAssignment) {
|
||||
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,
|
||||
port_end_line, port_end_character) = get_port_parameter_range(&content, hier_node);
|
||||
let inst_param_assignments = if let Some(param_node) = unwrap_node!(x, ParameterValueAssignment) {
|
||||
get_instance_params(syntax_tree, &doc, param_node)
|
||||
} else {
|
||||
Vec::<InstParameter>::new()
|
||||
};
|
||||
|
||||
hdlparam.add_instance(name, inst_type, line, character, end_character,
|
||||
param_start_line, param_start_character, param_end_line, param_end_character,
|
||||
port_start_line, port_start_character, port_end_line, port_end_character
|
||||
let inst_port_assignments = get_instance_ports(&syntax_tree, &doc, hier_node.clone());
|
||||
let port_range = get_pp_range(&doc, hier_node).to_option();
|
||||
|
||||
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 = get_identifier(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) {
|
||||
Some(id) => {
|
||||
let gate_node = id.clone();
|
||||
let id = get_identifier(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 (port_start_line, port_start_character,
|
||||
port_end_line, port_end_character) = get_port_parameter_range(&content, gate_node);
|
||||
let param_range = None;
|
||||
let inst_port_assignments = get_instance_ports(&syntax_tree, &doc, gate_node.clone());
|
||||
let port_range = get_pp_range(&doc, gate_node).to_option();
|
||||
|
||||
hdlparam.add_instance(name, inst_type, line, character, end_character,
|
||||
param_start_line, param_start_character, param_end_line, param_end_character,
|
||||
port_start_line, port_start_character, port_end_line, port_end_character
|
||||
hdlparam.add_instance(
|
||||
name, inst_type, inst_range,
|
||||
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)
|
||||
}
|
||||
|
||||
fn get_port_parameter_range(content: &[String], node: RefNode) -> (u32, u32, u32, u32) {
|
||||
let locate = get_first_last_locate(node);
|
||||
if locate.is_none() {
|
||||
(0,0,0,0)
|
||||
// 获取 port 或者 param 的 range
|
||||
/// 返回的四元组:(start_line, start_character, end_line, end_character)
|
||||
fn get_pp_range(doc: &Rope, node: RefNode) -> Range {
|
||||
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 {
|
||||
(
|
||||
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
|
||||
)
|
||||
Range { start: Position { line: 0, character: 0}, end: Position { line: 0, character: 0} }
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 };
|
||||
|
||||
for n in node {
|
||||
match n {
|
||||
RefNode::Symbol(x) => {
|
||||
if let RefNode::Symbol(x) = n {
|
||||
let locate = x.nodes.0;
|
||||
if locate != last_locate { last_locate = locate; }
|
||||
if first_locate.offset == 0 { first_locate = locate; };
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
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>) {
|
||||
let mut last_locate = Locate { offset: 0, line: 0, len: 0 };
|
||||
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> {
|
||||
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(
|
||||
tree: &SyntaxTree,
|
||||
_: &ParamAssignment,
|
||||
|
@ -206,6 +206,8 @@ fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> {
|
||||
inst_type: get_value(&tokens[i+1]),
|
||||
instports: None,
|
||||
instparams: None,
|
||||
intstport_assignments: Vec::new(),
|
||||
intstparam_assignments: Vec::new(),
|
||||
range: Range {
|
||||
start: Position {
|
||||
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]),
|
||||
instports: None,
|
||||
instparams: None,
|
||||
intstport_assignments: Vec::new(),
|
||||
intstparam_assignments: Vec::new(),
|
||||
range: Range {
|
||||
start: Position {
|
||||
line: tokens[i-1].pos.range.start.line + 1,
|
||||
@ -257,6 +261,8 @@ fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> {
|
||||
inst_type,
|
||||
instports: None,
|
||||
instparams: None,
|
||||
intstport_assignments: Vec::new(),
|
||||
intstparam_assignments: Vec::new(),
|
||||
range: Range {
|
||||
start: Position {
|
||||
line: tokens[i-1].pos.range.start.line + 1,
|
||||
|
@ -123,11 +123,8 @@ fn goto_instantiation<'a>(
|
||||
if token_name == param.name {
|
||||
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 mut target_range = param.range.to_lsp_range();
|
||||
target_range.start.line -= 1;
|
||||
target_range.start.character -= 1;
|
||||
target_range.end.line -= 1;
|
||||
target_range.end.character -= 1;
|
||||
let target_range = param.range.clone();
|
||||
let target_range = target_range.to_lsp_range();
|
||||
|
||||
let link = vec");
|
||||
let define_info = format!("Go to [Definition]({path_uri}#L{def_row}:{def_col})");
|
||||
|
||||
let port_num = module.ports.len();
|
||||
let param_num = module.params.len();
|
||||
@ -417,7 +389,6 @@ pub fn hover_module_declaration(
|
||||
let mut markdowns = Vec::<MarkedString>::new();
|
||||
markdowns.push(MarkedString::String(port_desc));
|
||||
markdowns.push(MarkedString::String(io_desc));
|
||||
markdowns.push(MarkedString::String("".to_string()));
|
||||
markdowns.push(MarkedString::String(define_info));
|
||||
markdowns.push(MarkedString::String("---".to_string()));
|
||||
|
||||
@ -441,18 +412,21 @@ pub fn hover_module_declaration(
|
||||
|
||||
|
||||
/// 根据 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 param_num = module.params.len();
|
||||
let port_num = module.ports.len();
|
||||
|
||||
if module.params.len() > 0 {
|
||||
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() {
|
||||
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" {
|
||||
param_desc_array.push(param.init.to_string());
|
||||
param_desc_array.push(format!(" = {}", param.init.to_string()));
|
||||
}
|
||||
|
||||
let param_desc = param_desc_array.join(" ");
|
||||
@ -468,23 +442,66 @@ fn make_module_profile_code(module: &crate::core::hdlparam::Module) -> String {
|
||||
}
|
||||
|
||||
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() {
|
||||
let mut port_desc_array = Vec::<String>::new();
|
||||
|
||||
// input, output, inout
|
||||
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" {
|
||||
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" {
|
||||
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" {
|
||||
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());
|
||||
let port_desc = port_desc_array.join(" ");
|
||||
|
||||
let port_desc = port_desc_array.join("");
|
||||
if i == port_num - 1 {
|
||||
codes.push(format!("\t{port_desc}"));
|
||||
} else {
|
||||
|
@ -33,16 +33,21 @@ pub fn hover(server: &LSPServer, params: &HoverParams) -> Option<Hover> {
|
||||
return Some(hover);
|
||||
}
|
||||
|
||||
|
||||
// info!("enter hover_position_port_param");
|
||||
// match positional port param
|
||||
if let Some(hover) = hover_position_port_param(server, &line_text, doc, pos, &language_id) {
|
||||
return Some(hover);
|
||||
}
|
||||
|
||||
// info!("enter hover_module_declaration");
|
||||
// match module name
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// match digit 5'b00110
|
||||
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)
|
||||
}
|
||||
|
||||
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 inlay_hint;
|
||||
|
||||
// 诊断
|
||||
pub mod diagnostics;
|
||||
|
||||
|
@ -13,6 +13,7 @@ mod definition;
|
||||
mod hover;
|
||||
mod document_symbol;
|
||||
mod document_highlight;
|
||||
mod inlay_hint;
|
||||
mod utils;
|
||||
mod diagnostics;
|
||||
mod format;
|
||||
@ -33,7 +34,7 @@ async fn main() {
|
||||
.start()
|
||||
.unwrap();
|
||||
|
||||
info!("launch Digital LSP");
|
||||
info!("launch Digital LSP, version: 0.4.0");
|
||||
|
||||
let stdin = tokio::io::stdin();
|
||||
let stdout = tokio::io::stdout();
|
||||
|
@ -4,7 +4,6 @@ use crate::completion::keyword::*;
|
||||
use flexi_logger::LoggerHandle;
|
||||
#[allow(unused)]
|
||||
use log::{debug, info, warn};
|
||||
use notification::DidDeleteFiles;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::string::ToString;
|
||||
use std::sync::{Mutex, RwLock};
|
||||
@ -214,12 +213,13 @@ impl LanguageServer for Backend {
|
||||
completion_provider: Some(completion_provider),
|
||||
definition_provider: Some(OneOf::Left(true)),
|
||||
hover_provider: Some(HoverProviderCapability::Simple(true)),
|
||||
// inlay_hint_provider: Some(OneOf::Left(true)),
|
||||
document_symbol_provider: Some(OneOf::Left(true)),
|
||||
document_highlight_provider: Some(OneOf::Left(true)),
|
||||
..ServerCapabilities::default()
|
||||
};
|
||||
|
||||
Ok(InitializeResult { server_info, capabilities })
|
||||
Ok(InitializeResult::default())
|
||||
}
|
||||
|
||||
async fn initialized(&self, _: InitializedParams) {
|
||||
@ -280,13 +280,6 @@ impl LanguageServer for Backend {
|
||||
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>>> {
|
||||
Ok(self.server.formatting(params))
|
||||
}
|
||||
@ -298,10 +291,27 @@ impl LanguageServer for Backend {
|
||||
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(
|
||||
&self,
|
||||
params: DocumentHighlightParams,
|
||||
) -> Result<Option<Vec<DocumentHighlight>>> {
|
||||
info!("enter highlight");
|
||||
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