diff --git a/src/completion/sv.rs b/src/completion/sv.rs index 669dee0..0d87213 100644 --- a/src/completion/sv.rs +++ b/src/completion/sv.rs @@ -272,17 +272,24 @@ fn make_module_completions( let path_to_files = server.srcs.hdl_param.path_to_hdl_file.read().unwrap(); // 遍历 hdlparam 中所有的 modules - for (_, hdl_file) in path_to_files.iter() { + 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```", language_id, module_profile) + value: format!("```{}\n{}\n```\n{}", language_id, module_profile, define_info) }; + let item = CompletionItem { label: module.name.to_string(), @@ -290,7 +297,10 @@ fn make_module_completions( 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); diff --git a/src/core/sv_parser.rs b/src/core/sv_parser.rs index 67b77a1..b09d054 100644 --- a/src/core/sv_parser.rs +++ b/src/core/sv_parser.rs @@ -9,7 +9,7 @@ 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::sources::{recovery_sv_parse_with_retry, LSPSupport}; use crate::utils::to_escape_path; use super::hdlparam::{FastHdlparam, Macro}; @@ -114,14 +114,14 @@ 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::::new(); - + // TODO: 删除这个 content let content = syntax_tree.text.text().split('\n') .map(|s| s.to_string()) .collect::>(); // 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) => { @@ -312,13 +312,13 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re let (param_start_line, param_start_character, param_end_line, param_end_character) = match unwrap_node!(x, ParameterValueAssignment) { Some(inst_node) => { - get_port_parameter_range(&content, inst_node) + // get_port_parameter_range(&content, inst_node) + get_pp_range(&doc, inst_node) } _ => (0, 0, 0, 0) }; - let (port_start_line, port_start_character, - port_end_line, port_end_character) = get_port_parameter_range(&content, hier_node); + let (port_start_line, port_start_character, port_end_line, port_end_character) = get_pp_range(&doc, hier_node); hdlparam.add_instance(name, inst_type, line, character, end_character, param_start_line, param_start_character, param_end_line, param_end_character, @@ -361,15 +361,33 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re Ok(hdlparam) } +/// 返回的四元组:(start_line, start_character, end_line, end_character) 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) + ( 0, 0, 0, 0 ) } 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 - ) + let locate = locate.unwrap(); + let start_line = locate.0.line; + let start_character = get_column_by_offset(&content, locate.0.offset) as u32; + let end_line = locate.1.line; + let end_character = get_column_by_offset(&content, locate.1.offset + locate.1.len) as u32; + + ( start_line, start_character, end_line, end_character ) + } +} + +// 获取 port 或者 param 的 range +/// 返回的四元组:(start_line, start_character, end_line, end_character) +fn get_pp_range(doc: &Rope, node: RefNode) -> (u32, u32, u32, u32) { + if let Some(locate) = get_first_last_locate(node) { + let start_byte = locate.0.offset; + let end_byte = locate.1.offset + locate.1.len; + let start_pos = doc.byte_to_pos(start_byte); + let end_pos = doc.byte_to_pos(end_byte); + ( start_pos.line, start_pos.character, end_pos.line, end_pos.character ) + } else { + ( 0, 0, 0, 0 ) } } diff --git a/src/hover/feature.rs b/src/hover/feature.rs index d3ca398..c82815f 100644 --- a/src/hover/feature.rs +++ b/src/hover/feature.rs @@ -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 { - // 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::::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 @@ -444,15 +415,18 @@ pub fn hover_module_declaration( pub fn make_module_profile_code(module: &crate::core::hdlparam::Module) -> String { let mut codes = Vec::::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::::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 @@ pub fn make_module_profile_code(module: &crate::core::hdlparam::Module) -> Strin } 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::::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 { diff --git a/src/hover/sv.rs b/src/hover/sv.rs index 093e5c8..e4b1471 100644 --- a/src/hover/sv.rs +++ b/src/hover/sv.rs @@ -27,18 +27,20 @@ pub fn hover(server: &LSPServer, params: &HoverParams) -> Option { if let Some(hover) = hover_include(doc, &line_text, pos, &language_id) { return Some(hover); } - + // match macro if let Some(hover) = hover_macro(server, &line_text, pos, &language_id) { 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"); @@ -300,7 +302,9 @@ fn hover_for_module(server: &LSPServer, pos: Position, doc: &Url) -> bool { let pathbuf = to_escape_path(&pathbuf); let path_string = pathbuf.to_str().unwrap().replace("\\", "/"); let hdlparam = server.srcs.hdl_param.clone(); + // info!("current pos: {pos:#?}"); let find_instance_range = |_: &Module, instance: &Instance| { + // info!("instance start pos: {:#?}", instance.range.start); pos.line + 1 == instance.range.start.line }; let find_module_range = |module: &Module| {