完成 module 端口赋值的 inlay hints
This commit is contained in:
parent
2dd7f98d5f
commit
cdcea82947
1
.vscode/settings.json
vendored
Normal file
1
.vscode/settings.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{}
|
@ -142,6 +142,42 @@ pub struct Parameter {
|
||||
pub range: Range
|
||||
}
|
||||
|
||||
impl Port {
|
||||
pub fn to_description(&self) -> String {
|
||||
let mut port_desc_array = Vec::<String>::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::<String>::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,
|
||||
|
@ -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::<String>::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::<String>::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;
|
||||
|
@ -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<Vec<In
|
||||
let path_string = path.to_str().unwrap();
|
||||
let visible_range = core::hdlparam::Range::from_lsp_range(¶ms.range);
|
||||
|
||||
info!("enter hints");
|
||||
|
||||
let fast_map = server.srcs.hdl_param.path_to_hdl_file.read().unwrap();
|
||||
let file_id = server.srcs.get_id(¶ms.text_document.uri);
|
||||
let file = server.srcs.get_file(file_id).unwrap();
|
||||
let file = file.read().unwrap();
|
||||
let rope = &file.text;
|
||||
// 先找到 当前 所在的 hdlfile
|
||||
if let Some(hdl_file) = &fast_map.get(path_string) {
|
||||
info!("enter some");
|
||||
|
||||
let fast = &hdl_file.fast;
|
||||
let mut hints = Vec::<InlayHint>::new();
|
||||
// 制作例化模块的 hint
|
||||
@ -28,11 +29,11 @@ pub fn inlay_hint(server: &LSPServer, params: &InlayHintParams) -> Option<Vec<In
|
||||
for instance in &module.instances {
|
||||
// 根据在可见视图外面的 range 就不管了
|
||||
if is_visible_range(&instance.instparams, &visible_range) {
|
||||
hints.extend(make_instparam_hints(params, instance));
|
||||
hints.extend(make_instparam_hints(server, params, instance, rope));
|
||||
}
|
||||
|
||||
if is_visible_range(&instance.instports, &visible_range) {
|
||||
hints.extend(make_instport_hints(params, instance));
|
||||
hints.extend(make_instport_hints(server, params, instance, rope));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -57,8 +58,10 @@ fn is_visible_range(
|
||||
}
|
||||
|
||||
fn make_instparam_hints(
|
||||
server: &LSPServer,
|
||||
params: &InlayHintParams,
|
||||
instance: &core::hdlparam::Instance
|
||||
instance: &core::hdlparam::Instance,
|
||||
rope: &Rope
|
||||
) -> Vec<InlayHint> {
|
||||
let mut hints = Vec::<InlayHint>::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<Position> {
|
||||
// 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<InlayHint> {
|
||||
let mut hints = Vec::<InlayHint>::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::<String, &core::hdlparam::Port>::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
|
||||
|
@ -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>(StringNotification { content: "hello from lsp server".to_string() }).await;
|
||||
@ -276,7 +280,6 @@ impl LanguageServer for Backend {
|
||||
}
|
||||
|
||||
async fn hover(&self, params: HoverParams) -> Result<Option<Hover>> {
|
||||
|
||||
Ok(self.server.hover(params))
|
||||
}
|
||||
|
||||
@ -295,7 +298,6 @@ impl LanguageServer for Backend {
|
||||
&self,
|
||||
params: DocumentSymbolParams,
|
||||
) -> Result<Option<DocumentSymbolResponse>> {
|
||||
info!("enter document");
|
||||
Ok(self.server.document_symbol(params))
|
||||
}
|
||||
|
||||
@ -303,7 +305,6 @@ impl LanguageServer for Backend {
|
||||
&self,
|
||||
params: DocumentHighlightParams,
|
||||
) -> Result<Option<Vec<DocumentHighlight>>> {
|
||||
info!("enter highlight");
|
||||
Ok(self.server.document_highlight(params))
|
||||
}
|
||||
|
||||
@ -311,7 +312,6 @@ impl LanguageServer for Backend {
|
||||
&self,
|
||||
params: InlayHintParams
|
||||
) -> Result<Option<Vec<InlayHint>>> {
|
||||
info!("enter inlay_hint");
|
||||
Ok(self.server.inlay_hint(params))
|
||||
}
|
||||
}
|
||||
|
@ -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<usize>;
|
||||
fn char_range_to_range(&self, range: StdRange<usize>) -> Range;
|
||||
fn apply_change(&mut self, change: &TextDocumentContentChangeEvent);
|
||||
fn find_first_str(&self, target: &str) -> Option<usize>;
|
||||
}
|
||||
|
||||
/// Extend ropey's Rope type with lsp convenience functions
|
||||
@ -797,6 +796,9 @@ impl LSPSupport for Rope {
|
||||
}
|
||||
}
|
||||
}
|
||||
fn find_first_str(&self, _: &str) -> Option<usize> {
|
||||
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<usize> {
|
||||
for (i, c) in self.chars().enumerate() {
|
||||
if c.to_string() == target {
|
||||
return Some(i)
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user