完成 verilator 的诊断
This commit is contained in:
parent
b1b302bbfb
commit
7dd4f58da6
@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use ropey::Rope;
|
use ropey::Rope;
|
||||||
use tower_lsp::lsp_types::{Diagnostic, Url};
|
use tower_lsp::lsp_types::{Diagnostic, Url};
|
||||||
|
|
||||||
use crate::server::LspServer;
|
use crate::{server::LspServer, utils::command::is_command_valid};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
@ -35,32 +35,28 @@ pub trait AbstractLinterConfiguration {
|
|||||||
/// 提供一次诊断目前基于 uri 中的地址读取真实路径来获取诊断结果
|
/// 提供一次诊断目前基于 uri 中的地址读取真实路径来获取诊断结果
|
||||||
fn provide_diagnostics(&self, uri: &Url, rope: &Rope, server: &LspServer) -> Option<Vec<Diagnostic>>;
|
fn provide_diagnostics(&self, uri: &Url, rope: &Rope, server: &LspServer) -> Option<Vec<Diagnostic>>;
|
||||||
|
|
||||||
/// 获取工具在 Windows 下的后缀,比如 iverilog 就是 exe , xvlog 就是 bat
|
|
||||||
fn get_windows_extension(&self) -> &str;
|
|
||||||
|
|
||||||
/// 获取 linter 安装路径,内部实现,内部调用
|
/// 获取 linter 安装路径,内部实现,内部调用
|
||||||
fn get_linter_path(&self) -> &str;
|
fn get_linter_path(&self) -> &str;
|
||||||
|
|
||||||
|
/// 获取 可执行文件 的名字,比如
|
||||||
|
/// - iverilog.exe
|
||||||
|
/// - iverilog
|
||||||
|
/// - xvlog.bat
|
||||||
|
fn get_exe_name(&self) -> String;
|
||||||
|
|
||||||
/// 获取真实调用路径,比如
|
/// 获取真实调用路径,比如
|
||||||
/// iverilog.exe 或者 /path/to/verilog.exe
|
/// iverilog.exe 或者 /path/to/verilog.exe
|
||||||
fn get_invoke_name(&self, execute_name: &str) -> String {
|
fn get_invoke_name(&self) -> String {
|
||||||
let suffix = {
|
let exe_name = self.get_exe_name();
|
||||||
let os = std::env::consts::OS;
|
|
||||||
if os == "windows" {
|
|
||||||
self.get_windows_extension()
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let linter_path = self.get_linter_path();
|
let linter_path = self.get_linter_path();
|
||||||
let pathbuf = PathBuf::from_str(linter_path);
|
let pathbuf = PathBuf::from_str(linter_path);
|
||||||
if linter_path.len() == 0 || !pathbuf.as_ref().unwrap().exists() {
|
if linter_path.len() == 0 || !pathbuf.as_ref().unwrap().exists() {
|
||||||
format!("{}{}", execute_name, suffix)
|
exe_name.to_string()
|
||||||
} else {
|
} else {
|
||||||
// 路径存在
|
// 路径存在
|
||||||
let pathbuf = pathbuf.unwrap();
|
let pathbuf = pathbuf.unwrap();
|
||||||
let pathbuf = pathbuf.join(format!("{}{}", execute_name, suffix));
|
let pathbuf = pathbuf.join(exe_name);
|
||||||
let path_string = pathbuf.to_str().unwrap();
|
let path_string = pathbuf.to_str().unwrap();
|
||||||
path_string.to_string()
|
path_string.to_string()
|
||||||
}
|
}
|
||||||
@ -69,7 +65,15 @@ pub trait AbstractLinterConfiguration {
|
|||||||
/// 获取与该工具匹配的诊断器名字与调用函数名。并检查它们是否有效
|
/// 获取与该工具匹配的诊断器名字与调用函数名。并检查它们是否有效
|
||||||
///
|
///
|
||||||
/// 参考链接:https://kirigaya.cn/blog/article?seq=284
|
/// 参考链接:https://kirigaya.cn/blog/article?seq=284
|
||||||
fn linter_status(&self) -> LinterStatus;
|
fn linter_status(&self) -> LinterStatus {
|
||||||
|
let invoke_name = self.get_invoke_name();
|
||||||
|
let available = is_command_valid(&invoke_name);
|
||||||
|
LinterStatus {
|
||||||
|
tool_name: self.get_exe_name(),
|
||||||
|
available,
|
||||||
|
invoke_name
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// rope 的第 line_index 行文字中,第一个和最后一个非空字符在本行的索引
|
/// rope 的第 line_index 行文字中,第一个和最后一个非空字符在本行的索引
|
||||||
|
@ -54,7 +54,7 @@ impl AbstractLinterConfiguration for IverilogConfiguration {
|
|||||||
) -> Option<Vec<Diagnostic>> {
|
) -> Option<Vec<Diagnostic>> {
|
||||||
let mut diagnostics = Vec::<Diagnostic>::new();
|
let mut diagnostics = Vec::<Diagnostic>::new();
|
||||||
|
|
||||||
let invoke_name = self.get_invoke_name("iverilog");
|
let invoke_name = self.get_invoke_name();
|
||||||
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();
|
||||||
|
|
||||||
@ -133,31 +133,15 @@ impl AbstractLinterConfiguration for IverilogConfiguration {
|
|||||||
Some(diagnostics)
|
Some(diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_windows_extension(&self) -> &str {
|
|
||||||
"exe"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_linter_path(&self) -> &str {
|
fn get_linter_path(&self) -> &str {
|
||||||
&self.linter.path
|
&self.linter.path
|
||||||
}
|
}
|
||||||
|
|
||||||
fn linter_status(&self) -> LinterStatus {
|
fn get_exe_name(&self) -> String {
|
||||||
match self.language_id.as_str() {
|
if std::env::consts::OS == "windows" {
|
||||||
"verilog" => {
|
format!("{}.exe", self.linter.exe_name)
|
||||||
let invoke_name = self.get_invoke_name("iverilog");
|
} else {
|
||||||
let available = is_command_valid(&invoke_name);
|
self.linter.exe_name.to_string()
|
||||||
LinterStatus {
|
|
||||||
tool_name: "iverilog".to_string(),
|
|
||||||
available,
|
|
||||||
invoke_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不支持 svlog
|
|
||||||
// 不支持 vhdl
|
|
||||||
_ => {
|
|
||||||
LinterStatus::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,19 +139,19 @@ pub fn update_diagnostics_configuration(
|
|||||||
"iverilog" => {
|
"iverilog" => {
|
||||||
linter_configuration.iverilog.linter.enabled = true;
|
linter_configuration.iverilog.linter.enabled = true;
|
||||||
linter_configuration.iverilog.linter.path = linter_path.to_string();
|
linter_configuration.iverilog.linter.path = linter_path.to_string();
|
||||||
let invoke_name = linter_configuration.iverilog.get_invoke_name("iverilog");
|
let invoke_name = linter_configuration.iverilog.get_invoke_name();
|
||||||
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
||||||
}
|
}
|
||||||
"verilator" => {
|
"verilator" => {
|
||||||
linter_configuration.verilator.linter.enabled = true;
|
linter_configuration.verilator.linter.enabled = true;
|
||||||
linter_configuration.verilator.linter.path = linter_path.to_string();
|
linter_configuration.verilator.linter.path = linter_path.to_string();
|
||||||
let invoke_name = linter_configuration.verilator.get_invoke_name("verilator");
|
let invoke_name = linter_configuration.verilator.get_invoke_name();
|
||||||
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
||||||
}
|
}
|
||||||
"verible" => {
|
"verible" => {
|
||||||
linter_configuration.verible.linter.enabled = true;
|
linter_configuration.verible.linter.enabled = true;
|
||||||
linter_configuration.verible.linter.path = linter_path.to_string();
|
linter_configuration.verible.linter.path = linter_path.to_string();
|
||||||
let invoke_name = linter_configuration.verible.get_invoke_name("verible-verilog-syntax");
|
let invoke_name = linter_configuration.verible.get_invoke_name();
|
||||||
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
||||||
}
|
}
|
||||||
"modelsim" => {
|
"modelsim" => {
|
||||||
@ -159,9 +159,9 @@ pub fn update_diagnostics_configuration(
|
|||||||
linter_configuration.modelsim.linter.path = linter_path.to_string();
|
linter_configuration.modelsim.linter.path = linter_path.to_string();
|
||||||
let invoke_name = {
|
let invoke_name = {
|
||||||
if language_id == "vhdl" {
|
if language_id == "vhdl" {
|
||||||
linter_configuration.modelsim.get_invoke_name("vcom")
|
linter_configuration.modelsim.get_invoke_name()
|
||||||
} else {
|
} else {
|
||||||
linter_configuration.modelsim.get_invoke_name("vlog")
|
linter_configuration.modelsim.get_invoke_name()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
||||||
@ -171,9 +171,9 @@ pub fn update_diagnostics_configuration(
|
|||||||
linter_configuration.vivado.linter.path = linter_path.to_string();
|
linter_configuration.vivado.linter.path = linter_path.to_string();
|
||||||
let invoke_name = {
|
let invoke_name = {
|
||||||
if language_id == "vhdl" {
|
if language_id == "vhdl" {
|
||||||
linter_configuration.vivado.get_invoke_name("xvhdl")
|
linter_configuration.vivado.get_invoke_name()
|
||||||
} else {
|
} else {
|
||||||
linter_configuration.vivado.get_invoke_name("xvlog")
|
linter_configuration.vivado.get_invoke_name()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
||||||
|
@ -56,49 +56,15 @@ impl AbstractLinterConfiguration for ModelsimConfiguration {
|
|||||||
Some(diagnostics)
|
Some(diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_windows_extension(&self) -> &str {
|
|
||||||
"exe"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_linter_path(&self) -> &str {
|
fn get_linter_path(&self) -> &str {
|
||||||
&self.linter.path
|
&self.linter.path
|
||||||
}
|
}
|
||||||
|
|
||||||
fn linter_status(&self) -> LinterStatus {
|
fn get_exe_name(&self) -> String {
|
||||||
match self.language_id.as_str() {
|
if std::env::consts::OS == "windows" {
|
||||||
"verilog" => {
|
format!("{}.exe", self.linter.exe_name)
|
||||||
let invoke_name = self.get_invoke_name("vlog");
|
} else {
|
||||||
let available = is_command_valid(&invoke_name);
|
self.linter.exe_name.to_string()
|
||||||
LinterStatus {
|
|
||||||
tool_name: "vlog".to_string(),
|
|
||||||
available,
|
|
||||||
invoke_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"systemverilog" => {
|
|
||||||
let invoke_name = self.get_invoke_name("vlog");
|
|
||||||
let available = is_command_valid(&invoke_name);
|
|
||||||
LinterStatus {
|
|
||||||
tool_name: "vlog".to_string(),
|
|
||||||
available,
|
|
||||||
invoke_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"vhdl" => {
|
|
||||||
let invoke_name = self.get_invoke_name("vcom");
|
|
||||||
let available = is_command_valid(&invoke_name);
|
|
||||||
LinterStatus {
|
|
||||||
tool_name: "vcom".to_string(),
|
|
||||||
available,
|
|
||||||
invoke_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
LinterStatus::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -142,36 +142,11 @@ impl AbstractLinterConfiguration for VeribleConfiguration {
|
|||||||
&self.linter.path
|
&self.linter.path
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_windows_extension(&self) -> &str {
|
fn get_exe_name(&self) -> String {
|
||||||
"exe"
|
if std::env::consts::OS == "windows" {
|
||||||
}
|
format!("{}.exe", self.linter.exe_name)
|
||||||
|
} else {
|
||||||
fn linter_status(&self) -> LinterStatus {
|
self.linter.exe_name.to_string()
|
||||||
match self.language_id.as_str() {
|
|
||||||
"verilog" => {
|
|
||||||
let invoke_name = self.get_invoke_name("verible-verilog-syntax");
|
|
||||||
let available = is_command_valid(&invoke_name);
|
|
||||||
LinterStatus {
|
|
||||||
tool_name: "verible-verilog-syntax".to_string(),
|
|
||||||
available,
|
|
||||||
invoke_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"systemverilog" => {
|
|
||||||
let invoke_name = self.get_invoke_name("verible-verilog-syntax");
|
|
||||||
let available = is_command_valid(&invoke_name);
|
|
||||||
LinterStatus {
|
|
||||||
tool_name: "verible-verilog-syntax".to_string(),
|
|
||||||
available,
|
|
||||||
invoke_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// verible 不支持 vhdl
|
|
||||||
_ => {
|
|
||||||
LinterStatus::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
use log::info;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use ropey::Rope;
|
use ropey::Rope;
|
||||||
@ -139,6 +140,97 @@ impl AbstractLinterConfiguration for VerilatorConfiguration {
|
|||||||
server: &LspServer
|
server: &LspServer
|
||||||
) -> Option<Vec<Diagnostic>> {
|
) -> Option<Vec<Diagnostic>> {
|
||||||
let mut diagnostics = Vec::<Diagnostic>::new();
|
let mut diagnostics = Vec::<Diagnostic>::new();
|
||||||
|
|
||||||
|
let invoke_name = self.get_invoke_name();
|
||||||
|
let pathbuf = uri.to_file_path().unwrap();
|
||||||
|
let path_string = pathbuf.to_str().unwrap();
|
||||||
|
|
||||||
|
let child = Command::new(&invoke_name)
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.args(&self.linter.args)
|
||||||
|
.arg(path_string)
|
||||||
|
.spawn()
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
let output = child.wait_with_output().ok()?;
|
||||||
|
let output_string = String::from_utf8(output.stderr).ok()?;
|
||||||
|
|
||||||
|
info!("verilator linter: {:?}, output:\n{}", path_string, output_string);
|
||||||
|
|
||||||
|
static REGEX_STORE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();
|
||||||
|
let regex = REGEX_STORE.get_or_init(|| { Regex::new(r"%(?P<severity>Error|Warning)(-(?P<warning_type>[A-Z0-9_]+))?: (?P<filepath>[^:]+):(?P<line>\d+):((?P<col>\d+):)? ?(?P<message>.*)").unwrap() });
|
||||||
|
|
||||||
|
// verilator 错误输出样例
|
||||||
|
// %Warning-IMPLICIT: library/Apply/Comm/FDE/AGC/AGC.v:23:12: Signal definition not found, creating implicitly: 'r_rms'
|
||||||
|
// : ... Suggested alternative: 'ref_rms'
|
||||||
|
// 23 | assign r_rms = (reference * reference);
|
||||||
|
// | ^~~~~
|
||||||
|
// ... Use "/* verilator lint_off IMPLICIT */" and lint_on around source to disable this message.
|
||||||
|
// %Error: Exiting due to 5 warning(s)
|
||||||
|
|
||||||
|
// 先将上面的输出处理为一整块一整块的数组,每块分解为两个部分:第一行(用于解析行号和列号)和后面几行(具体错误地址)
|
||||||
|
let mut error_tuples = Vec::<(String, String)>::new();
|
||||||
|
let mut current_error_tuple: Option<(&str, Vec<&str>)> = None;
|
||||||
|
for error_line in output_string.lines() {
|
||||||
|
if error_line.starts_with("%") {
|
||||||
|
if let Some((first, ref description)) = current_error_tuple {
|
||||||
|
error_tuples.push((first.to_string(), description.join("\n")));
|
||||||
|
}
|
||||||
|
current_error_tuple = Some((error_line, Vec::<&str>::new()));
|
||||||
|
} else {
|
||||||
|
if let Some((_, ref mut description)) = current_error_tuple {
|
||||||
|
description.push(error_line);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for error_tuple in error_tuples {
|
||||||
|
let captures = match regex.captures(error_tuple.0.as_str()) {
|
||||||
|
Some(caps) => caps,
|
||||||
|
None => continue
|
||||||
|
};
|
||||||
|
// 因为 verilator 会递归检查,因此报错信息中可能会出现非本文件内的信息
|
||||||
|
if captures.name("filepath")?.as_str().replace("\\", "/") != path_string {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let line: u32 = captures.name("line")?.as_str().to_string().parse().ok()?;
|
||||||
|
let col: u32 = captures.name("col").map_or("1", |m| m.as_str()).parse().ok()?;
|
||||||
|
|
||||||
|
// verilator 的诊断索引都是 one index 的
|
||||||
|
let pos = Position::new(line - 1, col - 1);
|
||||||
|
let severity = verilator_severity(captures.name("severity")?.as_str());
|
||||||
|
|
||||||
|
let message = match severity {
|
||||||
|
Some(DiagnosticSeverity::ERROR) => captures.name("message")?.as_str().to_string(),
|
||||||
|
Some(DiagnosticSeverity::WARNING) => format!(
|
||||||
|
"{}: {}",
|
||||||
|
captures.name("warning_type")?.as_str(),
|
||||||
|
captures.name("message")?.as_str()
|
||||||
|
),
|
||||||
|
_ => "".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let message = format!("{}\n\n---\n\n{}", message, error_tuple.1);
|
||||||
|
|
||||||
|
let diagnostic = Diagnostic {
|
||||||
|
range: Range::new(pos, pos),
|
||||||
|
code: None,
|
||||||
|
severity,
|
||||||
|
source: Some("Digital IDE: verilator".to_string()),
|
||||||
|
message,
|
||||||
|
related_information: None,
|
||||||
|
tags: None,
|
||||||
|
code_description: None,
|
||||||
|
data: None
|
||||||
|
};
|
||||||
|
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
Some(diagnostics)
|
Some(diagnostics)
|
||||||
}
|
}
|
||||||
@ -147,36 +239,11 @@ impl AbstractLinterConfiguration for VerilatorConfiguration {
|
|||||||
&self.linter.path
|
&self.linter.path
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_windows_extension(&self) -> &str {
|
fn get_exe_name(&self) -> String {
|
||||||
"exe"
|
if std::env::consts::OS == "windows" {
|
||||||
}
|
format!("{}.exe", self.linter.exe_name)
|
||||||
|
} else {
|
||||||
fn linter_status(&self) -> LinterStatus {
|
self.linter.exe_name.to_string()
|
||||||
match self.language_id.as_str() {
|
|
||||||
"verilog" => {
|
|
||||||
let invoke_name = self.get_invoke_name("verilator");
|
|
||||||
let available = is_command_valid(&invoke_name);
|
|
||||||
LinterStatus {
|
|
||||||
tool_name: "verilator".to_string(),
|
|
||||||
available,
|
|
||||||
invoke_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"systemverilog" => {
|
|
||||||
let invoke_name = self.get_invoke_name("verilator");
|
|
||||||
let available = is_command_valid(&invoke_name);
|
|
||||||
LinterStatus {
|
|
||||||
tool_name: "verilator".to_string(),
|
|
||||||
available,
|
|
||||||
invoke_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// verilator 不支持 vhdl
|
|
||||||
_ => {
|
|
||||||
LinterStatus::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -59,45 +59,11 @@ impl AbstractLinterConfiguration for VivadoConfiguration {
|
|||||||
&self.linter.path
|
&self.linter.path
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_windows_extension(&self) -> &str {
|
fn get_exe_name(&self) -> String {
|
||||||
"exe"
|
if std::env::consts::OS == "windows" {
|
||||||
}
|
format!("{}.bat", self.linter.exe_name)
|
||||||
|
} else {
|
||||||
fn linter_status(&self) -> LinterStatus {
|
self.linter.exe_name.to_string()
|
||||||
match self.language_id.as_str() {
|
|
||||||
"verilog" => {
|
|
||||||
let invoke_name = self.get_invoke_name("xvlog");
|
|
||||||
let available = is_command_valid(&invoke_name);
|
|
||||||
LinterStatus {
|
|
||||||
tool_name: "xvlog".to_string(),
|
|
||||||
available,
|
|
||||||
invoke_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"systemverilog" => {
|
|
||||||
let invoke_name = self.get_invoke_name("xvlog");
|
|
||||||
let available = is_command_valid(&invoke_name);
|
|
||||||
LinterStatus {
|
|
||||||
tool_name: "xvlog".to_string(),
|
|
||||||
available,
|
|
||||||
invoke_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"vhdl" => {
|
|
||||||
let invoke_name = self.get_invoke_name("xvhdl");
|
|
||||||
let available = is_command_valid(&invoke_name);
|
|
||||||
LinterStatus {
|
|
||||||
tool_name: "xvhdl".to_string(),
|
|
||||||
available,
|
|
||||||
invoke_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
LinterStatus::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,7 +17,12 @@ pub fn inlay_hint(server: &LspServer, params: &InlayHintParams) -> Option<Vec<In
|
|||||||
|
|
||||||
let fast_map = server.srcs.hdl_param.path_to_hdl_file.read().unwrap();
|
let fast_map = server.srcs.hdl_param.path_to_hdl_file.read().unwrap();
|
||||||
let file_id = server.srcs.get_id(¶ms.text_document.uri);
|
let file_id = server.srcs.get_id(¶ms.text_document.uri);
|
||||||
let file = server.srcs.get_file(file_id).unwrap();
|
let file = server.srcs.get_file(file_id);
|
||||||
|
if file.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let file = file.unwrap();
|
||||||
let file = file.read().unwrap();
|
let file = file.read().unwrap();
|
||||||
let rope = &file.text;
|
let rope = &file.text;
|
||||||
// 先找到 当前 所在的 hdlfile
|
// 先找到 当前 所在的 hdlfile
|
||||||
|
Loading…
x
Reference in New Issue
Block a user