实现 sv 的例化提示
This commit is contained in:
parent
df57c83b0e
commit
8ae9a09738
@ -24,6 +24,11 @@ pub struct Range {
|
|||||||
pub end: Position
|
pub end: Position
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait LikePosition {
|
||||||
|
fn line(&self) -> u32;
|
||||||
|
fn character(&self) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
impl Range {
|
impl Range {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn to_lsp_range(&self) -> LspRange {
|
pub fn to_lsp_range(&self) -> LspRange {
|
||||||
@ -31,6 +36,25 @@ impl Range {
|
|||||||
let end_pos= self.end.to_lsp_position();
|
let end_pos= self.end.to_lsp_position();
|
||||||
LspRange::new(start_pos, end_pos)
|
LspRange::new(start_pos, end_pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 判断输入的 position 是否在当前 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compare_pos(pos1: &LspPosition, pos2: &LspPosition) -> 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, PartialEq, Deserialize, Clone)]
|
#[derive(Debug, Serialize, PartialEq, Deserialize, Clone)]
|
||||||
@ -306,4 +330,13 @@ impl HdlParam {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn find_module_definition_path(&self, module_name: &str) -> Option<String> {
|
||||||
|
let module_name_to_path = self.module_name_to_path.read().unwrap();
|
||||||
|
if let Some(path) = module_name_to_path.get(module_name) {
|
||||||
|
return Some(path.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -5,7 +5,7 @@ use regex::Regex;
|
|||||||
use ropey::RopeSlice;
|
use ropey::RopeSlice;
|
||||||
use tower_lsp::lsp_types::{GotoDefinitionResponse, LocationLink, Position, Range, Url};
|
use tower_lsp::lsp_types::{GotoDefinitionResponse, LocationLink, Position, Range, Url};
|
||||||
|
|
||||||
use crate::{server::LSPServer, utils::{get_word_range_at_position, resolve_path, to_escape_path}};
|
use crate::{core::fast_hdlparam::FastHdlparam, server::LSPServer, utils::{get_word_range_at_position, resolve_path, to_escape_path}};
|
||||||
|
|
||||||
/// 跳转到 include 的文件
|
/// 跳转到 include 的文件
|
||||||
pub fn goto_include_definition(uri: &Url, line: &RopeSlice, pos: Position) -> Option<GotoDefinitionResponse> {
|
pub fn goto_include_definition(uri: &Url, line: &RopeSlice, pos: Position) -> Option<GotoDefinitionResponse> {
|
||||||
@ -106,6 +106,112 @@ pub fn goto_macro_definition(server: &LSPServer, line: &RopeSlice, pos: Position
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn goto_instantiation<'a>(
|
||||||
|
server: &LSPServer,
|
||||||
|
fast: &'a FastHdlparam,
|
||||||
|
token_name: &str,
|
||||||
|
pos: &Position,
|
||||||
|
range: &Range
|
||||||
|
) -> Option<GotoDefinitionResponse> {
|
||||||
|
for module in &fast.content {
|
||||||
|
for instance in &module.instances {
|
||||||
|
if let Some(param_range) = &instance.instparams {
|
||||||
|
// 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 param_range.contains(pos) {
|
||||||
|
let module = match server.srcs.hdl_param.find_module_by_name(&instance.inst_type) {
|
||||||
|
Some(module) => module,
|
||||||
|
None => return None
|
||||||
|
};
|
||||||
|
for param in &module.params {
|
||||||
|
if token_name == param.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 = param.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 link = vec![LocationLink {
|
||||||
|
target_uri,
|
||||||
|
origin_selection_range: Some(range.clone()),
|
||||||
|
target_range: target_range,
|
||||||
|
target_selection_range: target_range
|
||||||
|
}];
|
||||||
|
let links = GotoDefinitionResponse::Link(link);
|
||||||
|
return Some(links);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(port_range) = &instance.instports {
|
||||||
|
// 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 port_range.contains(pos) {
|
||||||
|
let module = match server.srcs.hdl_param.find_module_by_name(&instance.inst_type) {
|
||||||
|
Some(module) => module,
|
||||||
|
None => return None
|
||||||
|
};
|
||||||
|
for port in &module.ports {
|
||||||
|
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 link = vec![LocationLink {
|
||||||
|
target_uri,
|
||||||
|
origin_selection_range: Some(range.clone()),
|
||||||
|
target_range: target_range,
|
||||||
|
target_selection_range: target_range
|
||||||
|
}];
|
||||||
|
let links = GotoDefinitionResponse::Link(link);
|
||||||
|
return Some(links);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn goto_position_port_param_definition(
|
||||||
|
server: &LSPServer,
|
||||||
|
line: &RopeSlice,
|
||||||
|
url: &Url,
|
||||||
|
pos: Position
|
||||||
|
) -> Option<GotoDefinitionResponse> {
|
||||||
|
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;
|
||||||
|
if let Some(definition) = goto_instantiation(server, fast, name, &pos, &range) {
|
||||||
|
return Some(definition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
pub fn goto_instance_definition() {
|
pub fn goto_instance_definition() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{utils::get_definition_token};
|
use crate::utils::get_definition_token;
|
||||||
use crate::server::LSPServer;
|
use crate::server::LSPServer;
|
||||||
use crate::sources::LSPSupport;
|
use crate::sources::LSPSupport;
|
||||||
|
|
||||||
@ -44,6 +44,11 @@ impl LSPServer {
|
|||||||
|
|
||||||
let scope_tree = self.srcs.scope_tree.read().ok()?;
|
let scope_tree = self.srcs.scope_tree.read().ok()?;
|
||||||
|
|
||||||
|
// match position port & param
|
||||||
|
if let Some(definition) = goto_position_port_param_definition(self, &line_text, &doc, pos) {
|
||||||
|
return Some(definition);
|
||||||
|
}
|
||||||
|
|
||||||
let byte_idx = file.text.pos_to_byte(&pos);
|
let byte_idx = file.text.pos_to_byte(&pos);
|
||||||
let global_scope = scope_tree.as_ref()?;
|
let global_scope = scope_tree.as_ref()?;
|
||||||
let def = global_scope.get_definition(&token, byte_idx, &doc)?;
|
let def = global_scope.get_definition(&token, byte_idx, &doc)?;
|
||||||
|
@ -5,9 +5,9 @@ use regex::Regex;
|
|||||||
use ropey::RopeSlice;
|
use ropey::RopeSlice;
|
||||||
use tower_lsp::lsp_types::{Hover, HoverContents, LanguageString, MarkedString, Position, Range, Url};
|
use tower_lsp::lsp_types::{Hover, HoverContents, LanguageString, MarkedString, Position, Range, Url};
|
||||||
|
|
||||||
use crate::{core::fast_hdlparam::Define, server::LSPServer};
|
use crate::{core::fast_hdlparam::{Define, FastHdlparam}, server::LSPServer};
|
||||||
|
|
||||||
use super::{get_word_range_at_position, resolve_path, to_escape_path};
|
use super::{file::get_range_text, get_word_range_at_position, resolve_path, to_escape_path};
|
||||||
|
|
||||||
/// 将 4'b0011 分解为 ("b", "0011")
|
/// 将 4'b0011 分解为 ("b", "0011")
|
||||||
fn parse_digit_string(digit_string: &str) -> Option<(&str, &str)> {
|
fn parse_digit_string(digit_string: &str) -> Option<(&str, &str)> {
|
||||||
@ -202,3 +202,187 @@ pub fn hover_macro(server: &LSPServer, line: &RopeSlice, pos: Position, language
|
|||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn goto_instantiation<'a>(
|
||||||
|
server: &LSPServer,
|
||||||
|
fast: &'a FastHdlparam,
|
||||||
|
token_name: &str,
|
||||||
|
pos: &Position,
|
||||||
|
range: &Range,
|
||||||
|
language_id: &str
|
||||||
|
) -> Option<Hover> {
|
||||||
|
for module in &fast.content {
|
||||||
|
for instance in &module.instances {
|
||||||
|
if let Some(param_range) = &instance.instparams {
|
||||||
|
// 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 param_range.contains(pos) {
|
||||||
|
let module = match server.srcs.hdl_param.find_module_by_name(&instance.inst_type) {
|
||||||
|
Some(module) => module,
|
||||||
|
None => return None
|
||||||
|
};
|
||||||
|
for param in &module.params {
|
||||||
|
if token_name == param.name {
|
||||||
|
let hover = make_param_desc_hover(param, range, language_id);
|
||||||
|
return Some(hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(port_range) = &instance.instports {
|
||||||
|
if port_range.contains(pos) {
|
||||||
|
let module = match server.srcs.hdl_param.find_module_by_name(&instance.inst_type) {
|
||||||
|
Some(module) => module,
|
||||||
|
None => return None
|
||||||
|
};
|
||||||
|
for port in &module.ports {
|
||||||
|
if token_name == port.name {
|
||||||
|
let hover = make_port_desc_hover(port, range, language_id);
|
||||||
|
return Some(hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 计算 position 赋值的 port 或者 param
|
||||||
|
/// 比如 .clk ( clk ) 中的 .clk
|
||||||
|
pub 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;
|
||||||
|
if let Some(hover) = goto_instantiation(server, fast, name, &pos, &range, language_id) {
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hover_module_declaration(
|
||||||
|
server: &LSPServer,
|
||||||
|
token_name: &str,
|
||||||
|
language_id: &str
|
||||||
|
) -> Option<Hover> {
|
||||||
|
if let Some(module) = server.srcs.hdl_param.find_module_by_name(token_name) {
|
||||||
|
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}");
|
||||||
|
|
||||||
|
// 统计 dir
|
||||||
|
let mut input_count = 0 as u32;
|
||||||
|
let mut output_count = 0 as u32;
|
||||||
|
let mut inout_count = 0 as u32;
|
||||||
|
|
||||||
|
for port in &module.ports {
|
||||||
|
match port.dir_type.as_str() {
|
||||||
|
"input" => input_count += 1,
|
||||||
|
"output" => output_count += 1,
|
||||||
|
"inout" => inout_count += 1,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let io_desc = format!(" input {input_count} output {output_count} inout {inout_count}");
|
||||||
|
let desc_string = format!("{} | {}", port_desc, io_desc);
|
||||||
|
|
||||||
|
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 mut markdowns = Vec::<MarkedString>::new();
|
||||||
|
markdowns.push(MarkedString::String(desc_string));
|
||||||
|
markdowns.push(MarkedString::String("".to_string()));
|
||||||
|
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 {
|
||||||
|
language: language_id.to_string(),
|
||||||
|
value: code
|
||||||
|
};
|
||||||
|
markdowns.push(MarkedString::LanguageString(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
let hover = Hover {
|
||||||
|
contents: HoverContents::Array(markdowns),
|
||||||
|
range: None
|
||||||
|
};
|
||||||
|
|
||||||
|
return Some(hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
206
src/hover/mod.rs
206
src/hover/mod.rs
@ -1,13 +1,12 @@
|
|||||||
use std::collections::HashMap;
|
use std::sync::RwLockReadGuard;
|
||||||
use std::{path::PathBuf, str::FromStr, sync::RwLockReadGuard};
|
|
||||||
|
|
||||||
use crate::{core::fast_hdlparam::FastHdlparam, definition::*};
|
use crate::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 log::info;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use ropey::{Rope, RopeSlice};
|
use ropey::Rope;
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
pub mod feature;
|
pub mod feature;
|
||||||
@ -48,9 +47,15 @@ impl LSPServer {
|
|||||||
return Some(hover);
|
return Some(hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// match module name
|
||||||
|
if let Some(hover) = hover_module_declaration(self, &token, &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(self, global_scope, &token, &file, &doc, pos, &language_id) {
|
||||||
return Some(hover);
|
return Some(hover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,6 +205,7 @@ fn make_hover_with_comment(doc: &Rope, line: usize, language_id: &str) -> Option
|
|||||||
|
|
||||||
/// 计算正常 symbol 的 hover
|
/// 计算正常 symbol 的 hover
|
||||||
fn hover_common_symbol(
|
fn hover_common_symbol(
|
||||||
|
server: &LSPServer,
|
||||||
scope_tree: &GenericScope,
|
scope_tree: &GenericScope,
|
||||||
token: &String,
|
token: &String,
|
||||||
file: &RwLockReadGuard<'_, crate::sources::Source>,
|
file: &RwLockReadGuard<'_, crate::sources::Source>,
|
||||||
@ -217,193 +223,3 @@ fn hover_common_symbol(
|
|||||||
make_hover_with_comment(&file.text, def_line, &language_id)
|
make_hover_with_comment(&file.text, def_line, &language_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn goto_instantiation<'a>(
|
|
||||||
fast: &'a FastHdlparam,
|
|
||||||
pos: &Position
|
|
||||||
) -> Option<&'a crate::core::fast_hdlparam::Instance> {
|
|
||||||
for module in &fast.content {
|
|
||||||
for instance in &module.instances {
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 计算 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(¶m_range.start, pos) != 1 && compare_pos(pos, ¶m_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
|
|
||||||
}
|
|
4
src/request/fsm.rs
Normal file
4
src/request/fsm.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
pub fn fsm() {
|
||||||
|
|
||||||
|
}
|
@ -258,7 +258,6 @@ impl LanguageServer for Backend {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async fn completion(&self, params: CompletionParams) -> Result<Option<CompletionResponse>> {
|
async fn completion(&self, params: CompletionParams) -> Result<Option<CompletionResponse>> {
|
||||||
Ok(self.server.completion(params))
|
Ok(self.server.completion(params))
|
||||||
}
|
}
|
||||||
|
29
src/utils/file.rs
Normal file
29
src/utils/file.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use std::{fs, path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
|
use log::info;
|
||||||
|
use ropey::Rope;
|
||||||
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
|
use crate::sources::LSPSupport;
|
||||||
|
|
||||||
|
use super::to_escape_path;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
let start_index = rope.pos_to_byte(&range.start);
|
||||||
|
let end_index = rope.pos_to_byte(&range.end);
|
||||||
|
info!("start index: {}, end index: {}", start_index, end_index);
|
||||||
|
return Some(rope.slice(start_index..end_index).to_string());
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
Some(rope)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ use ropey::RopeSlice;
|
|||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
pub mod fast;
|
pub mod fast;
|
||||||
|
pub mod file;
|
||||||
|
|
||||||
/// 根据 pos 获取到当前光标所在的字符串,相当于 getWordRangeAtPosition
|
/// 根据 pos 获取到当前光标所在的字符串,相当于 getWordRangeAtPosition
|
||||||
pub fn get_definition_token(line: &RopeSlice, pos: Position) -> String {
|
pub fn get_definition_token(line: &RopeSlice, pos: Position) -> String {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user