Compare commits

..

11 Commits

Author SHA1 Message Date
2dd7f98d5f use proposed tower lsp 2024-10-31 15:35:17 +08:00
9f50823429 修复 Rope 后,自增自减导致 lsp 行为异常的错误 2024-10-30 14:52:43 +08:00
light-ly
23816af899 optimize code style | remove content 2024-10-29 23:58:03 +08:00
light-ly
e31f8ec8ac fix module and inst range 2024-10-29 22:50:49 +08:00
light-ly
0c0ee48ae5 add param assignments 2024-10-29 22:30:21 +08:00
light-ly
3303b65c3f add port assignment 2024-10-29 21:46:26 +08:00
82a21ccf34 完成 hover 视图对齐 2024-10-28 23:01:37 +08:00
8d733112c4 实现例化自动补全 2024-10-28 18:08:48 +08:00
4bde6263a3 Merge branch 'main' of https://github.com/Digital-EDA/digital-lsp-server 2024-10-26 22:33:09 +08:00
7f5ed156a5 save 2024-10-26 22:33:05 +08:00
light-ly
314540c7e6 fix hover bug 2024-10-26 22:06:06 +08:00
16 changed files with 747 additions and 254 deletions

View File

@ -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"] }

View File

@ -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 &params.context {
Some(context) => match context.trigger_kind {
// 特殊字符触发
CompletionTriggerKind::TRIGGER_CHARACTER => {
// info!("trigger character");
let trigger_character = context.trigger_character.clone().unwrap();
@ -54,12 +55,15 @@ 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,
file.text.pos_to_byte(&doc.position),
&doc.text_document.uri,
)?;
info!("current completion token: {}", token);
// complete keywords
comps.items.extend::<Vec<CompletionItem>>(
@ -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
}

View File

@ -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 的位置关系
/// 1pos1 在 pos2 后面
/// 0pos1 和 pos2 一样
/// -1pos1 在 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();

View File

@ -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,13 +373,10 @@ 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) => {
let locate = x.nodes.0;
if locate != last_locate { last_locate = locate; }
if first_locate.offset == 0 { first_locate = locate; };
}
_ => ()
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; };
}
}
@ -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(&param_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 lentghreturn 1
}
fn param_assignment(
tree: &SyntaxTree,
_: &ParamAssignment,

View File

@ -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,

View File

@ -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![LocationLink {
target_uri,
@ -155,8 +152,8 @@ fn goto_instantiation<'a>(
if token_name == port.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 = port.range.clone();
let target_range = target_range.affine(-1, -1).to_lsp_range();
let target_range = port.range.clone();
let target_range = target_range.to_lsp_range();
let link = vec![LocationLink {
target_uri,
@ -213,8 +210,8 @@ pub fn goto_module_declaration_definition(
let def_path = server.srcs.hdl_param.find_module_definition_path(&module.name).unwrap();
let target_uri = Url::from_file_path(PathBuf::from_str(&def_path).unwrap()).unwrap();
let mut target_range = module.range.clone();
let target_range = target_range.affine(-1, -1).to_lsp_range();
let target_range = module.range.clone();
let target_range = target_range.to_lsp_range();
let link = vec![LocationLink {
target_uri,

View File

@ -30,7 +30,6 @@ pub fn goto_definition(server: &LSPServer, params: &GotoDefinitionParams) -> Opt
}
// match instance
let scope_tree = server.srcs.scope_tree.read().ok()?;
// match position port & param

View File

@ -223,7 +223,9 @@ fn goto_instantiation<'a>(
None => return None
};
info!("position param find belong module: {:?}", module);
// info!("current pos: {pos:#?}");
// info!("param_range: {param_range:#?}");
// info!("position param find belong module: {:?}", module);
for param in &module.params {
if token_name == param.name {
@ -242,7 +244,9 @@ fn goto_instantiation<'a>(
None => return None
};
info!("position port find belong module: {:?}", module);
// info!("current pos: {pos:#?}");
// info!("port_range: {port_range:#?}");
// info!("position port find belong module: {:?}", module);
for port in &module.ports {
if token_name == port.name {
@ -342,38 +346,6 @@ pub fn hover_module_declaration(
token_name: &str,
language_id: &str
) -> Option<Hover> {
// let module_info = match definition.def_type {
// DefinitionType::GenericScope => {
// let pathbuf = PathBuf::from_str(definition.url.path()).unwrap();
// let pathbuf = to_escape_path(&pathbuf);
// let path_string = pathbuf.to_str().unwrap();
// let hdlparam = &server.srcs.hdl_param;
// let search_result = || {
// if let Some(hdl_file) = hdlparam.path_to_hdl_file.read().unwrap().get(path_string) {
// for module in &hdl_file.fast.content {
// if module.name == definition.ident {
// return Some((module.clone(), path_string.to_string()));
// }
// }
// }
// None
// };
// search_result()
// }
// _ => {
// let search_result = || {
// if let Some(module) = server.srcs.hdl_param.find_module_by_name(token_name) {
// let path_string = server.srcs.hdl_param.find_module_definition_path(&module.name).unwrap_or("unknown".to_string());
// return Some((module, path_string));
// }
// None
// };
// search_result()
// }
// };
let module_info = {
let search_result = || {
@ -390,7 +362,7 @@ pub fn hover_module_declaration(
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!("Definition [{path_string}]({path_uri}#L{def_row}:{def_col})");
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()));
@ -427,7 +398,7 @@ pub fn hover_module_declaration(
value: module_profile
};
markdowns.push(MarkedString::LanguageString(profile_markdown));
let hover = Hover {
contents: HoverContents::Array(markdowns),
range: None
@ -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();
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 {

View File

@ -33,15 +33,20 @@ 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) {
return Some(hover);
// 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
@ -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
View 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(&params.text_document.uri);
match language_id.as_str() {
"vhdl" => vhdl::inlay_hint(
self,
&params
),
"verilog" | "systemverilog" => sv::inlay_hint(
self,
&params
),
_ => None
}
}
}

110
src/inlay_hint/sv.rs Normal file
View 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 = &params.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(&params.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
View 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
}

View File

@ -18,6 +18,9 @@ pub mod document_symbol;
// 语法高亮
pub mod document_highlight;
// 内部提示
pub mod inlay_hint;
// 诊断
pub mod diagnostics;

View File

@ -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();

View File

@ -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