实现模块跨文件的定义跳转

This commit is contained in:
锦恢 2024-10-01 02:04:41 +08:00
parent 79f505177d
commit ceb827b850
8 changed files with 131 additions and 34 deletions

View File

@ -1,5 +1,4 @@
use std::collections::HashMap;
use std::f64::consts::E;
use std::sync::RwLock;
use serde::{Deserialize, Serialize};
@ -25,10 +24,6 @@ pub struct Range {
pub end: Position
}
pub trait LikePosition {
fn line(&self) -> u32;
fn character(&self) -> u32;
}
impl Range {
#[allow(unused)]
@ -42,6 +37,27 @@ impl Range {
pub fn contains(&self, postion: &LspPosition) -> bool {
compare_pos(&self.start.to_lsp_position(), postion) != 1 && compare_pos(postion, &self.end.to_lsp_position()) != 1
}
/// 对所有的 line 或者 所有的 character 进行偏移操作
pub fn affine(&mut self, line_offset: i32, character_offset: i32) -> &Range {
if line_offset > 0 {
self.start.line += line_offset as u32;
self.end.line += line_offset as u32;
} else {
self.start.line -= (- line_offset) as u32;
self.end.line -= (- line_offset) as u32;
}
if character_offset > 0 {
self.start.character += character_offset as u32;
self.end.character += character_offset as u32;
} else {
self.start.character -= (- character_offset) as u32;
self.end.character -= (- character_offset) as u32;
}
self
}
}
fn compare_pos(pos1: &LspPosition, pos2: &LspPosition) -> i32 {

View File

@ -313,7 +313,7 @@ pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Re
}
}
update_module_range(&path, &mut hdlparam);
// update_module_range(&path, &mut hdlparam);
Ok(hdlparam)
}
@ -576,6 +576,7 @@ fn get_includes(path: &PathBuf) -> Vec<crate::core::fast_hdlparam::Include> {
includes
}
#[allow(unused)]
fn update_module_range(path: &PathBuf, hdlparam: &mut FastHdlparam) {
let file = File::open(path).unwrap();
let reader = BufReader::new(file);

View File

@ -159,11 +159,8 @@ fn goto_instantiation<'a>(
if token_name == port.name {
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 mut target_range = port.range.to_lsp_range();
target_range.start.line -= 1;
target_range.start.character -= 1;
target_range.end.line -= 1;
target_range.end.character -= 1;
let mut target_range = port.range.clone();
let target_range = target_range.affine(-1, -1).to_lsp_range();
let link = vec![LocationLink {
target_uri,
@ -212,10 +209,26 @@ pub fn goto_position_port_param_definition(
None
}
pub fn goto_instance_definition() {
}
pub fn goto_module_definition() {
pub fn goto_module_declaration_definition(
server: &LSPServer,
token_name: &str
) -> Option<GotoDefinitionResponse> {
if let Some(module) = server.srcs.hdl_param.find_module_by_name(token_name) {
let def_path = server.srcs.hdl_param.find_module_definition_path(&module.name).unwrap();
let target_uri = Url::from_file_path(PathBuf::from_str(&def_path).unwrap()).unwrap();
let mut target_range = module.range.clone();
let target_range = target_range.affine(-1, -1).to_lsp_range();
let link = vec![LocationLink {
target_uri,
origin_selection_range: None,
target_range: target_range,
target_selection_range: target_range
}];
let links = GotoDefinitionResponse::Link(link);
return Some(links);
}
None
}

View File

@ -49,6 +49,11 @@ impl LSPServer {
return Some(definition);
}
// match module name
if let Some(definition) = goto_module_declaration_definition(self, &token) {
return Some(definition);
}
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)?;

View File

@ -3,7 +3,7 @@ use std::{path::PathBuf, str::FromStr};
use log::info;
use regex::Regex;
use ropey::RopeSlice;
use tower_lsp::lsp_types::{Hover, HoverContents, LanguageString, MarkedString, Position, Range, Url};
use tower_lsp::lsp_types::{Hover, HoverContents, LanguageString, MarkedString, MarkupContent, MarkupKind, Position, Range, Url};
use crate::{core::fast_hdlparam::{Define, FastHdlparam}, server::LSPServer};
@ -339,7 +339,7 @@ pub fn hover_module_declaration(
let port_num = module.ports.len();
let param_num = module.params.len();
let instance_num = module.instances.len();
let port_desc = format!(" port {port_num} param {param_num} instantiation {instance_num}");
let port_desc = format!("`port` {port_num}, `param` {param_num}, `instantiation` {instance_num}");
// 统计 dir
let mut input_count = 0 as u32;
@ -355,26 +355,25 @@ pub fn hover_module_declaration(
}
}
let io_desc = format!(" input {input_count} output {output_count} inout {inout_count}");
let desc_string = format!("{} | {}", port_desc, io_desc);
let io_desc = format!("`input` {input_count}, `output` {output_count}, `inout` {inout_count}");
let module_path = server.srcs.hdl_param.find_module_definition_path(&module.name).unwrap();
let module_pathbuf = PathBuf::from_str(module_path.as_str()).unwrap();
let path_string = server.srcs.hdl_param.find_module_definition_path(&module.name).unwrap_or("unknown".to_string());
let define_info = format!("define in {path_string}");
let mut markdowns = Vec::<MarkedString>::new();
markdowns.push(MarkedString::String(desc_string));
markdowns.push(MarkedString::String(port_desc));
markdowns.push(MarkedString::String(io_desc));
markdowns.push(MarkedString::String("".to_string()));
markdowns.push(MarkedString::String(define_info));
markdowns.push(MarkedString::String("---".to_string()));
info!("module range: {:?}", module.range);
if let Some(code) = get_range_text(&module_pathbuf, &module.range.to_lsp_range()) {
let code = LanguageString {
let module_profile = make_module_profile_code(&module);
let profile_markdown = LanguageString {
language: language_id.to_string(),
value: code
value: module_profile
};
markdowns.push(MarkedString::LanguageString(code));
}
markdowns.push(MarkedString::LanguageString(profile_markdown));
let hover = Hover {
contents: HoverContents::Array(markdowns),
@ -386,3 +385,64 @@ pub fn hover_module_declaration(
None
}
/// 根据 module 获取 module 的简单描述代码
fn make_module_profile_code(module: &crate::core::fast_hdlparam::Module) -> String {
let mut codes = Vec::<String>::new();
let param_num = module.params.len();
let port_num = module.ports.len();
if module.params.len() > 0 {
codes.push(format!("module {} #(", module.name));
for (i, param) in module.params.iter().enumerate() {
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(" ");
if i == param_num - 1 {
codes.push(format!("\t{param_desc}"));
} else {
codes.push(format!("\t{param_desc},"));
}
}
codes.push(")(".to_string());
} else {
codes.push(format!("module {} (", module.name));
}
if module.ports.len() > 0 {
for (i, port) in module.ports.iter().enumerate() {
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(" ");
if i == port_num - 1 {
codes.push(format!("\t{port_desc}"));
} else {
codes.push(format!("\t{port_desc},"));
}
}
codes.push(format!(")"));
} else {
codes.push(format!(")"));
}
let profile_string = codes.join("\n");
profile_string
}

View File

@ -4,6 +4,7 @@ use crate::definition::*;
use crate::server::LSPServer;
use crate::sources::LSPSupport;
use crate::utils::*;
#[allow(unused)]
use log::info;
use regex::Regex;
use ropey::Rope;
@ -40,7 +41,6 @@ impl LSPServer {
let scope_tree: RwLockReadGuard<'_, Option<GenericScope>> = 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) {

View File

@ -8,6 +8,7 @@ use crate::sources::LSPSupport;
use super::to_escape_path;
#[allow(unused)]
pub fn get_range_text(path: &PathBuf, range: &Range) -> Option<String> {
let path = to_escape_path(path);
if let Some(rope) = open_doc_as_rope(&path) {
@ -19,6 +20,7 @@ pub fn get_range_text(path: &PathBuf, range: &Range) -> Option<String> {
None
}
#[allow(unused)]
pub fn open_doc_as_rope(path: &PathBuf) -> Option<Rope> {
if let std::result::Result::Ok(text) = fs::read_to_string(path) {
let rope = Rope::from_str(text.as_str());

@ -1 +1 @@
Subproject commit 90e9d4cb3ba4e3a55a9b3fcd0fb83389a376ec35
Subproject commit 3002b3970b64903ec98a3274d7254fefa82f0435