From cdcea829479e67fa154451cd37cdce10cfcbc543 Mon Sep 17 00:00:00 2001 From: LSTM-Kirigaya <1193466151@qq.com> Date: Fri, 1 Nov 2024 20:39:29 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=20module=20=E7=AB=AF?= =?UTF-8?q?=E5=8F=A3=E8=B5=8B=E5=80=BC=E7=9A=84=20inlay=20hints?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 1 + src/core/hdlparam.rs | 36 +++++++++++ src/hover/feature.rs | 34 +++-------- src/inlay_hint/sv.rs | 139 +++++++++++++++++++++++++++++------------- src/server.rs | 14 ++--- src/sources.rs | 14 ++++- 6 files changed, 161 insertions(+), 77 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/core/hdlparam.rs b/src/core/hdlparam.rs index d9a9ec5..b66ce32 100644 --- a/src/core/hdlparam.rs +++ b/src/core/hdlparam.rs @@ -142,6 +142,42 @@ pub struct Parameter { pub range: Range } +impl Port { + pub fn to_description(&self) -> String { + let mut port_desc_array = Vec::::new(); + port_desc_array.push(self.dir_type.to_string()); + if self.net_type != "unknown" { + port_desc_array.push(self.net_type.to_string()); + } + + if self.signed != "unsigned" { + port_desc_array.push("signed".to_string()); + } + + if self.width != "1" { + port_desc_array.push(self.width.to_string()); + } + + port_desc_array.push(self.name.to_string()); + let port_desc = port_desc_array.join(" "); + port_desc + } +} + +impl Parameter { + pub fn to_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()); + } + let param_desc = param_desc_array.join(" "); + param_desc + } +} + #[derive(Debug, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize, Clone)] pub enum AssignType { Named, diff --git a/src/hover/feature.rs b/src/hover/feature.rs index ffa7dd1..3559cbe 100644 --- a/src/hover/feature.rs +++ b/src/hover/feature.rs @@ -295,25 +295,9 @@ pub fn hover_position_port_param( } fn make_port_desc_hover(port: &crate::core::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 + value: port.to_description() }; Hover { contents: HoverContents::Scalar(MarkedString::LanguageString(language_string)), @@ -322,18 +306,9 @@ fn make_port_desc_hover(port: &crate::core::hdlparam::Port, range: &Range, langu } fn make_param_desc_hover(param: &crate::core::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("=".to_string()); - 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 + value: param.to_description() }; Hover { contents: HoverContents::Scalar(MarkedString::LanguageString(language_string)), @@ -358,6 +333,11 @@ pub fn hover_module_declaration( search_result() }; + // info!("token: {:?}, module info: {:?}", token_name, module_info); + + // let test = server.srcs.hdl_param.module_name_to_path.read().unwrap(); + // info!("module name to path: {:#?}", test); + if let Some((module, path_string)) = module_info { let path_uri = Url::from_file_path(path_string.to_string()).unwrap().to_string(); let def_row = module.range.start.line; diff --git a/src/inlay_hint/sv.rs b/src/inlay_hint/sv.rs index 324b8af..a4b746f 100644 --- a/src/inlay_hint/sv.rs +++ b/src/inlay_hint/sv.rs @@ -1,8 +1,9 @@ -use std::{path::PathBuf, str::FromStr}; +use std::{collections::HashMap, path::PathBuf, str::FromStr}; -use crate::{core, server::LSPServer}; +use crate::{core, server::LSPServer, sources::LSPSupport}; #[allow(unused)] use log::info; +use ropey::Rope; use tower_lsp::lsp_types::*; use super::to_escape_path; @@ -14,13 +15,13 @@ pub fn inlay_hint(server: &LSPServer, params: &InlayHintParams) -> Option::new(); // 制作例化模块的 hint @@ -28,11 +29,11 @@ pub fn inlay_hint(server: &LSPServer, params: &InlayHintParams) -> Option Vec { let mut hints = Vec::::new(); @@ -66,44 +69,98 @@ fn make_instparam_hints( hints } +pub fn position_to_index(rope: &Rope, position: Position) -> usize { + let line_start = rope.line_to_char(position.line as usize); + let char_index = line_start + position.character as usize; + char_index +} + +pub fn index_to_position(slice: &Rope, char_index: usize) -> Position { + let line = slice.char_to_line(char_index); + let line_start = slice.line_to_char(line); + let character = char_index - line_start; + Position { + line: line as u32, + character: character as u32, + } +} + +fn find_instport_inlay_hints_position( + rope: &Rope, + range: &Range +) -> Option { + // let start = rope.pos_to_byte(&range.start); + // let end = rope.pos_to_byte(&range.end); + let start_offset = position_to_index(rope, range.start); + let end_offset = position_to_index(rope, range.end); + let instport_text = rope.slice(start_offset .. end_offset); + let instport_text = instport_text.to_string(); + info!("{:?}", instport_text); + + if let Some(offset) = instport_text.find("(") { + let target_offset = start_offset + offset + 1; + let target_position = index_to_position(rope, target_offset); + return Some(target_position); + } + + None +} + fn make_instport_hints( + server: &LSPServer, params: &InlayHintParams, - instance: &core::hdlparam::Instance + instance: &core::hdlparam::Instance, + rope: &Rope ) -> Vec { let mut hints = Vec::::new(); + let define_module = server.srcs.hdl_param.find_module_by_name(&instance.inst_type); + if define_module.is_none() { + return hints; + } + let define_module = define_module.unwrap(); + // 制作 port name 到 port 的映射 + let mut port_map = HashMap::::new(); + for port in &define_module.ports { + port_map.insert(port.name.to_string(), port); + } + for port_assigment in &instance.intstport_assignments { - let port_desc = MarkupContent { - kind: MarkupKind::Markdown, - value: format!("```verilog\n{:?}\n```", port_assigment.port) - }; + let port_name = port_assigment.port.clone().unwrap_or("".to_string()); + let port = port_map.get(&port_name); + if port.is_none() { + continue; + } + let port_info = port.unwrap(); + let instport_range = port_assigment.range.to_lsp_range(); + info!("inst name: {:?}, range: {:?}", instance.name, instport_range); + if let Some(hint_position) = find_instport_inlay_hints_position(rope, &instport_range) { + let port_desc = MarkupContent { + kind: MarkupKind::Markdown, + value: format!("```verilog\n{}\n```", port_info.to_description()) + }; - 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 label = { + let dir_type = port_info.dir_type.to_string(); + if dir_type == "output" { + format!("{}", dir_type) + } else { + format!("{}{}", dir_type, " ".repeat(1)) + } + }; - 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); + + let hint = InlayHint { + position: hint_position, + label: InlayHintLabel::String(label), + 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 diff --git a/src/server.rs b/src/server.rs index 18e6ead..f6c299d 100644 --- a/src/server.rs +++ b/src/server.rs @@ -213,18 +213,22 @@ 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)), + 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::default()) + Ok(InitializeResult { + server_info, + capabilities, + offset_encoding: None + }) } async fn initialized(&self, _: InitializedParams) { self.client - .log_message(MessageType::INFO, "digital lsp initialized!") + .log_message(MessageType::INFO, "Digital LSP initialized!") .await; // self.client.send_notification::(StringNotification { content: "hello from lsp server".to_string() }).await; @@ -276,7 +280,6 @@ impl LanguageServer for Backend { } async fn hover(&self, params: HoverParams) -> Result> { - Ok(self.server.hover(params)) } @@ -295,7 +298,6 @@ impl LanguageServer for Backend { &self, params: DocumentSymbolParams, ) -> Result> { - info!("enter document"); Ok(self.server.document_symbol(params)) } @@ -303,7 +305,6 @@ impl LanguageServer for Backend { &self, params: DocumentHighlightParams, ) -> Result>> { - info!("enter highlight"); Ok(self.server.document_highlight(params)) } @@ -311,7 +312,6 @@ impl LanguageServer for Backend { &self, params: InlayHintParams ) -> Result>> { - info!("enter inlay_hint"); Ok(self.server.inlay_hint(params)) } } diff --git a/src/sources.rs b/src/sources.rs index afc3e61..5a59720 100644 --- a/src/sources.rs +++ b/src/sources.rs @@ -68,8 +68,6 @@ impl LSPServer { } pub fn did_change(&self, params: DidChangeTextDocumentParams) { - info!("[LSPServer] did change"); - 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(); @@ -755,6 +753,7 @@ pub trait LSPSupport { fn range_to_char_range(&self, range: &Range) -> StdRange; fn char_range_to_range(&self, range: StdRange) -> Range; fn apply_change(&mut self, change: &TextDocumentContentChangeEvent); + fn find_first_str(&self, target: &str) -> Option; } /// Extend ropey's Rope type with lsp convenience functions @@ -797,6 +796,9 @@ impl LSPSupport for Rope { } } } + fn find_first_str(&self, _: &str) -> Option { + panic!("haven't impl this method"); + } } impl<'a> LSPSupport for RopeSlice<'a> { @@ -831,4 +833,12 @@ impl<'a> LSPSupport for RopeSlice<'a> { fn apply_change(&mut self, _: &TextDocumentContentChangeEvent) { panic!("can't edit a rope slice"); } + fn find_first_str(&self, target: &str) -> Option { + for (i, c) in self.chars().enumerate() { + if c.to_string() == target { + return Some(i) + } + } + None + } }