实现 position port & param hover

This commit is contained in:
锦恢 2024-09-30 20:26:10 +08:00
parent fedde4a4d4
commit df57c83b0e
8 changed files with 297 additions and 96 deletions

View File

@ -1,4 +1,9 @@
use std::collections::HashMap;
use std::sync::RwLock;
use serde::{Deserialize, Serialize}; 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)] #[derive(Debug, Clone, Serialize, PartialEq, Deserialize)]
pub struct Position { pub struct Position {
@ -6,12 +11,28 @@ pub struct Position {
pub character: u32 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)] #[derive(Debug, Clone, Serialize, PartialEq, Deserialize)]
pub struct Range { pub struct Range {
pub start: Position, pub start: Position,
pub end: 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)] #[derive(Debug, Serialize, PartialEq, Deserialize, Clone)]
pub struct Port { pub struct Port {
pub name: String, pub name: String,
@ -232,63 +253,57 @@ impl FastHdlparam {
last_module.instances.push(instance); last_module.instances.push(instance);
} }
} }
}
// pub fn print_fast(&self) { pub struct HdlFile {
// if self.content.is_empty() { pub fast: FastHdlparam,
// println!("none module"); pub name_to_module: HashMap<String, Module>
// } else { }
// for module in &self.content {
// println!("module {}", module.name); pub struct HdlParam {
// if !module.params.is_empty() { /// 路径到 HdlFile 的映射
// println!(" params:"); pub path_to_hdl_file: RwLock<HashMap<String, HdlFile>>,
// for param in &module.params { /// 模块名字到其所在的 HdlFile 路径的映射
// println!(" parameter {} {} {}", param.net_type, param.name, param.init); pub module_name_to_path: RwLock<HashMap<String, String>>
// println!(" range start {} {}", param.range.start.line, param.range.start.character); }
// println!(" range end {} {}", param.range.end.line, param.range.end.character);
// } impl HdlParam {
// } pub fn new() -> Self {
// if !module.ports.is_empty() { Self {
// println!(" ports:"); path_to_hdl_file: RwLock::new(HashMap::<String, HdlFile>::new()),
// for port in &module.ports { module_name_to_path: RwLock::new(HashMap::<String, String>::new())
// 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); pub fn update_fast(&self, path: String, fast: FastHdlparam) {
// } let mut fast_map = self.path_to_hdl_file.write().unwrap();
// println!(" range start {} {}", port.range.start.line, port.range.start.character); // 构建映射
// println!(" range end {} {}", port.range.end.line, port.range.end.character); let mut name_to_module = HashMap::<String, Module>::new();
// } let mut module_name_to_path = self.module_name_to_path.write().unwrap();
// }
// if !module.instances.is_empty() { for module in &fast.content {
// println!(" instances:"); name_to_module.insert(module.name.to_string(), module.clone());
// for instance in &module.instances { if !module_name_to_path.contains_key(&module.name) {
// println!(" {} {}", instance.inst_type, instance.name); module_name_to_path.insert(module.name.to_string(), path.to_string());
// if instance.instparams.is_none() { }
// println!(" params: {:?}", instance.instparams); }
// } else {
// println!(" params:"); let file = HdlFile { fast, name_to_module };
// println!(" range start {} {}", instance.instparams.clone().unwrap().start.line, fast_map.insert(path, file);
// instance.instparams.clone().unwrap().start.character); }
// println!(" range end {} {}", instance.instparams.clone().unwrap().end.line,
// instance.instparams.clone().unwrap().end.character); pub fn find_module_by_name(&self, name: &str) -> Option<Module> {
// } let module_name_to_path = self.module_name_to_path.read().unwrap();
// if instance.instports.is_none() { if let Some(path) = module_name_to_path.get(name) {
// println!(" ports: {:?}", instance.instports); let fast_map = self.path_to_hdl_file.read().unwrap();
// } else { if let Some(hdl_file) = fast_map.get(path) {
// println!(" ports:"); if let Some(module) = hdl_file.name_to_module.get(name) {
// println!(" range start {} {}", instance.instports.clone().unwrap().start.line, return Some(module.clone());
// 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); None
// 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);
// }
// }
// }
} }

View File

@ -3,6 +3,7 @@ use crate::definition::match_definitions;
use sv_parser::*; use sv_parser::*;
use tower_lsp::lsp_types::*; use tower_lsp::lsp_types::*;
/// 找到 node 的 名字,开始的位置和结束的位置
pub fn get_ident(tree: &SyntaxTree, node: RefNode) -> (String, usize) { pub fn get_ident(tree: &SyntaxTree, node: RefNode) -> (String, usize) {
let loc = unwrap_locate!(node).unwrap(); let loc = unwrap_locate!(node).unwrap();
let ident_str = tree.get_str(loc).unwrap().to_string(); let ident_str = tree.get_str(loc).unwrap().to_string();

View File

@ -44,10 +44,9 @@ impl LSPServer {
let scope_tree = self.srcs.scope_tree.read().ok()?; let scope_tree = self.srcs.scope_tree.read().ok()?;
let def = scope_tree let byte_idx = file.text.pos_to_byte(&pos);
.as_ref()? let global_scope = scope_tree.as_ref()?;
// 获取定义 let def = global_scope.get_definition(&token, byte_idx, &doc)?;
.get_definition(&token, file.text.pos_to_byte(&pos), &doc)?;
let def_pos = file.text.byte_to_pos(def.byte_idx()); let def_pos = file.text.byte_to_pos(def.byte_idx());
Some(GotoDefinitionResponse::Scalar(Location::new( Some(GotoDefinitionResponse::Scalar(Location::new(

View File

@ -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::server::LSPServer;
use crate::sources::LSPSupport; use crate::sources::LSPSupport;
use crate::utils::*; use crate::utils::*;
use log::info;
use regex::Regex; use regex::Regex;
use ropey::{Rope, RopeSlice}; use ropey::{Rope, RopeSlice};
use tower_lsp::lsp_types::*; use tower_lsp::lsp_types::*;
@ -36,10 +38,16 @@ impl LSPServer {
return Some(hover); return Some(hover);
} }
let scope_tree: RwLockReadGuard<'_, Option<GenericScope>> = self.srcs.scope_tree.read().ok()?; let scope_tree: RwLockReadGuard<'_, Option<GenericScope>> = self.srcs.scope_tree.read().ok()?;
let global_scope = scope_tree.as_ref(); 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 { if let Some(global_scope) = global_scope {
// match 正常 symbol // match 正常 symbol
if let Some(hover) = hover_common_symbol(global_scope, &token, &file, &doc, pos, &language_id) { 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) make_hover_with_comment(&file.text, def_line, &language_id)
} }
/// 计算 position 赋值的 port 或者 param fn goto_instantiation<'a>(
/// 比如 .clk ( clk ) 中的 . fast: &'a FastHdlparam,
fn hover_position_port(line: &RopeSlice, pos: Position, language_id: &str) -> Option<Hover> { pos: &Position
let position_port_regex = Regex::new(r"[.0-9a-zA-Z]").unwrap(); ) -> Option<&'a crate::core::fast_hdlparam::Instance> {
if let Some((port_name, range)) = get_word_range_at_position(line, pos, position_port_regex) { for module in &fast.content {
if port_name.starts_with(".") { for instance in &module.instances {
let port_name = &port_name[1..];
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 None
} }
/// 计算 position 赋值的 port 或者 param
/// 比如 .clk ( clk ) 中的 .clk
fn hover_position_port_param(
server: &LSPServer,
line: &RopeSlice,
url: &Url,
pos: Position,
language_id: &str
) -> Option<Hover> {
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::<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
};
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::<String>::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<Hover> {
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<Hover> {
if let Some(inst_param_range) = &instance.instparams {
let param_range = inst_param_range.to_lsp_range();
if compare_pos(&param_range.start, pos) != 1 && compare_pos(pos, &param_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
}

View File

@ -2,5 +2,8 @@ use tower_lsp::lsp_types::*;
use crate::server::LSPServer; use crate::server::LSPServer;
pub fn hover_vhdl(server: &LSPServer, param: &DocumentSymbolParams) -> Option<Hover> { pub fn hover_vhdl(server: &LSPServer, param: &DocumentSymbolParams) -> Option<Hover> {
let design_file = server.srcs.design_file_map.write().unwrap();
None None
} }

View File

@ -116,12 +116,10 @@ pub fn do_fast<'a>(path: String, _server: &Arc<Backend>) -> Result<FastHdlparam
); );
if let Some(syntax_tree) = parse_result { if let Some(syntax_tree) = parse_result {
if let Ok(hdlparam) = make_fast_from_syntaxtree(&syntax_tree, &path_buf) { if let Ok(fast) = make_fast_from_syntaxtree(&syntax_tree, &path_buf) {
let mut fast_map = _server.server.srcs.fast_map.write().unwrap(); let hdl_param = _server.server.srcs.hdl_param.clone();
fast_map.insert(path.to_string(), hdlparam); hdl_param.update_fast(path.to_string(), fast.clone());
if let Some(hdlparam) = fast_map.get(&path) { return Ok(fast);
return Ok(hdlparam.clone());
}
} }
} }

View File

@ -1,4 +1,5 @@
use crate::core::fast_hdlparam::FastHdlparam; use crate::core::fast_hdlparam::FastHdlparam;
use crate::core::fast_hdlparam::HdlParam;
use crate::core::sv_parser::make_fast_from_syntaxtree; use crate::core::sv_parser::make_fast_from_syntaxtree;
use crate::core::vhdl_parser::make_fast_from_design_file; use crate::core::vhdl_parser::make_fast_from_design_file;
use crate::core::vhdl_parser::vhdl_parse; use crate::core::vhdl_parser::vhdl_parse;
@ -128,6 +129,7 @@ pub struct Source {
pub enum ParseIR { pub enum ParseIR {
/// 基于 rust_hdl 的IR存放 VHDL /// 基于 rust_hdl 的IR存放 VHDL
#[allow(unused)]
DesignFile(vhdl_lang::ast::DesignFile), DesignFile(vhdl_lang::ast::DesignFile),
/// 存放 sv 的 IR /// 存放 sv 的 IR
SyntaxTree(sv_parser::SyntaxTree) SyntaxTree(sv_parser::SyntaxTree)
@ -181,8 +183,8 @@ pub struct Sources {
pub include_dirs: Arc<RwLock<Vec<PathBuf>>>, pub include_dirs: Arc<RwLock<Vec<PathBuf>>>,
// source directories // source directories
pub source_dirs: Arc<RwLock<Vec<PathBuf>>>, pub source_dirs: Arc<RwLock<Vec<PathBuf>>>,
// fast result /// hdlparam 后端实现
pub fast_map: Arc<RwLock<HashMap<String, FastHdlparam>>> pub hdl_param: Arc<HdlParam>,
} }
impl std::default::Default for Sources { impl std::default::Default for Sources {
@ -201,7 +203,7 @@ impl Sources {
design_file_map: Arc::new(RwLock::new(HashMap::new())), design_file_map: Arc::new(RwLock::new(HashMap::new())),
include_dirs: Arc::new(RwLock::new(Vec::new())), include_dirs: Arc::new(RwLock::new(Vec::new())),
source_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) { pub fn init(&self) {
@ -248,7 +250,7 @@ impl Sources {
let source_handle = source.clone(); let source_handle = source.clone();
let scope_handle = self.scope_tree.clone(); let scope_handle = self.scope_tree.clone();
let design_file_handle = self.design_file_map.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(); let inc_dirs = self.include_dirs.clone();
info!("launch worker to parse {:?}", doc.uri.to_string()); info!("launch worker to parse {:?}", doc.uri.to_string());
@ -270,7 +272,7 @@ impl Sources {
"vhdl" => { "vhdl" => {
vhdl_parser_pipeline( vhdl_parser_pipeline(
&design_file_handle, &design_file_handle,
&fast_map_handle, &hdl_param_handle,
uri, uri,
); );
}, },
@ -278,7 +280,7 @@ impl Sources {
sv_parser_pipeline( sv_parser_pipeline(
&source_handle, &source_handle,
&scope_handle, &scope_handle,
&fast_map_handle, &hdl_param_handle,
&text, &text,
uri, uri,
range, range,
@ -492,7 +494,7 @@ pub fn recovery_sv_parse(
pub fn sv_parser_pipeline( pub fn sv_parser_pipeline(
source_handle: &Arc<RwLock<Source>>, source_handle: &Arc<RwLock<Source>>,
scope_handle: &Arc<RwLock<Option<GenericScope>>>, scope_handle: &Arc<RwLock<Option<GenericScope>>>,
fast_map_handle: &Arc<RwLock<HashMap<String, FastHdlparam>>>, hdl_param_handle: &Arc<HdlParam>,
doc: &Rope, doc: &Rope,
uri: &Url, uri: &Url,
last_change_range: &Option<Range>, last_change_range: &Option<Range>,
@ -531,9 +533,8 @@ pub fn sv_parser_pipeline(
// 加入语法树 & 更新 fast // 加入语法树 & 更新 fast
if let Some(syntax_tree) = syntax_tree { if let Some(syntax_tree) = syntax_tree {
if let Ok(hdlparam) = make_fast_from_syntaxtree(&syntax_tree, &escape_path) { if let Ok(fast) = make_fast_from_syntaxtree(&syntax_tree, &escape_path) {
let mut fast_map = fast_map_handle.write().unwrap(); hdl_param_handle.update_fast(escape_path_string.to_string(), fast);
fast_map.insert(escape_path_string.to_string(), hdlparam);
} }
let parse_ir = ParseIR::SyntaxTree(syntax_tree); let parse_ir = ParseIR::SyntaxTree(syntax_tree);
file.parse_ir = Some(parse_ir); file.parse_ir = Some(parse_ir);
@ -567,7 +568,7 @@ pub fn sv_parser_pipeline(
pub fn vhdl_parser_pipeline( pub fn vhdl_parser_pipeline(
design_file_handle: &Arc<RwLock<HashMap<String, DesignFile>>>, design_file_handle: &Arc<RwLock<HashMap<String, DesignFile>>>,
fast_map_handle: &Arc<RwLock<HashMap<String, FastHdlparam>>>, hdl_param_handle: &Arc<HdlParam>,
uri: &Url uri: &Url
) { ) {
let path = match PathBuf::from_str(uri.path()) { 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) { if let Some(design_file) = vhdl_parse(&escape_path) {
let mut design_files = design_file_handle.write().unwrap(); let mut design_files = design_file_handle.write().unwrap();
if let Some(hdlparam) = make_fast_from_design_file(&design_file) { if let Some(fast) = make_fast_from_design_file(&design_file) {
let mut fast_map = fast_map_handle.write().unwrap(); hdl_param_handle.update_fast(escape_path_string.to_string(), fast);
fast_map.insert(escape_path_string.to_string(), hdlparam);
} }
design_files.insert(escape_path_string.to_string(), design_file); design_files.insert(escape_path_string.to_string(), design_file);
} }

View File

@ -6,10 +6,10 @@ impl LSPServer {
/// macro 可以以 ` 开头 /// macro 可以以 ` 开头
pub fn find_macros(&self, macro_name: &str) -> Option<(Define, String)> { pub fn find_macros(&self, macro_name: &str) -> Option<(Define, String)> {
let macro_name = macro_name.replace("`", ""); 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() { for path in fast_map.keys() {
if let Some(hdlparam) = fast_map.get(path) { if let Some(hdl_file) = fast_map.get(path) {
for define in &hdlparam.fast_macro.defines { for define in &hdl_file.fast.fast_macro.defines {
if define.name == macro_name { if define.name == macro_name {
return Some((define.clone(), path.to_string())); return Some((define.clone(), path.to_string()));
} }