From fcfa4b141a7f9385a5a121bd617f4626046dfec3 Mon Sep 17 00:00:00 2001 From: LSTM-Kirigaya <1193466151@qq.com> Date: Thu, 3 Oct 2024 23:57:52 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=BC=93=E5=AD=98=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rust_hdl | 2 +- src/core/hdlparam.rs | 19 +++++++++ src/hover/feature.rs | 2 +- src/hover/sv.rs | 93 ++++++++++++++++++++++++++++++++++++++++---- src/test/vhdl.rs | 23 ++++++++++- src/utils/fast.rs | 2 + src/utils/mod.rs | 46 ++++++++++++++++++++++ 7 files changed, 177 insertions(+), 10 deletions(-) diff --git a/rust_hdl b/rust_hdl index d3f01fe..0a33521 160000 --- a/rust_hdl +++ b/rust_hdl @@ -1 +1 @@ -Subproject commit d3f01fe8ec8d6d48031e3eaf043a65244297ca9c +Subproject commit 0a335218d2f8e469ed3f510d168e4cd4ad2c1057 diff --git a/src/core/hdlparam.rs b/src/core/hdlparam.rs index 365cc46..e90f8eb 100644 --- a/src/core/hdlparam.rs +++ b/src/core/hdlparam.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::sync::RwLock; +use log::info; use serde::{Deserialize, Serialize}; use tower_lsp::lsp_types::Position as LspPosition; use tower_lsp::lsp_types::Range as LspRange; @@ -323,6 +324,7 @@ impl HdlParam { } } + /// 根据 path 更新 fast pub fn update_fast(&self, path: String, fast: FastHdlparam) { let mut fast_map = self.path_to_hdl_file.write().unwrap(); // 构建映射 @@ -340,6 +342,7 @@ impl HdlParam { fast_map.insert(path, file); } + /// 根据 module 的名字,找到 module 对象,拷贝返回 pub fn find_module_by_name(&self, name: &str) -> Option { let module_name_to_path = self.module_name_to_path.read().unwrap(); if let Some(path) = module_name_to_path.get(name) { @@ -354,6 +357,7 @@ impl HdlParam { None } + /// 输入 module 名字,找到 module 定义的文件的路径 pub fn find_module_definition_path(&self, module_name: &str) -> Option { let module_name_to_path = self.module_name_to_path.read().unwrap(); if let Some(path) = module_name_to_path.get(module_name) { @@ -362,5 +366,20 @@ impl HdlParam { None } + + /// 遍历 path_string 下的所有 instance,并根据条件返回 + pub fn walk_instantiation(&self, path_string: &str, condition: impl Fn(&Module, &Instance) -> bool) -> Option { + 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 { + for inst in &def_module.instances { + if condition(def_module, inst) { + return Some(inst.clone()); + } + } + } + } + None + } } \ No newline at end of file diff --git a/src/hover/feature.rs b/src/hover/feature.rs index 58573b7..c63700c 100644 --- a/src/hover/feature.rs +++ b/src/hover/feature.rs @@ -182,7 +182,7 @@ fn make_macro_define_content(macro_define: &Define) -> String { } pub fn hover_macro(server: &LSPServer, line: &RopeSlice, pos: Position, language_id: &str) -> Option { - let macro_text_regex = Regex::new(r"[`0-9a-zA-Z]").unwrap(); + let macro_text_regex = Regex::new(r"[`_0-9a-zA-Z]").unwrap(); if let Some((macro_text, range)) = get_word_range_at_position(line, pos, macro_text_regex) { if macro_text.starts_with("`") { if let Some((macro_define, _)) = server.find_macros(¯o_text) { diff --git a/src/hover/sv.rs b/src/hover/sv.rs index 994aa3c..1057163 100644 --- a/src/hover/sv.rs +++ b/src/hover/sv.rs @@ -1,9 +1,10 @@ +use log::info; use regex::Regex; use ropey::Rope; use tower_lsp::lsp_types::*; -use crate::{server::LSPServer, sources::LSPSupport}; +use crate::{core::hdlparam::{HdlFile, Instance, Module}, hover::{to_escape_path, BracketMatchResult, BracketMatcher}, server::LSPServer, sources::LSPSupport}; use super::feature::*; -use std::sync::RwLockReadGuard; +use std::{path::PathBuf, str::FromStr, sync::RwLockReadGuard}; use crate::definition::*; @@ -60,7 +61,7 @@ pub fn hover(server: &LSPServer, params: &HoverParams) -> Option { None } -fn make_hover_with_comment(doc: &Rope, line: usize, language_id: &str) -> Option { +fn make_hover_with_comment(doc: &Rope, line: usize, language_id: &str, exclude_code: bool) -> Option { if line == 0 { let language_string = LanguageString { language: language_id.to_string(), @@ -112,6 +113,8 @@ fn make_hover_with_comment(doc: &Rope, line: usize, language_id: &str) -> Option if line.starts_with("/*") { line = line.strip_prefix("/*").unwrap().trim().to_string(); + } else if line.starts_with("//") { + line = line.strip_prefix("//").unwrap().trim().to_string(); } if line.ends_with("*/") { @@ -165,7 +168,7 @@ fn make_hover_with_comment(doc: &Rope, line: usize, language_id: &str) -> Option language: language_id.to_string(), value: code })); - comment_markdowns.insert(0, MarkedString::String(comment)); + comment_markdowns.insert(0, MarkedString::String(comment.trim().to_string())); } else { // 这行只有代码,没有注释 comment_markdowns.push(MarkedString::LanguageString(LanguageString { @@ -175,13 +178,34 @@ fn make_hover_with_comment(doc: &Rope, line: usize, language_id: &str) -> Option } } else { // 否则,都是上方的注释 - comment_markdowns.push(MarkedString::String(line_hover)); + comment_markdowns.push(MarkedString::String(line_hover.trim().to_string())); + } + } + + // 合并其中的 markdown + let mut merge_markdowns = Vec::::new(); + let mut string_buffer = String::new(); + for (_, md) in comment_markdowns.iter().enumerate() { + match md { + MarkedString::String(markdown_string) => { + string_buffer.push_str(format!("{}\n", markdown_string.trim()).as_str()); + } + MarkedString::LanguageString(code) => { + if !string_buffer.is_empty() { + merge_markdowns.push(MarkedString::String(string_buffer.to_string())); + string_buffer.clear(); + } + + if !exclude_code { + merge_markdowns.push(MarkedString::LanguageString(code.to_owned())); + } + } } } if comment_markdowns.len() > 0 { return Some(Hover { - contents: HoverContents::Array(comment_markdowns), + contents: HoverContents::Array(merge_markdowns), range: None }); } @@ -207,8 +231,63 @@ fn hover_common_symbol( .get_definition(token, file.text.pos_to_byte(&pos), doc)?; // 根据 symbol 的类别进行额外的判断 + match symbol_definition.def_type { + DefinitionType::ModuleInstantiation => { + let hdlparam = server.srcs.hdl_param.clone(); + let pathbuf = PathBuf::from_str(doc.path()).unwrap(); + let pathbuf = to_escape_path(&pathbuf); + let path_string = pathbuf.to_str().unwrap().replace("\\", "/"); + + let find_name_condition = |_: &Module, instance: &Instance| { + symbol_definition.ident == instance.name + }; + + + if let Some(instance) = hdlparam.walk_instantiation(&path_string, find_name_condition) { + info!("instance {:?}", instance); + let def_line = file.text.byte_to_line(symbol_definition.byte_idx()); + let mut markdown_comment = match make_hover_with_comment(&file.text, def_line, &language_id, true) { + Some(hover) => { + match hover.contents { + HoverContents::Array(array) => array, + _ => Vec::::new() + } + }, + None => Vec::::new() + }; + + // 扫描到右括号 + let mut current_line = def_line; + let mut buffer = String::new(); + let len_lines = file.text.len_lines(); + let mut matcher = BracketMatcher::new(); + + loop { + if current_line >= len_lines { + break; + } + let line_text = file.text.line(current_line).to_string(); + buffer.push_str(&line_text); + match matcher.consume_string(&line_text) { + BracketMatchResult::Invalid | BracketMatchResult::Complete => break, + BracketMatchResult::Valid => {} + } + + current_line += 1; + } + markdown_comment.push(MarkedString::LanguageString(LanguageString { + language: language_id.to_string(), + value: buffer + })); + + return Some(Hover { contents: HoverContents::Array(markdown_comment), range: None }); + } + } + + _ => {} + }; let def_line = file.text.byte_to_line(symbol_definition.byte_idx()); - make_hover_with_comment(&file.text, def_line, &language_id) + make_hover_with_comment(&file.text, def_line, &language_id, false) } diff --git a/src/test/vhdl.rs b/src/test/vhdl.rs index 6dfbfdb..3b1dfb7 100644 --- a/src/test/vhdl.rs +++ b/src/test/vhdl.rs @@ -2,7 +2,7 @@ #[cfg(test)] mod test_vhdl_fast { - use crate::{core::vhdl_parser::{make_fast_from_design_file, vhdl_parse}, test::TESTFILES_TEMP_DIR, utils::*}; + use crate::{core::vhdl_parser::{make_fast_from_design_file, vhdl_parse}, test::{DIGTIAL_IDE_TEST, TESTFILES_TEMP_DIR}, utils::*}; #[test] fn test_temp() { @@ -23,4 +23,25 @@ mod test_vhdl_fast { } } } + + + #[test] + fn test_digital_ide_test() { + let file_iter = RecursiveFileIterator::new(DIGTIAL_IDE_TEST); + for file in file_iter { + let language_id = get_language_id_by_pathbuf(&file); + if language_id == "vhdl" { + println!("test file: {:?}", file); + if let Some(design_file) = vhdl_parse(&file) { + if let Some(_) = make_fast_from_design_file(&design_file) { + println!("<(^-^)>"); + } else { + eprintln!("error happen when make fast {:?}", file); + } + } else { + eprintln!("error happen when parse {:?}", file); + } + } + } + } } \ No newline at end of file diff --git a/src/utils/fast.rs b/src/utils/fast.rs index babafd6..139ccbe 100644 --- a/src/utils/fast.rs +++ b/src/utils/fast.rs @@ -1,4 +1,6 @@ +use log::info; + use crate::{core::hdlparam::Define, server::LSPServer}; impl LSPServer { diff --git a/src/utils/mod.rs b/src/utils/mod.rs index c808a98..dd394e0 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -290,4 +290,50 @@ pub fn srcpos_to_location(pos: &SrcPos) -> Location { uri, range: to_lsp_range(pos.range()), } +} + + +/// 用于判断括号匹配的数据结构 +pub struct BracketMatcher { + stack: Vec +} + +pub enum BracketMatchResult { + Valid, + Invalid, + Complete +} + +impl BracketMatcher { + pub fn new() -> Self { + BracketMatcher { stack: Vec::::new() } + } + + /// 匹配一段字符串内的括号,如果匹配不成功,返回 false + pub fn consume_string(&mut self, text: &str) -> BracketMatchResult { + for ch in text.chars() { + match ch { + '(' => { + self.stack.push(ch); + } + ')' => { + let top = self.stack.pop(); + if top.is_none() { + return BracketMatchResult::Invalid; + } else { + let top = top.unwrap(); + if top != '(' { + return BracketMatchResult::Invalid; + } + } + if self.stack.len() == 0 { + return BracketMatchResult::Complete; + } + } + _ => {} + } + } + + BracketMatchResult::Valid + } } \ No newline at end of file