diff --git a/src/core/fast_hdlparam.rs b/src/core/fast_hdlparam.rs index 5254eb4..c5bca98 100644 --- a/src/core/fast_hdlparam.rs +++ b/src/core/fast_hdlparam.rs @@ -1,4 +1,9 @@ +use std::collections::HashMap; +use std::sync::RwLock; + 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)] pub struct Position { @@ -6,12 +11,28 @@ pub struct Position { pub character: u32 } +impl Position { + #[allow(unused)] + pub fn to_lsp_position(&self) -> LspPosition { + LspPosition { line: self.line, character: self.character } + } +} + #[derive(Debug, Clone, Serialize, PartialEq, Deserialize)] pub struct Range { pub start: Position, pub end: Position } +impl Range { + #[allow(unused)] + pub fn to_lsp_range(&self) -> LspRange { + let start_pos = self.start.to_lsp_position(); + let end_pos= self.end.to_lsp_position(); + LspRange::new(start_pos, end_pos) + } +} + #[derive(Debug, Serialize, PartialEq, Deserialize, Clone)] pub struct Port { pub name: String, @@ -232,63 +253,57 @@ impl FastHdlparam { last_module.instances.push(instance); } } - - // pub fn print_fast(&self) { - // if self.content.is_empty() { - // println!("none module"); - // } else { - // for module in &self.content { - // println!("module {}", module.name); - // if !module.params.is_empty() { - // println!(" params:"); - // for param in &module.params { - // println!(" parameter {} {} {}", param.net_type, param.name, param.init); - // println!(" range start {} {}", param.range.start.line, param.range.start.character); - // println!(" range end {} {}", param.range.end.line, param.range.end.character); - // } - // } - // if !module.ports.is_empty() { - // println!(" ports:"); - // for port in &module.ports { - // if port.width == "1" { - // println!(" {} {} {}", port.dir_type, port.net_type, port.name); - // } else { - // println!(" {} {} {} {}", port.dir_type, port.net_type, port.width, port.name); - // } - // println!(" range start {} {}", port.range.start.line, port.range.start.character); - // println!(" range end {} {}", port.range.end.line, port.range.end.character); - // } - // } - // if !module.instances.is_empty() { - // println!(" instances:"); - // for instance in &module.instances { - // println!(" {} {}", instance.inst_type, instance.name); - // if instance.instparams.is_none() { - // println!(" params: {:?}", instance.instparams); - // } else { - // println!(" params:"); - // println!(" range start {} {}", instance.instparams.clone().unwrap().start.line, - // instance.instparams.clone().unwrap().start.character); - // println!(" range end {} {}", instance.instparams.clone().unwrap().end.line, - // instance.instparams.clone().unwrap().end.character); - // } - // if instance.instports.is_none() { - // println!(" ports: {:?}", instance.instports); - // } else { - // println!(" ports:"); - // println!(" range start {} {}", instance.instports.clone().unwrap().start.line, - // instance.instports.clone().unwrap().start.character); - // println!(" range end {} {}", instance.instports.clone().unwrap().end.line, - // instance.instports.clone().unwrap().end.character); - // } - // println!(" range start {} {}", instance.range.start.line, instance.range.start.character); - // println!(" range end {} {}", instance.range.end.line, instance.range.end.character); - // } - // } - // println!(" range start {} {}", module.range.start.line, module.range.start.character); - // println!(" range end {} {}", module.range.end.line, module.range.end.character); - // } - // } - // } - } + +pub struct HdlFile { + pub fast: FastHdlparam, + pub name_to_module: HashMap +} + +pub struct HdlParam { + /// 路径到 HdlFile 的映射 + pub path_to_hdl_file: RwLock>, + /// 模块名字到其所在的 HdlFile 路径的映射 + pub module_name_to_path: RwLock> +} + +impl HdlParam { + pub fn new() -> Self { + Self { + path_to_hdl_file: RwLock::new(HashMap::::new()), + module_name_to_path: RwLock::new(HashMap::::new()) + } + } + + pub fn update_fast(&self, path: String, fast: FastHdlparam) { + let mut fast_map = self.path_to_hdl_file.write().unwrap(); + // 构建映射 + let mut name_to_module = HashMap::::new(); + let mut module_name_to_path = self.module_name_to_path.write().unwrap(); + + for module in &fast.content { + name_to_module.insert(module.name.to_string(), module.clone()); + if !module_name_to_path.contains_key(&module.name) { + module_name_to_path.insert(module.name.to_string(), path.to_string()); + } + } + + let file = HdlFile { fast, name_to_module }; + fast_map.insert(path, file); + } + + 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) { + let fast_map = self.path_to_hdl_file.read().unwrap(); + if let Some(hdl_file) = fast_map.get(path) { + if let Some(module) = hdl_file.name_to_module.get(name) { + return Some(module.clone()); + } + } + } + + None + } + +} \ No newline at end of file diff --git a/src/definition/extract_defs.rs b/src/definition/extract_defs.rs index 9c08c37..568b985 100644 --- a/src/definition/extract_defs.rs +++ b/src/definition/extract_defs.rs @@ -3,6 +3,7 @@ use crate::definition::match_definitions; use sv_parser::*; use tower_lsp::lsp_types::*; +/// 找到 node 的 名字,开始的位置和结束的位置 pub fn get_ident(tree: &SyntaxTree, node: RefNode) -> (String, usize) { let loc = unwrap_locate!(node).unwrap(); let ident_str = tree.get_str(loc).unwrap().to_string(); diff --git a/src/definition/mod.rs b/src/definition/mod.rs index d790dd3..781d89a 100644 --- a/src/definition/mod.rs +++ b/src/definition/mod.rs @@ -44,10 +44,9 @@ impl LSPServer { let scope_tree = self.srcs.scope_tree.read().ok()?; - let def = scope_tree - .as_ref()? - // 获取定义 - .get_definition(&token, file.text.pos_to_byte(&pos), &doc)?; + let byte_idx = file.text.pos_to_byte(&pos); + let global_scope = scope_tree.as_ref()?; + let def = global_scope.get_definition(&token, byte_idx, &doc)?; let def_pos = file.text.byte_to_pos(def.byte_idx()); Some(GotoDefinitionResponse::Scalar(Location::new( diff --git a/src/hover/mod.rs b/src/hover/mod.rs index 4c9ad37..8a120be 100644 --- a/src/hover/mod.rs +++ b/src/hover/mod.rs @@ -1,9 +1,11 @@ -use std::sync::RwLockReadGuard; +use std::collections::HashMap; +use std::{path::PathBuf, str::FromStr, sync::RwLockReadGuard}; -use crate::definition::*; +use crate::{core::fast_hdlparam::FastHdlparam, definition::*}; use crate::server::LSPServer; use crate::sources::LSPSupport; use crate::utils::*; +use log::info; use regex::Regex; use ropey::{Rope, RopeSlice}; use tower_lsp::lsp_types::*; @@ -36,10 +38,16 @@ impl LSPServer { return Some(hover); } - let scope_tree: RwLockReadGuard<'_, Option> = self.srcs.scope_tree.read().ok()?; let global_scope = scope_tree.as_ref(); + // info!("get scope tree: {:?}", scope_tree); + + // match positional port param + if let Some(hover) = hover_position_port_param(self, &line_text, &doc, pos, &language_id) { + return Some(hover); + } + if let Some(global_scope) = global_scope { // match 正常 symbol if let Some(hover) = hover_common_symbol(global_scope, &token, &file, &doc, pos, &language_id) { @@ -209,16 +217,193 @@ fn hover_common_symbol( make_hover_with_comment(&file.text, def_line, &language_id) } -/// 计算 position 赋值的 port 或者 param -/// 比如 .clk ( clk ) 中的 . -fn hover_position_port(line: &RopeSlice, pos: Position, language_id: &str) -> Option { - let position_port_regex = Regex::new(r"[.0-9a-zA-Z]").unwrap(); - if let Some((port_name, range)) = get_word_range_at_position(line, pos, position_port_regex) { - if port_name.starts_with(".") { - let port_name = &port_name[1..]; +fn goto_instantiation<'a>( + fast: &'a FastHdlparam, + pos: &Position +) -> Option<&'a crate::core::fast_hdlparam::Instance> { + for module in &fast.content { + for instance in &module.instances { + if let Some(param_range) = &instance.instparams { + let range = param_range.to_lsp_range(); + // let in_scope = compare_pos(&range.start, pos) != 1 && compare_pos(pos, &range.end) != 1; + // info!("pos: {pos:?}, param_range: {range:?}, in_scope: {in_scope:?}"); + if compare_pos(&range.start, pos) != 1 && compare_pos(pos, &range.end) != 1 { + return Some(instance); + } + } + + if let Some(port_range) = &instance.instports { + let range = port_range.to_lsp_range(); + // let in_scope = compare_pos(&range.start, pos) != 1 && compare_pos(pos, &range.end) != 1; + // info!("pos: {pos:?}, port_range: {range:?}, in_scope: {in_scope:?}"); + if compare_pos(&range.start, pos) != 1 && compare_pos(pos, &range.end) != 1 { + return Some(instance); + } + } + } + } + + None +} + +/// 计算 position 赋值的 port 或者 param +/// 比如 .clk ( clk ) 中的 .clk +fn hover_position_port_param( + server: &LSPServer, + line: &RopeSlice, + url: &Url, + pos: Position, + language_id: &str +) -> Option { + let position_port_regex = Regex::new(r"[.0-9a-zA-Z]").unwrap(); + if let Some((name, range)) = get_word_range_at_position(line, pos, position_port_regex) { + if name.starts_with(".") { + let name = &name[1..]; + // 进入最近的 scope 寻找 + let fast_map = server.srcs.hdl_param.path_to_hdl_file.read().unwrap(); + let path = PathBuf::from_str(url.path()).unwrap(); + let path = to_escape_path(&path); + let path_string = path.to_str().unwrap(); + if let Some(hdl_file) = fast_map.get(path_string) { + // 先找到属于哪一个 module + let fast = &hdl_file.fast; + info!("find hdl file: {:?}", fast); + if let Some(instance) = goto_instantiation(fast, &pos) { + info!("find instance scope: {:?}", instance); + if let Some(hover) = hover_position_param(server, instance, &pos, &range, name, language_id) { + info!("hover_position_param return"); + return Some(hover); + } + if let Some(hover) = hover_position_port(server, instance, &pos, &range, name, language_id) { + info!("hover_position_port return"); + return Some(hover); + } + } + } } } + None +} + +fn make_port_desc_hover(port: &crate::core::fast_hdlparam::Port, range: &Range, language_id: &str) -> Hover { + let mut port_desc_array = Vec::::new(); + port_desc_array.push(port.dir_type.to_string()); + if port.net_type != "unknown" { + port_desc_array.push(port.net_type.to_string()); + } + + if port.signed != "unsigned" { + port_desc_array.push("signed".to_string()); + } + + if port.width != "1" { + port_desc_array.push(port.width.to_string()); + } + + port_desc_array.push(port.name.to_string()); + let port_desc = port_desc_array.join(" "); + let language_string = LanguageString { + language: language_id.to_string(), + value: port_desc + }; + Hover { + contents: HoverContents::Scalar(MarkedString::LanguageString(language_string)), + range: Some(range.clone()) + } +} + +fn make_param_desc_hover(param: &crate::core::fast_hdlparam::Parameter, range: &Range, language_id: &str) -> Hover { + let mut param_desc_array = Vec::::new(); + param_desc_array.push(format!("parameter {}", param.name)); + + if param.init != "unknown" { + param_desc_array.push(param.init.to_string()); + } + + let param_desc = param_desc_array.join(" "); + let language_string = LanguageString { + language: language_id.to_string(), + value: param_desc + }; + Hover { + contents: HoverContents::Scalar(MarkedString::LanguageString(language_string)), + range: Some(range.clone()) + } +} + + +/// pos1 < pos2 -1 +/// pos1 = pos2 0 +/// pos1 > pos2 1 +fn compare_pos(pos1: &Position, pos2: &Position) -> i32 { + if pos1.line > pos2.line { + 1 + } else if pos1.line < pos2.line { + -1 + } else if pos1.character > pos2.character { + 1 + } else if pos1.character < pos2.character { + -1 + } else { + 0 + } +} + +fn hover_position_port( + server: &LSPServer, + instance: &crate::core::fast_hdlparam::Instance, + pos: &Position, + range: &Range, + token_name: &str, + language_id: &str +) -> Option { + + if let Some(inst_port_range) = &instance.instports { + let port_range = inst_port_range.to_lsp_range(); + + if compare_pos(&port_range.start, pos) != 1 && compare_pos(pos, &port_range.end) != 1 { + let module_name = &instance.inst_type; + // 确定当前光标在 inst port 内 + if let Some(module) = server.srcs.hdl_param.find_module_by_name(module_name) { + info!("find original module"); + for port in &module.ports { + if token_name == port.name { + // 制作 port 的 Hover + let hover = make_port_desc_hover(port, range, language_id); + return Some(hover); + } + } + } + } + } + None +} + +fn hover_position_param( + server: &LSPServer, + instance: &crate::core::fast_hdlparam::Instance, + pos: &Position, + range: &Range, + token_name: &str, + language_id: &str +) -> Option { + if let Some(inst_param_range) = &instance.instparams { + let param_range = inst_param_range.to_lsp_range(); + if compare_pos(¶m_range.start, pos) != 1 && compare_pos(pos, ¶m_range.end) != 1 { + let module_name = &instance.inst_type; + // 确定当前光标在 inst port 内 + if let Some(module) = server.srcs.hdl_param.find_module_by_name(module_name) { + for param in &module.params { + if token_name == param.name { + // 制作 port 的 Hover + let hover = make_param_desc_hover(param, range, language_id); + return Some(hover); + } + } + } + } + } None } \ No newline at end of file diff --git a/src/hover/vhdl.rs b/src/hover/vhdl.rs index 46b7a70..3144ebf 100644 --- a/src/hover/vhdl.rs +++ b/src/hover/vhdl.rs @@ -2,5 +2,8 @@ use tower_lsp::lsp_types::*; use crate::server::LSPServer; pub fn hover_vhdl(server: &LSPServer, param: &DocumentSymbolParams) -> Option { + let design_file = server.srcs.design_file_map.write().unwrap(); + + None } \ No newline at end of file diff --git a/src/request.rs b/src/request.rs index be03904..e6ce8be 100644 --- a/src/request.rs +++ b/src/request.rs @@ -116,12 +116,10 @@ pub fn do_fast<'a>(path: String, _server: &Arc) -> Result>>, // source directories pub source_dirs: Arc>>, - // fast result - pub fast_map: Arc>> + /// hdlparam 后端实现 + pub hdl_param: Arc, } impl std::default::Default for Sources { @@ -201,7 +203,7 @@ impl Sources { design_file_map: Arc::new(RwLock::new(HashMap::new())), include_dirs: Arc::new(RwLock::new(Vec::new())), source_dirs: Arc::new(RwLock::new(Vec::new())), - fast_map: Arc::new(RwLock::new(HashMap::new())) + hdl_param: Arc::new(HdlParam::new()) } } pub fn init(&self) { @@ -248,7 +250,7 @@ impl Sources { let source_handle = source.clone(); let scope_handle = self.scope_tree.clone(); let design_file_handle = self.design_file_map.clone(); - let fast_map_handle = self.fast_map.clone(); + let hdl_param_handle = self.hdl_param.clone(); let inc_dirs = self.include_dirs.clone(); info!("launch worker to parse {:?}", doc.uri.to_string()); @@ -270,7 +272,7 @@ impl Sources { "vhdl" => { vhdl_parser_pipeline( &design_file_handle, - &fast_map_handle, + &hdl_param_handle, uri, ); }, @@ -278,7 +280,7 @@ impl Sources { sv_parser_pipeline( &source_handle, &scope_handle, - &fast_map_handle, + &hdl_param_handle, &text, uri, range, @@ -492,7 +494,7 @@ pub fn recovery_sv_parse( pub fn sv_parser_pipeline( source_handle: &Arc>, scope_handle: &Arc>>, - fast_map_handle: &Arc>>, + hdl_param_handle: &Arc, doc: &Rope, uri: &Url, last_change_range: &Option, @@ -531,9 +533,8 @@ pub fn sv_parser_pipeline( // 加入语法树 & 更新 fast if let Some(syntax_tree) = syntax_tree { - if let Ok(hdlparam) = make_fast_from_syntaxtree(&syntax_tree, &escape_path) { - let mut fast_map = fast_map_handle.write().unwrap(); - fast_map.insert(escape_path_string.to_string(), hdlparam); + if let Ok(fast) = make_fast_from_syntaxtree(&syntax_tree, &escape_path) { + hdl_param_handle.update_fast(escape_path_string.to_string(), fast); } let parse_ir = ParseIR::SyntaxTree(syntax_tree); file.parse_ir = Some(parse_ir); @@ -567,7 +568,7 @@ pub fn sv_parser_pipeline( pub fn vhdl_parser_pipeline( design_file_handle: &Arc>>, - fast_map_handle: &Arc>>, + hdl_param_handle: &Arc, uri: &Url ) { let path = match PathBuf::from_str(uri.path()) { @@ -585,9 +586,8 @@ pub fn vhdl_parser_pipeline( } if let Some(design_file) = vhdl_parse(&escape_path) { let mut design_files = design_file_handle.write().unwrap(); - if let Some(hdlparam) = make_fast_from_design_file(&design_file) { - let mut fast_map = fast_map_handle.write().unwrap(); - fast_map.insert(escape_path_string.to_string(), hdlparam); + if let Some(fast) = make_fast_from_design_file(&design_file) { + hdl_param_handle.update_fast(escape_path_string.to_string(), fast); } design_files.insert(escape_path_string.to_string(), design_file); } diff --git a/src/utils/fast.rs b/src/utils/fast.rs index af0f77e..9a02b63 100644 --- a/src/utils/fast.rs +++ b/src/utils/fast.rs @@ -6,10 +6,10 @@ impl LSPServer { /// macro 可以以 ` 开头 pub fn find_macros(&self, macro_name: &str) -> Option<(Define, String)> { let macro_name = macro_name.replace("`", ""); - let fast_map = self.srcs.fast_map.read().unwrap(); + let fast_map = self.srcs.hdl_param.path_to_hdl_file.read().unwrap(); for path in fast_map.keys() { - if let Some(hdlparam) = fast_map.get(path) { - for define in &hdlparam.fast_macro.defines { + if let Some(hdl_file) = fast_map.get(path) { + for define in &hdl_file.fast.fast_macro.defines { if define.name == macro_name { return Some((define.clone(), path.to_string())); }