From c8aa5e2dcc0b2c39ab596c24ae6f8255c2bdebee Mon Sep 17 00:00:00 2001 From: LSTM-Kirigaya <1193466151@qq.com> Date: Mon, 11 Nov 2024 23:53:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=20IP=20=E7=9A=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81=EF=BC=88=E8=BF=98=E5=B7=AE=E8=87=AA=E5=8A=A8=E8=A1=A5?= =?UTF-8?q?=E5=85=A8=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/hdlparam.rs | 31 ++++++++ src/definition/feature.rs | 41 +++++++++-- src/hover/feature.rs | 58 ++++++++++----- src/server.rs | 7 +- src/sources.rs | 146 +++++++++++++++++++++++--------------- 5 files changed, 200 insertions(+), 83 deletions(-) diff --git a/src/core/hdlparam.rs b/src/core/hdlparam.rs index b04ca8a..514e2e1 100644 --- a/src/core/hdlparam.rs +++ b/src/core/hdlparam.rs @@ -200,6 +200,18 @@ impl Port { let port_desc = port_desc_array.join(" "); port_desc } + pub fn to_vhdl_description(&self) -> String { + let mut port_desc_array = Vec::::new(); + + port_desc_array.push(self.name.to_string()); + port_desc_array.push(":".to_string()); + port_desc_array.push(self.dir_type.to_string()); + let width_string = self.width.replace("[", "(").replace("]", ")").replace(":", " downto "); + port_desc_array.push(format!("{}{};", self.net_type.to_lowercase(), width_string)); + + let port_desc = port_desc_array.join(" "); + port_desc + } } impl Parameter { @@ -207,6 +219,17 @@ impl Parameter { let mut param_desc_array = Vec::::new(); param_desc_array.push(format!("parameter {}", self.name)); + if self.init != "unknown" { + param_desc_array.push("=".to_string()); + param_desc_array.push(self.init.to_string()); + } + let param_desc = param_desc_array.join(" "); + param_desc + } + pub fn vhdl_to_vlog_description(&self) -> String { + let mut param_desc_array = Vec::::new(); + param_desc_array.push(format!("parameter {}", self.name)); + if self.init != "unknown" { param_desc_array.push("=".to_string()); param_desc_array.push(self.init.to_string()); @@ -499,6 +522,14 @@ impl HdlParam { None } + /// 根据 module name 计算出对应的 file type,默认为 common + pub fn find_file_type_by_module_name(&self, module_name: &str) -> String { + if let Some((_, file_type, _)) = self.find_module_context_by_name(module_name) { + return file_type; + } + "common".to_string() + } + /// 输入 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(); diff --git a/src/definition/feature.rs b/src/definition/feature.rs index e640637..3a18a49 100644 --- a/src/definition/feature.rs +++ b/src/definition/feature.rs @@ -124,7 +124,23 @@ fn goto_instantiation<'a>( 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 target_range = param.range.clone(); - let target_range = target_range.to_lsp_range(); + + let file_type = server.srcs.hdl_param.find_file_type_by_module_name(&instance.inst_type); + let target_range = match file_type.as_str() { + "common" => { + target_range.to_lsp_range() + } + "ip" => { + let mut target_range = target_range.clone(); + target_range.affine(-1, -1).to_lsp_range() + } + "primitives" => { + target_range.to_lsp_range() + } + _ => { + target_range.to_lsp_range() + } + }; let link = vec![LocationLink { target_uri, @@ -153,7 +169,23 @@ fn goto_instantiation<'a>( 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 target_range = port.range.clone(); - let target_range = target_range.to_lsp_range(); + + let file_type = server.srcs.hdl_param.find_file_type_by_module_name(&instance.inst_type); + let target_range = match file_type.as_str() { + "common" => { + target_range.to_lsp_range() + } + "ip" => { + let mut target_range = target_range.clone(); + target_range.affine(-1, -1).to_lsp_range() + } + "primitives" => { + target_range.to_lsp_range() + } + _ => { + target_range.to_lsp_range() + } + }; let link = vec![LocationLink { target_uri, @@ -281,9 +313,8 @@ fn goto_ip_module_declaration_definition( if pathbuf.exists() { let target_uri = Url::from_file_path(PathBuf::from_str(&def_path).unwrap()).unwrap(); - let target_range = module.range.clone(); - info!("target range: {:?}", target_range); - let target_range = target_range.to_lsp_range(); + let mut target_range = module.range.clone(); + let target_range = target_range.affine(-1, -1).to_lsp_range(); let link = vec![LocationLink { target_uri, diff --git a/src/hover/feature.rs b/src/hover/feature.rs index 643fe37..9341ac0 100644 --- a/src/hover/feature.rs +++ b/src/hover/feature.rs @@ -229,7 +229,8 @@ fn goto_instantiation<'a>( for param in &module.params { if token_name == param.name { - let hover = make_param_desc_hover(param, range, language_id); + let file_type = server.srcs.hdl_param.find_file_type_by_module_name(&instance.inst_type); + let hover = make_param_desc_hover(&file_type, param, range, language_id); return Some(hover); } } @@ -250,7 +251,8 @@ fn goto_instantiation<'a>( for port in &module.ports { if token_name == port.name { - let hover = make_port_desc_hover(port, range, language_id); + let file_type = server.srcs.hdl_param.find_file_type_by_module_name(&instance.inst_type); + let hover = make_port_desc_hover(&file_type, port, range, language_id); return Some(hover); } } @@ -294,21 +296,50 @@ pub fn hover_position_port_param( None } -fn make_port_desc_hover(port: &crate::core::hdlparam::Port, range: &Range, language_id: &str) -> Hover { - let language_string = LanguageString { - language: language_id.to_string(), - value: port.to_description() +fn make_port_desc_hover(file_type: &str, port: &crate::core::hdlparam::Port, range: &Range, language_id: &str) -> Hover { + info!("enter make_port_desc_hover, file_type: {}", file_type); + + let (language, value) = match file_type { + "common" => { + (language_id.to_string(), port.to_description()) + } + "ip" => { + ("vhdl".to_string(), port.to_vhdl_description()) + } + "primitives" => { + (language_id.to_string(), port.to_description()) + } + _ => { + (language_id.to_string(), port.to_description()) + } }; + + let language_string = LanguageString { language, value }; Hover { contents: HoverContents::Scalar(MarkedString::LanguageString(language_string)), range: Some(range.clone()) } } -fn make_param_desc_hover(param: &crate::core::hdlparam::Parameter, range: &Range, language_id: &str) -> Hover { +fn make_param_desc_hover(file_type: &str, param: &crate::core::hdlparam::Parameter, range: &Range, language_id: &str) -> Hover { + let value = match file_type { + "common" => { + param.to_description() + } + "ip" => { + param.vhdl_to_vlog_description() + } + "primitives" => { + param.to_description() + } + _ => { + param.to_description() + } + }; + let language_string = LanguageString { language: language_id.to_string(), - value: param.to_description() + value }; Hover { contents: HoverContents::Scalar(MarkedString::LanguageString(language_string)), @@ -654,16 +685,7 @@ pub fn make_entity_profile_code(module: &crate::core::hdlparam::Module) -> Strin } }; - let width_mapper = |width: &str| { - if width == "1" { - 0 - } else { - width.len() + 5 - } - }; - let max_port_length = module.ports.iter().map(|port| port.name.len()).max().unwrap_or(0); - let max_net_length = module.ports.iter().map(|port| net_mapper(&port.net_type)).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); @@ -680,7 +702,7 @@ pub fn make_entity_profile_code(module: &crate::core::hdlparam::Module) -> Strin // std_logic, signed, unsigned 等等 if port.net_type != "unknown" { - port_desc_array.push(port.net_type.to_string()); + port_desc_array.push(port.net_type.to_lowercase()); } // (57 downto 0) diff --git a/src/server.rs b/src/server.rs index c8d7f93..aa4d08e 100644 --- a/src/server.rs +++ b/src/server.rs @@ -6,7 +6,7 @@ use flexi_logger::LoggerHandle; use log::{debug, info, warn}; use serde::{Deserialize, Serialize}; use std::string::ToString; -use std::sync::{Mutex, RwLock}; +use std::sync::{Arc, Mutex, RwLock}; use tower_lsp::jsonrpc::Result; use tower_lsp::lsp_types::*; use tower_lsp::{Client, LanguageServer}; @@ -16,7 +16,7 @@ pub struct LSPServer { pub key_comps: Vec, pub sys_tasks: Vec, pub directives: Vec, - pub conf: RwLock, + pub conf: Arc>, #[allow(unused)] pub log_handle: Mutex>, } @@ -31,7 +31,7 @@ impl LSPServer { key_comps: keyword_completions(KEYWORDS), sys_tasks: other_completions(SYS_TASKS), directives: other_completions(DIRECTIVES), - conf: RwLock::new(ProjectConfig::default()), + conf: Arc::new(RwLock::new(ProjectConfig::default())), log_handle: Mutex::new(log_handle), } } @@ -284,6 +284,7 @@ impl LanguageServer for Backend { } async fn did_change(&self, params: DidChangeTextDocumentParams) { + info!("file did change: {:?}", params.text_document.uri); // // 如果文件太大则显示错误 // if CacheManager::uri_is_big_file(¶ms.text_document.uri) { // // self.client.show_message(MessageType::WARNING, "考虑到性能问题,对于大于 1MB 的文件不会主动提供语言服务") diff --git a/src/sources.rs b/src/sources.rs index 841909c..85be09f 100644 --- a/src/sources.rs +++ b/src/sources.rs @@ -8,6 +8,7 @@ use crate::definition::get_scopes_from_syntax_tree; use crate::definition::get_scopes_from_vhdl_fast; use crate::diagnostics::{get_diagnostics, is_hidden}; use crate::server::LSPServer; +use crate::server::ProjectConfig; use crate::utils::to_escape_path; #[allow(unused)] use log::info; @@ -41,8 +42,6 @@ macro_rules! unwrap_result { impl LSPServer { pub fn did_open(&self, params: DidOpenTextDocumentParams) -> PublishDiagnosticsParams { - info!("[LSPServer] did open"); - let document: TextDocumentItem = params.text_document; let uri = document.uri.clone(); @@ -58,54 +57,69 @@ impl LSPServer { }], }); } else { - self.srcs.add(document); + self.srcs.add(self, document); } // diagnostics let urls = self.srcs.names.read().unwrap().keys().cloned().collect(); let file_id = self.srcs.get_id(&uri); - let file = self.srcs.get_file(file_id).unwrap(); - let file = file.read().unwrap(); - get_diagnostics(uri, &file.text, urls, &self.conf.read().unwrap()) + if let Some(file) = self.srcs.get_file(file_id) { + let file = file.read().unwrap(); + get_diagnostics(uri, &file.text, urls, &self.conf.read().unwrap()) + } else { + PublishDiagnosticsParams { + uri, + diagnostics: Vec::new(), + version: None, + } + } } pub fn did_change(&self, params: DidChangeTextDocumentParams) { let file_id = self.srcs.get_id(¶ms.text_document.uri); - let file = self.srcs.get_file(file_id).unwrap(); - let mut file = file.write().unwrap(); + if let Some(file) = self.srcs.get_file(file_id) { + let mut file = file.write().unwrap(); - // loop through changes and apply - for change in params.content_changes { - if change.range.is_none() { - file.text = Rope::from_str(&change.text); - } else { - file.text.apply_change(&change); + // loop through changes and apply + for change in params.content_changes { + if change.range.is_none() { + file.text = Rope::from_str(&change.text); + } else { + file.text.apply_change(&change); + } + file.last_change_range = change.range; } - file.last_change_range = change.range; + file.version = params.text_document.version; + drop(file); + + // invalidate syntaxtree and wake parse thread + let meta_data = self.srcs.get_meta_data(file_id).unwrap(); + let (lock, cvar) = &*meta_data.read().unwrap().valid_parse; + let mut valid = lock.lock().unwrap(); + *valid = false; + cvar.notify_all(); } - file.version = params.text_document.version; - drop(file); - - // invalidate syntaxtree and wake parse thread - let meta_data = self.srcs.get_meta_data(file_id).unwrap(); - let (lock, cvar) = &*meta_data.read().unwrap().valid_parse; - let mut valid = lock.lock().unwrap(); - *valid = false; - cvar.notify_all(); } pub fn did_save(&self, params: DidSaveTextDocumentParams) -> PublishDiagnosticsParams { - info!("[LSPServer] did save"); - let urls = self.srcs.names.read().unwrap().keys().cloned().collect(); let file_id = self.srcs.get_id(¶ms.text_document.uri); - let file = self.srcs.get_file(file_id).unwrap(); - let file = file.read().unwrap(); - get_diagnostics( - params.text_document.uri, - &file.text, - urls, - &self.conf.read().unwrap(), - ) + let uri = params.text_document.uri.clone(); + + if let Some(file) = self.srcs.get_file(file_id) { + let file = file.read().unwrap(); + get_diagnostics( + uri, + &file.text, + urls, + &self.conf.read().unwrap(), + ) + } else { + PublishDiagnosticsParams { + uri, + diagnostics: Vec::new(), + version: None, + } + } } pub fn did_delete_files(&self, params: DeleteFilesParams) { @@ -240,7 +254,7 @@ impl Sources { } /// 增加一个 hdl 文件,并为该文件添加单独的解析线程 - pub fn add(&self, doc: TextDocumentItem) { + pub fn add(&self, server: &LSPServer, doc: TextDocumentItem) { // 对于当前的文件增加一个解析线程,不断进行解析和同步 #[allow(clippy::mutex_atomic)] // https://github.com/rust-lang/rust-clippy/issues/1516 let valid_parse = Arc::new((Mutex::new(false), Condvar::new())); @@ -259,6 +273,8 @@ impl Sources { let hdl_param_handle = self.hdl_param.clone(); let inc_dirs = self.include_dirs.clone(); + let conf = server.conf.clone(); + info!("launch worker to parse {:?}", doc.uri.to_string()); let language_id = doc.language_id.to_string(); @@ -289,6 +305,7 @@ impl Sources { match language_id.as_str() { "vhdl" => { vhdl_parser_pipeline( + &conf, &source_handle, &scope_handle, &hdl_param_handle, @@ -298,6 +315,7 @@ impl Sources { }, "verilog" | "systemverilog" => { sv_parser_pipeline( + &conf, &source_handle, &scope_handle, &hdl_param_handle, @@ -360,15 +378,16 @@ impl Sources { /// wait for a valid parse pub fn wait_parse_ready(&self, id: usize, wait_valid: bool) { - let file = self.get_file(id).unwrap(); - let file = file.read().unwrap(); - if file.parse_ir.is_none() || wait_valid { - drop(file); - let meta_data = self.get_meta_data(id).unwrap(); - let (lock, cvar) = &*meta_data.read().unwrap().valid_parse; - let mut valid = lock.lock().unwrap(); - while !*valid { - valid = cvar.wait(valid).unwrap(); + if let Some(file) = self.get_file(id) { + let file = file.read().unwrap(); + if file.parse_ir.is_none() || wait_valid { + drop(file); + let meta_data = self.get_meta_data(id).unwrap(); + let (lock, cvar) = &*meta_data.read().unwrap().valid_parse; + let mut valid = lock.lock().unwrap(); + while !*valid { + valid = cvar.wait(valid).unwrap(); + } } } } @@ -562,6 +581,7 @@ pub fn recovery_sv_parse( } pub fn sv_parser_pipeline( + conf: &Arc>, source_handle: &Arc>, scope_handle: &Arc>>, hdl_param_handle: &Arc, @@ -641,6 +661,7 @@ pub fn sv_parser_pipeline( } pub fn vhdl_parser_pipeline( + conf: &Arc>, source_handle: &Arc>, scope_handle: &Arc>>, hdl_param_handle: &Arc, @@ -665,30 +686,41 @@ pub fn vhdl_parser_pipeline( return; } - // TODO: 通过更加精细的方法获取下面的变量 - + let extension_path = { + let configure = conf.read().unwrap(); + configure.extension_path.to_string() + }; let mut file = source_handle.write().unwrap(); let mut scope_tree = if let Some(design_file) = vhdl_parse(&escape_path) { - //let mut design_files = design_file_handle.write().unwrap(); - - if let Some(fast) = make_fast_from_design_file(&design_file) { + if let Some(mut fast) = make_fast_from_design_file(&design_file) { let parse_ir = ParseIR::DesignFile(design_file); file.parse_ir = Some(parse_ir); + + let file_type = { + let fast_map = hdl_param_handle.path_to_hdl_file.read().unwrap(); + if let Some(hdl_file) = fast_map.get(escape_path_string) { + hdl_file.fast.file_type.to_string() + } else { + if let Some(relative_path) = escape_path_string.strip_prefix(&extension_path) { + if relative_path.starts_with("/user/ip") || relative_path.starts_with("user/ip") { + "ip".to_string() + } else { + "common".to_string() + } + } else { + "common".to_string() + } + } + }; + + fast.file_type = file_type; hdl_param_handle.update_fast(escape_path_string.to_string(), fast.clone()); let scope_tree = get_scopes_from_vhdl_fast(&fast, doc, uri); scope_tree } else { None } - - // let mut msg_printer = MessagePrinter::default(); - // if let Some(project) = design_files.get_mut("VHDLProject") { - // project.digital_lsp_update_config(&escape_path, &mut msg_printer); - // } else { - // let project = vhdl_lang::Project::new_without_config(&escape_path, &mut msg_printer); - // design_files.insert("VHDLProject".to_string(), project); - // } } else { file.parse_ir = None; None