修复 macro usage 无法跳转的问题
This commit is contained in:
parent
9688a330bf
commit
0cf07fd017
@ -4,7 +4,7 @@ use std::{path::PathBuf, str::FromStr};
|
|||||||
use log::info;
|
use log::info;
|
||||||
use ropey::{Rope, RopeSlice};
|
use ropey::{Rope, RopeSlice};
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
use crate::{hover::feature::make_vhdl_module_profile_code, utils::{from_lsp_pos, to_escape_path}};
|
use crate::{hover::feature::make_vhdl_module_profile_code, utils::to_escape_path};
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use crate::{server::LspServer, sources::LSPSupport, utils::get_language_id_by_uri};
|
use crate::{server::LspServer, sources::LSPSupport, utils::get_language_id_by_uri};
|
||||||
|
|
||||||
@ -29,7 +29,10 @@ pub fn completion(server: &LspServer, params: &CompletionParams) -> Option<Compl
|
|||||||
);
|
);
|
||||||
|
|
||||||
let project = server.srcs.vhdl_project.read().ok()?;
|
let project = server.srcs.vhdl_project.read().ok()?;
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
let global_project = project.as_ref().unwrap();
|
let global_project = project.as_ref().unwrap();
|
||||||
|
|
||||||
let path = match PathBuf::from_str(uri.path()) {
|
let path = match PathBuf::from_str(uri.path()) {
|
||||||
Ok(path) => path,
|
Ok(path) => path,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
@ -38,6 +41,8 @@ pub fn completion(server: &LspServer, params: &CompletionParams) -> Option<Compl
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let escape_path = to_escape_path(&path);
|
let escape_path = to_escape_path(&path);
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
let project_file = escape_path.as_path();
|
let project_file = escape_path.as_path();
|
||||||
|
|
||||||
// let Some(source) = global_project.project.get_source(project_file) else {
|
// let Some(source) = global_project.project.get_source(project_file) else {
|
||||||
|
@ -446,15 +446,19 @@ impl FastHdlparam {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct HdlFile {
|
pub struct HdlFile {
|
||||||
|
/// 专注于模块树构建和粗粒度 AST 信息的数据结构
|
||||||
pub fast: FastHdlparam,
|
pub fast: FastHdlparam,
|
||||||
pub name_to_module: HashMap<String, Module>
|
/// 名字到 module 映射的 map
|
||||||
|
pub name_to_module: HashMap<String, Module>,
|
||||||
|
/// 解析器生成的额外信息
|
||||||
|
pub parse_result: sv_parser::common::ParseResult
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HdlParam {
|
pub struct HdlParam {
|
||||||
/// 路径到 HdlFile 的映射
|
/// 路径到 HdlFile 的映射
|
||||||
pub path_to_hdl_file: RwLock<HashMap<String, HdlFile>>,
|
pub path_to_hdl_file: RwLock<HashMap<String, HdlFile>>,
|
||||||
/// 模块名字到其所在的 HdlFile 路径的映射
|
/// 模块名字到其所在的 HdlFile 路径的映射
|
||||||
pub module_name_to_path: RwLock<HashMap<String, String>>
|
pub module_name_to_path: RwLock<HashMap<String, String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -467,8 +471,13 @@ impl HdlParam {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 根据 path 更新 fast
|
/// 根据 path 更新 fast 和 parse_result
|
||||||
pub fn update_fast(&self, path: String, fast: FastHdlparam) {
|
pub fn update_hdl_file(
|
||||||
|
&self,
|
||||||
|
path: String,
|
||||||
|
fast: FastHdlparam,
|
||||||
|
parse_result: sv_parser::common::ParseResult
|
||||||
|
) {
|
||||||
let mut fast_map = self.path_to_hdl_file.write().unwrap();
|
let mut fast_map = self.path_to_hdl_file.write().unwrap();
|
||||||
// 构建映射
|
// 构建映射
|
||||||
let mut name_to_module = HashMap::<String, Module>::new();
|
let mut name_to_module = HashMap::<String, Module>::new();
|
||||||
@ -481,7 +490,7 @@ impl HdlParam {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let file = HdlFile { fast, name_to_module };
|
let file = HdlFile { fast, name_to_module, parse_result };
|
||||||
fast_map.insert(path, file);
|
fast_map.insert(path, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,10 +72,8 @@ pub fn sv_parser(path: &str) -> Option<FastHdlparam> {
|
|||||||
let doc = Rope::from_str(&text);
|
let doc = Rope::from_str(&text);
|
||||||
let uri = Url::from_file_path(&path).unwrap();
|
let uri = Url::from_file_path(&path).unwrap();
|
||||||
let result = recovery_sv_parse_with_retry(&doc, &uri, &None, &includes);
|
let result = recovery_sv_parse_with_retry(&doc, &uri, &None, &includes);
|
||||||
|
|
||||||
// println!("result: {result:?}");
|
|
||||||
|
|
||||||
if let Some(syntax_tree) = result {
|
if let Some((syntax_tree, _)) = result {
|
||||||
if let Ok(fast) = make_fast_from_syntaxtree(&syntax_tree, &path) {
|
if let Ok(fast) = make_fast_from_syntaxtree(&syntax_tree, &path) {
|
||||||
return Some(fast);
|
return Some(fast);
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ pub fn goto_include_definition(uri: &Url, line: &RopeSlice, pos: Position) -> Op
|
|||||||
|
|
||||||
/// 跳转到宏定义
|
/// 跳转到宏定义
|
||||||
pub fn goto_macro_definition(server: &LspServer, line: &RopeSlice, pos: Position) -> Option<GotoDefinitionResponse> {
|
pub fn goto_macro_definition(server: &LspServer, line: &RopeSlice, pos: Position) -> Option<GotoDefinitionResponse> {
|
||||||
let macro_text_regex = Regex::new(r"[`0-9a-zA-Z]").unwrap();
|
let macro_text_regex = Regex::new(r"[`_0-9a-zA-Z]").unwrap();
|
||||||
if let Some((macro_text, range)) = get_word_range_at_position(line, pos, macro_text_regex) {
|
if let Some((macro_text, range)) = get_word_range_at_position(line, pos, macro_text_regex) {
|
||||||
if macro_text.starts_with("`") {
|
if macro_text.starts_with("`") {
|
||||||
if let Some((macro_define, define_path)) = server.find_macros(¯o_text) {
|
if let Some((macro_define, define_path)) = server.find_macros(¯o_text) {
|
||||||
@ -84,8 +84,7 @@ pub fn goto_macro_definition(server: &LspServer, line: &RopeSlice, pos: Position
|
|||||||
Err(_) => return None
|
Err(_) => return None
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut target_range = macro_define.range.clone();
|
let target_range = macro_define.range.to_lsp_range();
|
||||||
let target_range = target_range.affine(-1, -1).to_lsp_range();
|
|
||||||
let link = vec![LocationLink {
|
let link = vec![LocationLink {
|
||||||
target_uri,
|
target_uri,
|
||||||
origin_selection_range: Some(range),
|
origin_selection_range: Some(range),
|
||||||
|
@ -24,7 +24,7 @@ pub fn goto_definition(server: &LspServer, params: &GotoDefinitionParams) -> Opt
|
|||||||
return Some(definition);
|
return Some(definition);
|
||||||
}
|
}
|
||||||
|
|
||||||
// match macro
|
// match macro usage
|
||||||
if let Some(definition) = goto_macro_definition(server, &line_text, pos) {
|
if let Some(definition) = goto_macro_definition(server, &line_text, pos) {
|
||||||
return Some(definition);
|
return Some(definition);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
use std::process::{Command, Stdio};
|
use std::{collections::HashSet, process::{Command, Stdio}};
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
use regex::{escape, Regex};
|
use regex::{escape, Regex};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use xml::name;
|
use crate::{diagnostics::find_non_whitespace_indices, server::LspServer, utils::from_uri_to_escape_path_string};
|
||||||
use crate::{diagnostics::find_non_whitespace_indices, server::LspServer};
|
|
||||||
use ropey::Rope;
|
use ropey::Rope;
|
||||||
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, NumberOrString, Position, Range, Url};
|
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, NumberOrString, Position, Range, Url};
|
||||||
|
|
||||||
@ -72,14 +71,15 @@ impl AbstractLinterConfiguration for VivadoConfiguration {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// vivado 比较特殊,需要先分析出当前文件用了哪些其他文件的宏,然后把那部分宏所在的文件加入编译参数中
|
// vivado 比较特殊,需要先分析出当前文件用了哪些其他文件的宏,然后把那部分宏所在的文件加入编译参数中
|
||||||
|
let dependence_files = get_all_dependence_files(uri, server);
|
||||||
|
|
||||||
|
|
||||||
let child = Command::new(&invoke_name)
|
let child = Command::new(&invoke_name)
|
||||||
.current_dir(cwd)
|
.current_dir(cwd)
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.args(&self.linter.args)
|
.args(&self.linter.args)
|
||||||
|
.args(dependence_files)
|
||||||
.arg(path_string)
|
.arg(path_string)
|
||||||
.spawn()
|
.spawn()
|
||||||
.ok()?;
|
.ok()?;
|
||||||
@ -107,7 +107,6 @@ impl AbstractLinterConfiguration for VivadoConfiguration {
|
|||||||
Err(_) => 0
|
Err(_) => 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
if let Some((start_char, end_char)) = find_vivado_suitable_range(rope, error_no, error_description) {
|
if let Some((start_char, end_char)) = find_vivado_suitable_range(rope, error_no, error_description) {
|
||||||
let range = Range {
|
let range = Range {
|
||||||
start: Position { line: error_no as u32, character: start_char as u32 },
|
start: Position { line: error_no as u32, character: start_char as u32 },
|
||||||
@ -146,6 +145,50 @@ impl AbstractLinterConfiguration for VivadoConfiguration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 计算出当前文件所有用到的别的文件(比如使用了其他文件的宏)
|
||||||
|
/// 必须把这些文件也编入诊断中,才能基于 vivado 得到合理的结果
|
||||||
|
fn get_all_dependence_files(
|
||||||
|
uri: &Url,
|
||||||
|
server: &LspServer
|
||||||
|
) -> Vec<String> {
|
||||||
|
let mut files = HashSet::<String>::new();
|
||||||
|
let path_string = from_uri_to_escape_path_string(uri).unwrap();
|
||||||
|
let mut used_macro_names = HashSet::<String>::new();
|
||||||
|
|
||||||
|
let hdl_param = server.srcs.hdl_param.clone();
|
||||||
|
let path_to_hdl_file = hdl_param.path_to_hdl_file.read().unwrap();
|
||||||
|
if let Some(hdl_file) = path_to_hdl_file.get(&path_string) {
|
||||||
|
for macro_symbol in &hdl_file.parse_result.symbol_table.macro_usages {
|
||||||
|
used_macro_names.insert(macro_symbol.name.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (file_path, hdl_file) in path_to_hdl_file.iter() {
|
||||||
|
if file_path == path_string.as_str() {
|
||||||
|
// 只看其他文件
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for define in hdl_file.fast.fast_macro.defines.iter() {
|
||||||
|
let macro_name = define.name.to_string();
|
||||||
|
if used_macro_names.contains(¯o_name) {
|
||||||
|
used_macro_names.remove(¯o_name);
|
||||||
|
files.insert(file_path.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 unused_macro_names 都找到了对应的 path,直接 break 即可
|
||||||
|
if used_macro_names.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 释放锁
|
||||||
|
drop(path_to_hdl_file);
|
||||||
|
|
||||||
|
files.into_iter().collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// 根据 vivado 返回的诊断信息,返回适合的错误在那一行的起始位置
|
/// 根据 vivado 返回的诊断信息,返回适合的错误在那一行的起始位置
|
||||||
/// 默认是返回该行的第一个非空字符到最后一个非空字符中间的位置,即 find_non_whitespace_indices
|
/// 默认是返回该行的第一个非空字符到最后一个非空字符中间的位置,即 find_non_whitespace_indices
|
||||||
fn find_vivado_suitable_range(
|
fn find_vivado_suitable_range(
|
||||||
|
@ -193,11 +193,15 @@ fn do_sv_fast(
|
|||||||
);
|
);
|
||||||
|
|
||||||
let sources = &backend.server.srcs;
|
let sources = &backend.server.srcs;
|
||||||
if let Some(syntax_tree) = parse_result {
|
if let Some((syntax_tree, parse_result)) = parse_result {
|
||||||
if let Ok(mut fast) = make_fast_from_syntaxtree(&syntax_tree, &path_buf) {
|
if let Ok(mut fast) = make_fast_from_syntaxtree(&syntax_tree, &path_buf) {
|
||||||
fast.file_type = file_type.to_string();
|
fast.file_type = file_type.to_string();
|
||||||
let hdl_param = sources.hdl_param.clone();
|
let hdl_param = sources.hdl_param.clone();
|
||||||
hdl_param.update_fast(path.to_string(), fast.clone());
|
hdl_param.update_hdl_file(
|
||||||
|
path.to_string(),
|
||||||
|
fast.clone(),
|
||||||
|
parse_result
|
||||||
|
);
|
||||||
return Ok(fast);
|
return Ok(fast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,7 +256,12 @@ fn do_vhdl_fast(
|
|||||||
file_type: "ip".to_string(),
|
file_type: "ip".to_string(),
|
||||||
content: fake_content
|
content: fake_content
|
||||||
};
|
};
|
||||||
hdl_param.update_fast(path.to_string(), ip_fast.clone());
|
|
||||||
|
hdl_param.update_hdl_file(
|
||||||
|
path.to_string(),
|
||||||
|
ip_fast.clone(),
|
||||||
|
sv_parser::common::ParseResult::new()
|
||||||
|
);
|
||||||
return Ok(ip_fast);
|
return Ok(ip_fast);
|
||||||
} else if let Some(vhdl_project) = &mut *vhdl_project.write().unwrap() {
|
} else if let Some(vhdl_project) = &mut *vhdl_project.write().unwrap() {
|
||||||
vhdl_project.config_file_strs.push(format!("{:?}", pathbuf));
|
vhdl_project.config_file_strs.push(format!("{:?}", pathbuf));
|
||||||
@ -280,7 +289,12 @@ fn do_vhdl_fast(
|
|||||||
for module in &mut fast.content {
|
for module in &mut fast.content {
|
||||||
module.instances.clear();
|
module.instances.clear();
|
||||||
}
|
}
|
||||||
hdl_param.update_fast(path.to_string(), fast.clone());
|
// 为了兼容 verilog 而制作的空的
|
||||||
|
hdl_param.update_hdl_file(
|
||||||
|
path.to_string(),
|
||||||
|
fast.clone(),
|
||||||
|
sv_parser::common::ParseResult::new()
|
||||||
|
);
|
||||||
return Ok(fast);
|
return Ok(fast);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -321,7 +335,11 @@ fn do_vhdl_fast(
|
|||||||
// info!("debug, module : {:?}, path: {:?}", module, pathbuf);
|
// info!("debug, module : {:?}, path: {:?}", module, pathbuf);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
hdl_param.update_fast(path.to_string(), fast.clone());
|
hdl_param.update_hdl_file(
|
||||||
|
path.to_string(),
|
||||||
|
fast.clone(),
|
||||||
|
sv_parser::common::ParseResult::new()
|
||||||
|
);
|
||||||
return Ok(fast);
|
return Ok(fast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,10 @@ use crate::core::scope_tree::get_scopes_from_vhdl_fast;
|
|||||||
use crate::diagnostics::provide_diagnostics;
|
use crate::diagnostics::provide_diagnostics;
|
||||||
use crate::server::LspServer;
|
use crate::server::LspServer;
|
||||||
use crate::server::LspConfiguration;
|
use crate::server::LspConfiguration;
|
||||||
|
use crate::utils::from_uri_to_escape_path_string;
|
||||||
use crate::utils::to_escape_path;
|
use crate::utils::to_escape_path;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::{info, debug, error};
|
||||||
use log::{debug, error};
|
|
||||||
use pathdiff::diff_paths;
|
use pathdiff::diff_paths;
|
||||||
use ropey::{Rope, RopeSlice};
|
use ropey::{Rope, RopeSlice};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
@ -276,7 +276,11 @@ impl Sources {
|
|||||||
for (name, template) in primitive_xml.name_to_template {
|
for (name, template) in primitive_xml.name_to_template {
|
||||||
// use "primitive/name" as a fake path
|
// use "primitive/name" as a fake path
|
||||||
let fake_path = "primitive/".to_string() + &name;
|
let fake_path = "primitive/".to_string() + &name;
|
||||||
hdl_param_handle.update_fast(fake_path, template.fast);
|
hdl_param_handle.update_hdl_file(
|
||||||
|
fake_path,
|
||||||
|
template.fast,
|
||||||
|
sv_parser::common::ParseResult::new()
|
||||||
|
);
|
||||||
primitive_text_handle.update_text(&name, &template.text);
|
primitive_text_handle.update_text(&name, &template.text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -525,9 +529,9 @@ pub fn recovery_sv_parse_with_retry(
|
|||||||
uri: &Url,
|
uri: &Url,
|
||||||
last_change_range: &Option<Range>,
|
last_change_range: &Option<Range>,
|
||||||
inc_paths: &[PathBuf],
|
inc_paths: &[PathBuf],
|
||||||
) -> Option<SyntaxTree>{
|
) -> Option<(SyntaxTree, sv_parser::common::ParseResult)>{
|
||||||
if let Some(syntax_tree) = recovery_sv_parse(doc, uri, last_change_range, inc_paths, false) {
|
if let Some((syntax_tree, parse_result)) = recovery_sv_parse(doc, uri, last_change_range, inc_paths, false) {
|
||||||
Some(syntax_tree)
|
Some((syntax_tree, parse_result))
|
||||||
} else {
|
} else {
|
||||||
recovery_sv_parse(doc, uri, last_change_range, inc_paths, true)
|
recovery_sv_parse(doc, uri, last_change_range, inc_paths, true)
|
||||||
}
|
}
|
||||||
@ -547,7 +551,7 @@ pub fn recovery_sv_parse(
|
|||||||
last_change_range: &Option<Range>,
|
last_change_range: &Option<Range>,
|
||||||
inc_paths: &[PathBuf],
|
inc_paths: &[PathBuf],
|
||||||
allow_incomplete: bool,
|
allow_incomplete: bool,
|
||||||
) -> Option<SyntaxTree> {
|
) -> Option<(SyntaxTree, sv_parser::common::ParseResult)> {
|
||||||
let mut parse_iterations = 1;
|
let mut parse_iterations = 1;
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut includes: Vec<PathBuf> = inc_paths.to_vec();
|
let mut includes: Vec<PathBuf> = inc_paths.to_vec();
|
||||||
@ -583,10 +587,10 @@ pub fn recovery_sv_parse(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 最多解析 500 次
|
// 最多解析 50 次
|
||||||
while i < parse_iterations && i < 500 {
|
while i < parse_iterations && i < 50 {
|
||||||
i += 1;
|
i += 1;
|
||||||
match parse_sv_str(
|
match make_ast_from_svlog_code(
|
||||||
&text.to_string(),
|
&text.to_string(),
|
||||||
uri.to_file_path().unwrap(),
|
uri.to_file_path().unwrap(),
|
||||||
&defines,
|
&defines,
|
||||||
@ -594,8 +598,8 @@ pub fn recovery_sv_parse(
|
|||||||
true,
|
true,
|
||||||
allow_incomplete
|
allow_incomplete
|
||||||
) {
|
) {
|
||||||
Ok((syntax_tree, _)) => {
|
Ok((syntax_tree, parse_result)) => {
|
||||||
return Some(syntax_tree);
|
return Some((syntax_tree, parse_result));
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// println!("err: {err:?}");
|
// println!("err: {err:?}");
|
||||||
@ -642,8 +646,10 @@ pub fn recovery_sv_parse(
|
|||||||
defines.insert(not_found_macro_name, Some(com_define));
|
defines.insert(not_found_macro_name, Some(com_define));
|
||||||
parse_iterations += 1;
|
parse_iterations += 1;
|
||||||
}
|
}
|
||||||
sv_parser::Error::Preprocess(trace) => match trace {
|
sv_parser::Error::Preprocess(trace) => match trace {
|
||||||
Some((_, byte_idx)) => {
|
Some((_, byte_idx)) => {
|
||||||
|
info!("meet preprocess error, text: {text:?}");
|
||||||
|
|
||||||
// 把出错的地方替换成空格
|
// 把出错的地方替换成空格
|
||||||
// println!("text {text:?}");
|
// println!("text {text:?}");
|
||||||
recover_text_by_byte_idx(byte_idx, &mut reverted_change, &mut text);
|
recover_text_by_byte_idx(byte_idx, &mut reverted_change, &mut text);
|
||||||
@ -690,21 +696,10 @@ pub fn sv_parser_pipeline(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = match PathBuf::from_str(uri.path()) {
|
let escape_path_string = from_uri_to_escape_path_string(uri).unwrap();
|
||||||
Ok(path) => path,
|
let escape_path = PathBuf::from_str(&escape_path_string).unwrap();
|
||||||
Err(error) => {
|
|
||||||
info!("error happen in <goto_include_definition>: {:?}", error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let escape_path = to_escape_path(&path);
|
|
||||||
let escape_path_string = escape_path.to_str().unwrap_or("");
|
|
||||||
if escape_path_string.len() == 0 {
|
|
||||||
info!("error happen in [sv_parser_pipeline], escape_path_string is empty");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let syntax_tree = recovery_sv_parse_with_retry(
|
let ast = recovery_sv_parse_with_retry(
|
||||||
doc,
|
doc,
|
||||||
uri,
|
uri,
|
||||||
last_change_range,
|
last_change_range,
|
||||||
@ -712,17 +707,22 @@ pub fn sv_parser_pipeline(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 更新 scope tree
|
// 更新 scope tree
|
||||||
let mut scope_tree = match &syntax_tree {
|
let mut scope_tree = match &ast {
|
||||||
Some(tree) => get_scopes_from_syntax_tree(tree, uri),
|
Some((tree, _)) => get_scopes_from_syntax_tree(tree, uri),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut file = source_handle.write().unwrap();
|
let mut file = source_handle.write().unwrap();
|
||||||
|
|
||||||
// 加入语法树 & 更新 fast
|
// 加入语法树 & 更新 fast
|
||||||
if let Some(syntax_tree) = syntax_tree {
|
if let Some((syntax_tree, parse_result)) = ast {
|
||||||
if let Ok(fast) = make_fast_from_syntaxtree(&syntax_tree, &escape_path) {
|
if let Ok(fast) = make_fast_from_syntaxtree(&syntax_tree, &escape_path) {
|
||||||
hdl_param_handle.update_fast(escape_path_string.to_string(), fast);
|
info!("update parse_result: {:?}", parse_result);
|
||||||
|
hdl_param_handle.update_hdl_file(
|
||||||
|
escape_path_string.to_string(),
|
||||||
|
fast,
|
||||||
|
parse_result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
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);
|
||||||
@ -879,7 +879,11 @@ pub fn vhdl_parser_pipeline(
|
|||||||
};
|
};
|
||||||
|
|
||||||
fast.file_type = file_type;
|
fast.file_type = file_type;
|
||||||
hdl_param_handle.update_fast(escape_path_string.to_string(), fast.clone());
|
hdl_param_handle.update_hdl_file(
|
||||||
|
escape_path_string.to_string(),
|
||||||
|
fast.clone(),
|
||||||
|
sv_parser::common::ParseResult::new()
|
||||||
|
);
|
||||||
let scope_tree = get_scopes_from_vhdl_fast(&fast, doc, uri);
|
let scope_tree = get_scopes_from_vhdl_fast(&fast, doc, uri);
|
||||||
scope_tree
|
scope_tree
|
||||||
} else {
|
} else {
|
||||||
|
@ -332,7 +332,7 @@ mod test_scope_tree {
|
|||||||
let result = recovery_sv_parse_with_retry(&doc, &uri, &None, &includes);
|
let result = recovery_sv_parse_with_retry(&doc, &uri, &None, &includes);
|
||||||
// let result = recovery_sv_parse(&doc, &uri, &None, &includes, true);
|
// let result = recovery_sv_parse(&doc, &uri, &None, &includes, true);
|
||||||
|
|
||||||
if let Some(syntax_tree) = result {
|
if let Some((syntax_tree, _)) = result {
|
||||||
let file_url = format!("file://{}", file_path);
|
let file_url = format!("file://{}", file_path);
|
||||||
let uri = Url::parse(&file_url);
|
let uri = Url::parse(&file_url);
|
||||||
if let Ok(uri) = uri {
|
if let Ok(uri) = uri {
|
||||||
|
@ -8,13 +8,11 @@ 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.hdl_param.path_to_hdl_file.read().unwrap();
|
let path_to_hdl_file = self.srcs.hdl_param.path_to_hdl_file.read().unwrap();
|
||||||
for path in fast_map.keys() {
|
for (path, hdl_file) in path_to_hdl_file.iter() {
|
||||||
if let Some(hdl_file) = fast_map.get(path) {
|
for define in &hdl_file.fast.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()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::{env::consts::OS, path::{Path, PathBuf}};
|
use std::{env::consts::OS, path::{Path, PathBuf}, str::FromStr};
|
||||||
|
|
||||||
|
use log::info;
|
||||||
use percent_encoding::percent_decode_str;
|
use percent_encoding::percent_decode_str;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use ropey::RopeSlice;
|
use ropey::RopeSlice;
|
||||||
@ -176,6 +177,29 @@ pub fn to_escape_path(path: &PathBuf) -> PathBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 将 uri 转换为 digital lsp 内部使用的路径字符串
|
||||||
|
/// 比如 hdlparam 里面有一些以 String 作为主键的 hashmap
|
||||||
|
/// 它们的 String 如果代表路径,那么都是通过该函数从 uri 转换而来的
|
||||||
|
pub fn from_uri_to_escape_path_string(
|
||||||
|
uri: &Url
|
||||||
|
) -> Option<String> {
|
||||||
|
let path = match PathBuf::from_str(uri.path()) {
|
||||||
|
Ok(path) => path,
|
||||||
|
Err(error) => {
|
||||||
|
info!("PathBuf::from_str(uri.path()) 发生错误 {:?}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let escape_path = to_escape_path(&path);
|
||||||
|
let escape_path_string = escape_path.to_str().unwrap_or("");
|
||||||
|
if escape_path_string.len() == 0 {
|
||||||
|
info!("escape_path_string 为空");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(escape_path_string.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_lsp_pos(position: vhdl_lang::Position) -> Position {
|
pub fn to_lsp_pos(position: vhdl_lang::Position) -> Position {
|
||||||
Position {
|
Position {
|
||||||
line: position.line,
|
line: position.line,
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit f04201227d9811e595add86510cb3d4cc4191eb5
|
Subproject commit bf73f0e4ef0ab048704d52b468985d6630f77a1e
|
Loading…
x
Reference in New Issue
Block a user