更好的 vivado 诊断器
This commit is contained in:
parent
4db6837029
commit
36ba7a350d
@ -38,7 +38,7 @@ impl Default for CacheItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct CacheInfo {
|
pub struct CacheInfo {
|
||||||
// version
|
// version
|
||||||
pub version: Option<String>,
|
pub version: Option<String>,
|
||||||
/// 解析类型文件缓存的根目录
|
/// 解析类型文件缓存的根目录
|
||||||
|
@ -61,7 +61,18 @@ impl AbstractLinterConfiguration for ModelsimConfiguration {
|
|||||||
let pathbuf = uri.to_file_path().unwrap();
|
let pathbuf = uri.to_file_path().unwrap();
|
||||||
let path_string = pathbuf.to_str().unwrap();
|
let path_string = pathbuf.to_str().unwrap();
|
||||||
|
|
||||||
|
let cache_info = server.cache.cache_info.read().unwrap();
|
||||||
|
|
||||||
|
let cwd = match &cache_info.linter_cache {
|
||||||
|
Some(pc) => pc,
|
||||||
|
None => {
|
||||||
|
info!("缓存系统尚未完成初始化,本次诊断取消");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let child = Command::new(&invoke_name)
|
let child = Command::new(&invoke_name)
|
||||||
|
.current_dir(cwd)
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
@ -73,10 +84,10 @@ impl AbstractLinterConfiguration for ModelsimConfiguration {
|
|||||||
let output = child.wait_with_output().ok()?;
|
let output = child.wait_with_output().ok()?;
|
||||||
let output_string = String::from_utf8(output.stdout).ok()?;
|
let output_string = String::from_utf8(output.stdout).ok()?;
|
||||||
|
|
||||||
info!("vivado linter: {:?}, output:\n{}", path_string, output_string);
|
info!("modelsim linter: {:?}, output:\n{}", path_string, output_string);
|
||||||
|
|
||||||
static REGEX_STORE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();
|
static REGEX_STORE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();
|
||||||
let regex = REGEX_STORE.get_or_init(|| { Regex::new(r"ERROR: \[VRFC \d+-\d+\] (?P<description>.+) \[(?P<file>.+):(?P<line>\d+)\]").unwrap() });
|
let regex = REGEX_STORE.get_or_init(|| { Regex::new(r"\*\* (Error|Warning): \(\S+\) (?P<file>.*?)(\((?P<line>\d+)\))?: (?P<description>.+)").unwrap() });
|
||||||
|
|
||||||
for error_line in output_string.lines() {
|
for error_line in output_string.lines() {
|
||||||
let caps = match regex.captures(error_line) {
|
let caps = match regex.captures(error_line) {
|
||||||
@ -84,6 +95,8 @@ impl AbstractLinterConfiguration for ModelsimConfiguration {
|
|||||||
None => continue
|
None => continue
|
||||||
};
|
};
|
||||||
|
|
||||||
|
info!("get caps: {:?}", caps);
|
||||||
|
|
||||||
let error_description = caps.name("description").unwrap().as_str();
|
let error_description = caps.name("description").unwrap().as_str();
|
||||||
let error_no = caps.name("line").unwrap().as_str();
|
let error_no = caps.name("line").unwrap().as_str();
|
||||||
let error_no = match error_no.parse::<usize>() {
|
let error_no = match error_no.parse::<usize>() {
|
||||||
|
@ -2,8 +2,9 @@ use std::process::{Command, Stdio};
|
|||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
use regex::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};
|
use crate::{diagnostics::find_non_whitespace_indices, server::LspServer};
|
||||||
use ropey::Rope;
|
use ropey::Rope;
|
||||||
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range, Url};
|
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range, Url};
|
||||||
@ -60,7 +61,18 @@ impl AbstractLinterConfiguration for VivadoConfiguration {
|
|||||||
let pathbuf = uri.to_file_path().unwrap();
|
let pathbuf = uri.to_file_path().unwrap();
|
||||||
let path_string = pathbuf.to_str().unwrap();
|
let path_string = pathbuf.to_str().unwrap();
|
||||||
|
|
||||||
|
let cache_info = server.cache.cache_info.read().unwrap();
|
||||||
|
|
||||||
|
let cwd = match &cache_info.linter_cache {
|
||||||
|
Some(pc) => pc,
|
||||||
|
None => {
|
||||||
|
info!("缓存系统尚未完成初始化,本次诊断取消");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let child = Command::new(&invoke_name)
|
let child = Command::new(&invoke_name)
|
||||||
|
.current_dir(cwd)
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
@ -75,7 +87,7 @@ impl AbstractLinterConfiguration for VivadoConfiguration {
|
|||||||
info!("vivado linter: {:?}, output:\n{}", path_string, output_string);
|
info!("vivado linter: {:?}, output:\n{}", path_string, output_string);
|
||||||
|
|
||||||
static REGEX_STORE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();
|
static REGEX_STORE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();
|
||||||
let regex = REGEX_STORE.get_or_init(|| { Regex::new(r"ERROR: \[VRFC \d+-\d+\] (?P<description>.+) \[(?P<file>.+):(?P<line>\d+)\]").unwrap() });
|
let regex = REGEX_STORE.get_or_init(|| { Regex::new(r"ERROR: \[VRFC (?P<error_code>\S+)] (?P<description>.+) \[(?P<file>.+):(?P<line>\d+)\]").unwrap() });
|
||||||
|
|
||||||
for error_line in output_string.lines() {
|
for error_line in output_string.lines() {
|
||||||
let caps = match regex.captures(error_line) {
|
let caps = match regex.captures(error_line) {
|
||||||
@ -83,6 +95,7 @@ impl AbstractLinterConfiguration for VivadoConfiguration {
|
|||||||
None => continue
|
None => continue
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let error_code = caps.name("error_code").unwrap().as_str();
|
||||||
let error_description = caps.name("description").unwrap().as_str();
|
let error_description = caps.name("description").unwrap().as_str();
|
||||||
let error_no = caps.name("line").unwrap().as_str();
|
let error_no = caps.name("line").unwrap().as_str();
|
||||||
let error_no = match error_no.parse::<usize>() {
|
let error_no = match error_no.parse::<usize>() {
|
||||||
@ -91,7 +104,8 @@ impl AbstractLinterConfiguration for VivadoConfiguration {
|
|||||||
Err(_) => 0
|
Err(_) => 0
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((start_char, end_char)) = find_non_whitespace_indices(rope, error_no) {
|
|
||||||
|
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 },
|
||||||
end: Position { line: error_no as u32, character: end_char as u32 }
|
end: Position { line: error_no as u32, character: end_char as u32 }
|
||||||
@ -127,4 +141,46 @@ impl AbstractLinterConfiguration for VivadoConfiguration {
|
|||||||
self.linter.exe_name.to_string()
|
self.linter.exe_name.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 根据 vivado 返回的诊断信息,返回适合的错误在那一行的起始位置
|
||||||
|
/// 默认是返回该行的第一个非空字符到最后一个非空字符中间的位置,即 find_non_whitespace_indices
|
||||||
|
fn find_vivado_suitable_range(
|
||||||
|
rope: &Rope,
|
||||||
|
error_no: usize,
|
||||||
|
error_description: &str
|
||||||
|
) -> Option<(usize, usize)> {
|
||||||
|
// 一般 vivado 会把出错的关键词用单引号包起来
|
||||||
|
// 只需要提取这个单词,并在行中匹配它,如果任何一步失败,都采用 find_non_whitespace_indices 即可
|
||||||
|
static REGEX_STORE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();
|
||||||
|
let regex = REGEX_STORE.get_or_init(|| { Regex::new(r"'([^']+)'").unwrap() });
|
||||||
|
let error_keyword = match regex.captures(error_description) {
|
||||||
|
Some(caps) => {
|
||||||
|
caps.get(1).unwrap().as_str()
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return find_non_whitespace_indices(rope, error_no)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let error_keyword = escape(error_keyword);
|
||||||
|
let pattern = format!(r"\b(?i){}\b", error_keyword);
|
||||||
|
let regex = Regex::new(&pattern).unwrap();
|
||||||
|
|
||||||
|
info!("find keyword: {:?}", error_keyword);
|
||||||
|
|
||||||
|
if let Some(line_text) = rope.line(error_no).as_str() {
|
||||||
|
// 处理特殊情况: error_keyword 为 ;
|
||||||
|
if error_keyword == ";" {
|
||||||
|
if let Some(index) = line_text.find(";") {
|
||||||
|
return Some((index, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(mat) = regex.find(line_text) {
|
||||||
|
info!("mat {} {}", mat.start(), mat.end());
|
||||||
|
return Some((mat.start(), mat.end()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
find_non_whitespace_indices(rope, error_no)
|
||||||
}
|
}
|
@ -333,7 +333,7 @@ fn do_vhdl_fast(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 将后端新的 fast 同步到前端去
|
||||||
pub fn sync_fast(
|
pub fn sync_fast(
|
||||||
path: String,
|
path: String,
|
||||||
file_type: String,
|
file_type: String,
|
||||||
@ -360,6 +360,7 @@ pub fn sync_fast(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let hdl_param = backend.server.srcs.hdl_param.clone();
|
let hdl_param = backend.server.srcs.hdl_param.clone();
|
||||||
|
// TODO: 检查加锁的有效性,因为前端在请求该方法时,后端可能仍然在计算
|
||||||
let path_to_hdl_file = hdl_param.path_to_hdl_file.read().unwrap();
|
let path_to_hdl_file = hdl_param.path_to_hdl_file.read().unwrap();
|
||||||
if let Some(hdl_file) = path_to_hdl_file.get(&path) {
|
if let Some(hdl_file) = path_to_hdl_file.get(&path) {
|
||||||
let fast = hdl_file.fast.clone();
|
let fast = hdl_file.fast.clone();
|
||||||
|
@ -874,9 +874,9 @@ pub fn vhdl_parser_pipeline(
|
|||||||
let parse_ir = ParseIR::DesignFile(design_file);
|
let parse_ir = ParseIR::DesignFile(design_file);
|
||||||
file.parse_ir = Some(parse_ir);
|
file.parse_ir = Some(parse_ir);
|
||||||
|
|
||||||
for module in &fast.content {
|
// for module in &fast.content {
|
||||||
info!("parse port number: {:?}", module.ports.len());
|
// info!("parse port number: {:?}", module.ports.len());
|
||||||
}
|
// }
|
||||||
|
|
||||||
let file_type = {
|
let file_type = {
|
||||||
let fast_map = hdl_param_handle.path_to_hdl_file.read().unwrap();
|
let fast_map = hdl_param_handle.path_to_hdl_file.read().unwrap();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user