完成诊断器架构重新设计
This commit is contained in:
parent
7824b74c9a
commit
e726fffd99
9
.vscode/lsp.code-snippets
vendored
9
.vscode/lsp.code-snippets
vendored
@ -35,5 +35,14 @@
|
|||||||
"\t}",
|
"\t}",
|
||||||
"}",
|
"}",
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"new": {
|
||||||
|
"scope": "rust",
|
||||||
|
"prefix": "new",
|
||||||
|
"body": [
|
||||||
|
"pub fn new($1) -> Self {",
|
||||||
|
"\t$2",
|
||||||
|
"}"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
66
src/diagnostics/common.rs
Normal file
66
src/diagnostics/common.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use std::{path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct LinterStatus {
|
||||||
|
pub tool_name: String,
|
||||||
|
pub available: bool,
|
||||||
|
pub invoke_name: String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Default for LinterStatus {
|
||||||
|
fn default() -> Self {
|
||||||
|
LinterStatus {
|
||||||
|
tool_name: "".to_string(),
|
||||||
|
available: false,
|
||||||
|
invoke_name: "".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait AbstractLinterConfiguration {
|
||||||
|
fn new(language_id: &str) -> Self;
|
||||||
|
|
||||||
|
/// 提供一次诊断
|
||||||
|
fn provide_diagnostics(&self);
|
||||||
|
|
||||||
|
|
||||||
|
/// 获取工具在 Windows 下的后缀,比如 iverilog 就是 exe , xvlog 就是 bat
|
||||||
|
fn get_windows_extension(&self) -> &str;
|
||||||
|
|
||||||
|
fn get_linter_path(&self) -> &str;
|
||||||
|
|
||||||
|
/// 获取真实调用路径,比如
|
||||||
|
///
|
||||||
|
/// iverilog.exe 或者 /path/to/verilog.exe
|
||||||
|
fn get_invoke_name(&self, execute_name: &str) -> String {
|
||||||
|
let suffix = {
|
||||||
|
let os = std::env::consts::OS;
|
||||||
|
if os == "windows" {
|
||||||
|
self.get_windows_extension()
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let linter_path = self.get_linter_path();
|
||||||
|
let pathbuf = PathBuf::from_str(linter_path);
|
||||||
|
if linter_path.len() == 0 || !pathbuf.as_ref().unwrap().exists() {
|
||||||
|
format!("{}{}", execute_name, suffix)
|
||||||
|
} else {
|
||||||
|
// 路径存在
|
||||||
|
let pathbuf = pathbuf.unwrap();
|
||||||
|
let pathbuf = pathbuf.join(format!("{}{}", execute_name, suffix));
|
||||||
|
let path_string = pathbuf.to_str().unwrap();
|
||||||
|
path_string.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取与该工具匹配的诊断器名字与调用函数名。并检查它们是否有效
|
||||||
|
///
|
||||||
|
/// 参考链接:https://kirigaya.cn/blog/article?seq=284
|
||||||
|
fn linter_status(&self) -> LinterStatus;
|
||||||
|
}
|
74
src/diagnostics/iverilog.rs
Normal file
74
src/diagnostics/iverilog.rs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
use std::{path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::utils::command::is_command_valid;
|
||||||
|
|
||||||
|
use super::{AbstractLinterConfiguration, LinterStatus};
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct IverilogConfiguration {
|
||||||
|
pub language_id: String,
|
||||||
|
pub linter: IverilogLinter
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct IverilogLinter {
|
||||||
|
pub name: String,
|
||||||
|
/// 目前是否启动
|
||||||
|
pub enabled: bool,
|
||||||
|
pub path: String,
|
||||||
|
pub args: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for IverilogLinter {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
name: "iverilog".to_string(),
|
||||||
|
enabled: false,
|
||||||
|
path: "iverilog".to_string(),
|
||||||
|
args: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbstractLinterConfiguration for IverilogConfiguration {
|
||||||
|
fn new(language_id: &str) -> Self {
|
||||||
|
IverilogConfiguration {
|
||||||
|
language_id: language_id.to_string(),
|
||||||
|
linter: IverilogLinter::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn provide_diagnostics(&self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_windows_extension(&self) -> &str {
|
||||||
|
"exe"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_linter_path(&self) -> &str {
|
||||||
|
&self.linter.path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn linter_status(&self) -> LinterStatus {
|
||||||
|
match self.language_id.as_str() {
|
||||||
|
"verilog" => {
|
||||||
|
let invoke_name = self.get_invoke_name("iverilog");
|
||||||
|
let available = is_command_valid(&invoke_name);
|
||||||
|
LinterStatus {
|
||||||
|
tool_name: "iverilog".to_string(),
|
||||||
|
available,
|
||||||
|
invoke_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不支持 svlog
|
||||||
|
// 不支持 vhdl
|
||||||
|
_ => {
|
||||||
|
LinterStatus::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,19 @@
|
|||||||
use std::fs::OpenOptions;
|
|
||||||
|
|
||||||
use crate::{server::{LspConfiguration, LspServer}, utils::get_language_id_by_uri};
|
use crate::{server::{LspConfiguration, LspServer}, utils::get_language_id_by_uri};
|
||||||
use log::info;
|
use log::info;
|
||||||
use ropey::Rope;
|
use ropey::Rope;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
|
pub mod common;
|
||||||
|
|
||||||
|
pub mod iverilog;
|
||||||
pub mod verible;
|
pub mod verible;
|
||||||
pub mod verilator;
|
pub mod verilator;
|
||||||
pub mod vivado;
|
pub mod vivado;
|
||||||
pub mod modelsim;
|
pub mod modelsim;
|
||||||
|
|
||||||
|
pub use common::*;
|
||||||
|
pub use iverilog::*;
|
||||||
pub use verible::*;
|
pub use verible::*;
|
||||||
pub use verilator::*;
|
pub use verilator::*;
|
||||||
pub use vivado::*;
|
pub use vivado::*;
|
||||||
@ -19,6 +22,10 @@ pub use modelsim::*;
|
|||||||
/// description
|
/// description
|
||||||
/// 诊断功能需要提供两套函数,一套函数用于从给定路径读取文件并给出诊断结果;一套用于从 lsp 的文件缓冲区直接读取文本然后给出诊断结果。
|
/// 诊断功能需要提供两套函数,一套函数用于从给定路径读取文件并给出诊断结果;一套用于从 lsp 的文件缓冲区直接读取文本然后给出诊断结果。
|
||||||
/// 前者用于扫描整个项目使用,后者在用户实时修改代码时,给出实时的诊断信息。
|
/// 前者用于扫描整个项目使用,后者在用户实时修改代码时,给出实时的诊断信息。
|
||||||
|
///
|
||||||
|
/// 诊断模块的每一个子诊断器都需要实现如下的函数
|
||||||
|
/// - provide_diagnostics: 提供一次诊断
|
||||||
|
/// -
|
||||||
|
|
||||||
/// 获取诊断核心函数
|
/// 获取诊断核心函数
|
||||||
pub fn provide_diagnostics(
|
pub fn provide_diagnostics(
|
||||||
@ -55,7 +62,7 @@ pub fn provide_diagnostics(
|
|||||||
info!("verilator linter enter");
|
info!("verilator linter enter");
|
||||||
|
|
||||||
} else if linter_configuration.verible.linter.enabled {
|
} else if linter_configuration.verible.linter.enabled {
|
||||||
info!("verilator linter enter");
|
info!("verible linter enter");
|
||||||
|
|
||||||
} else if linter_configuration.modelsim.linter.enabled {
|
} else if linter_configuration.modelsim.linter.enabled {
|
||||||
info!("modelsim linter enter");
|
info!("modelsim linter enter");
|
||||||
@ -103,27 +110,37 @@ pub fn update_diagnostics_configuration(
|
|||||||
linter_configuration.modelsim.linter.enabled = false;
|
linter_configuration.modelsim.linter.enabled = false;
|
||||||
linter_configuration.vivado.linter.enabled = false;
|
linter_configuration.vivado.linter.enabled = false;
|
||||||
|
|
||||||
if linter_configuration.verilator.linter.name == linter_name {
|
match linter_name {
|
||||||
|
"iverilog" => {
|
||||||
|
linter_configuration.iverilog.linter.enabled = true;
|
||||||
|
linter_configuration.iverilog.linter.path = linter_path.to_string();
|
||||||
|
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.iverilog.linter.path);
|
||||||
|
}
|
||||||
|
"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();
|
||||||
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.verilator.linter.path);
|
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.verilator.linter.path);
|
||||||
|
}
|
||||||
} else if linter_configuration.verible.linter.name == linter_name {
|
"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();
|
||||||
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.verible.linter.path);
|
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.verible.linter.path);
|
||||||
|
}
|
||||||
} else if linter_configuration.modelsim.linter.name == linter_name {
|
"modelsim" => {
|
||||||
linter_configuration.modelsim.linter.enabled = true;
|
linter_configuration.modelsim.linter.enabled = true;
|
||||||
linter_configuration.modelsim.linter.path = linter_path.to_string();
|
linter_configuration.modelsim.linter.path = linter_path.to_string();
|
||||||
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.modelsim.linter.path);
|
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.modelsim.linter.path);
|
||||||
|
}
|
||||||
} else if linter_configuration.vivado.linter.name == linter_name {
|
"vivado" => {
|
||||||
linter_configuration.vivado.linter.enabled = true;
|
linter_configuration.vivado.linter.enabled = true;
|
||||||
linter_configuration.vivado.linter.path = linter_path.to_string();
|
linter_configuration.vivado.linter.path = linter_path.to_string();
|
||||||
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.vivado.linter.path);
|
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.vivado.linter.path);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
|
info!("未找到匹配的诊断器: {}", linter_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -141,6 +158,8 @@ pub enum DigitalLinterMode {
|
|||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[derive(serde::Serialize)]
|
#[derive(serde::Serialize)]
|
||||||
pub struct DigitalLinterConfiguration {
|
pub struct DigitalLinterConfiguration {
|
||||||
|
// iverilog 相关的工具配置
|
||||||
|
pub iverilog: IverilogConfiguration,
|
||||||
// verible 相关的工具配置
|
// verible 相关的工具配置
|
||||||
pub verible: VeribleConfiguration,
|
pub verible: VeribleConfiguration,
|
||||||
// verilator 相关的工具配置
|
// verilator 相关的工具配置
|
||||||
@ -151,13 +170,14 @@ pub struct DigitalLinterConfiguration {
|
|||||||
pub vivado: VivadoConfiguration
|
pub vivado: VivadoConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for DigitalLinterConfiguration {
|
impl DigitalLinterConfiguration {
|
||||||
fn default() -> Self {
|
pub fn new(language_id: &str) -> Self {
|
||||||
DigitalLinterConfiguration {
|
DigitalLinterConfiguration {
|
||||||
verible: VeribleConfiguration::default(),
|
iverilog: IverilogConfiguration::new(language_id),
|
||||||
verilator: VerilatorConfiguration::default(),
|
verible: VeribleConfiguration::new(language_id),
|
||||||
modelsim: ModelsimConfiguration::default(),
|
verilator: VerilatorConfiguration::new(language_id),
|
||||||
vivado: VivadoConfiguration::default()
|
modelsim: ModelsimConfiguration::new(language_id),
|
||||||
|
vivado: VivadoConfiguration::new(language_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,15 +1,19 @@
|
|||||||
|
use std::{path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::utils::command::is_command_valid;
|
||||||
|
|
||||||
|
use super::{AbstractLinterConfiguration, LinterStatus};
|
||||||
|
|
||||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
|
||||||
pub struct ModelsimConfiguration {
|
pub struct ModelsimConfiguration {
|
||||||
pub linter: ModelsimLinter,
|
pub language_id: String,
|
||||||
pub format: ModelsimFormat,
|
pub linter: ModelsimLinter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
|
||||||
pub struct ModelsimLinter {
|
pub struct ModelsimLinter {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// 目前是否启动
|
/// 目前是否启动
|
||||||
@ -18,19 +22,12 @@ pub struct ModelsimLinter {
|
|||||||
pub args: Vec<String>,
|
pub args: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct ModelsimFormat {
|
|
||||||
pub enabled: bool,
|
|
||||||
pub path: String,
|
|
||||||
pub args: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ModelsimLinter {
|
impl Default for ModelsimLinter {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: "modelsim".to_string(),
|
name: "modelsim".to_string(),
|
||||||
enabled: true,
|
enabled: false,
|
||||||
path: "Modelsim-verilog-syntax".to_string(),
|
path: "Modelsim-verilog-syntax".to_string(),
|
||||||
args: Vec::new(),
|
args: Vec::new(),
|
||||||
}
|
}
|
||||||
@ -38,16 +35,61 @@ impl Default for ModelsimLinter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Default for ModelsimFormat {
|
impl AbstractLinterConfiguration for ModelsimConfiguration {
|
||||||
fn default() -> Self {
|
fn new(language_id: &str) -> Self {
|
||||||
Self {
|
ModelsimConfiguration {
|
||||||
enabled: true,
|
language_id: language_id.to_string(),
|
||||||
path: "Modelsim-verilog-format".to_string(),
|
linter: ModelsimLinter::default()
|
||||||
args: Vec::new(),
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn provide_diagnostics(&self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_windows_extension(&self) -> &str {
|
||||||
|
"exe"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_linter_path(&self) -> &str {
|
||||||
|
&self.linter.path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn linter_status(&self) -> LinterStatus {
|
||||||
|
match self.language_id.as_str() {
|
||||||
|
"verilog" => {
|
||||||
|
let invoke_name = self.get_invoke_name("vlog");
|
||||||
|
let available = is_command_valid(&invoke_name);
|
||||||
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide_diagnostics() {
|
|
||||||
|
|
||||||
}
|
|
@ -4,16 +4,20 @@ use ropey::Rope;
|
|||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
|
use crate::utils::command::is_command_valid;
|
||||||
|
|
||||||
|
use super::{AbstractLinterConfiguration, LinterStatus};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
|
||||||
pub struct VeribleConfiguration {
|
pub struct VeribleConfiguration {
|
||||||
|
pub language_id: String,
|
||||||
pub linter: VeribleLinter,
|
pub linter: VeribleLinter,
|
||||||
pub format: VeribleFormat,
|
pub format: VeribleFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
|
||||||
pub struct VeribleLinter {
|
pub struct VeribleLinter {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// 目前是否启动
|
/// 目前是否启动
|
||||||
@ -23,7 +27,6 @@ pub struct VeribleLinter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
|
||||||
pub struct VeribleFormat {
|
pub struct VeribleFormat {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub path: String,
|
pub path: String,
|
||||||
@ -34,7 +37,7 @@ impl Default for VeribleLinter {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: "verible".to_string(),
|
name: "verible".to_string(),
|
||||||
enabled: true,
|
enabled: false,
|
||||||
path: "verible-verilog-syntax".to_string(),
|
path: "verible-verilog-syntax".to_string(),
|
||||||
args: Vec::new(),
|
args: Vec::new(),
|
||||||
}
|
}
|
||||||
@ -45,16 +48,14 @@ impl Default for VeribleLinter {
|
|||||||
impl Default for VeribleFormat {
|
impl Default for VeribleFormat {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
enabled: true,
|
enabled: false,
|
||||||
path: "verible-verilog-format".to_string(),
|
path: "verible-verilog-format".to_string(),
|
||||||
args: Vec::new(),
|
args: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide_diagnostics() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// syntax checking using verible-verilog-syntax
|
/// syntax checking using verible-verilog-syntax
|
||||||
@ -112,3 +113,55 @@ fn verible_syntax(
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl AbstractLinterConfiguration for VeribleConfiguration {
|
||||||
|
fn new(language_id: &str) -> Self {
|
||||||
|
VeribleConfiguration {
|
||||||
|
language_id: language_id.to_string(),
|
||||||
|
linter: VeribleLinter::default(),
|
||||||
|
format: VeribleFormat::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn provide_diagnostics(&self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_linter_path(&self) -> &str {
|
||||||
|
&self.linter.path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_windows_extension(&self) -> &str {
|
||||||
|
"exe"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn linter_status(&self) -> LinterStatus {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,14 +5,17 @@ use std::path::PathBuf;
|
|||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
|
use crate::utils::command::is_command_valid;
|
||||||
|
|
||||||
|
use super::{AbstractLinterConfiguration, LinterStatus};
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
|
||||||
pub struct VerilatorConfiguration {
|
pub struct VerilatorConfiguration {
|
||||||
|
pub language_id: String,
|
||||||
pub linter: VerilatorLinter,
|
pub linter: VerilatorLinter,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
|
||||||
pub struct VerilatorLinter {
|
pub struct VerilatorLinter {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// 目前是否启动
|
/// 目前是否启动
|
||||||
@ -25,7 +28,7 @@ impl Default for VerilatorLinter {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: "verilator".to_string(),
|
name: "verilator".to_string(),
|
||||||
enabled: true,
|
enabled: false,
|
||||||
path: "verilator".to_string(),
|
path: "verilator".to_string(),
|
||||||
args: vec![
|
args: vec![
|
||||||
"--lint-only".to_string(),
|
"--lint-only".to_string(),
|
||||||
@ -36,10 +39,6 @@ impl Default for VerilatorLinter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide_diagnostics() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// convert captured severity string to DiagnosticSeverity
|
/// convert captured severity string to DiagnosticSeverity
|
||||||
fn verilator_severity(severity: &str) -> Option<DiagnosticSeverity> {
|
fn verilator_severity(severity: &str) -> Option<DiagnosticSeverity> {
|
||||||
@ -123,3 +122,54 @@ fn verilator_syntax(
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl AbstractLinterConfiguration for VerilatorConfiguration {
|
||||||
|
fn new(language_id: &str) -> Self {
|
||||||
|
VerilatorConfiguration {
|
||||||
|
language_id: language_id.to_string(),
|
||||||
|
linter: VerilatorLinter::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn provide_diagnostics(&self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_linter_path(&self) -> &str {
|
||||||
|
&self.linter.path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_windows_extension(&self) -> &str {
|
||||||
|
"exe"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn linter_status(&self) -> LinterStatus {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,16 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::utils::command::is_command_valid;
|
||||||
|
|
||||||
|
use super::{AbstractLinterConfiguration, LinterStatus};
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
|
||||||
pub struct VivadoConfiguration {
|
pub struct VivadoConfiguration {
|
||||||
|
pub language_id: String,
|
||||||
pub linter: VivadoLinter,
|
pub linter: VivadoLinter,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
|
||||||
pub struct VivadoLinter {
|
pub struct VivadoLinter {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// 目前是否启动
|
/// 目前是否启动
|
||||||
@ -20,7 +23,7 @@ impl Default for VivadoLinter {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: "vivado".to_string(),
|
name: "vivado".to_string(),
|
||||||
enabled: true,
|
enabled: false,
|
||||||
path: "Vivado".to_string(),
|
path: "Vivado".to_string(),
|
||||||
args: vec![
|
args: vec![
|
||||||
"--lint-only".to_string(),
|
"--lint-only".to_string(),
|
||||||
@ -31,6 +34,61 @@ impl Default for VivadoLinter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide_diagnostics() {
|
impl AbstractLinterConfiguration for VivadoConfiguration {
|
||||||
|
fn new(language_id: &str) -> Self {
|
||||||
|
VivadoConfiguration {
|
||||||
|
language_id: language_id.to_string(),
|
||||||
|
linter: VivadoLinter::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn provide_diagnostics(&self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_linter_path(&self) -> &str {
|
||||||
|
&self.linter.path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_windows_extension(&self) -> &str {
|
||||||
|
"exe"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn linter_status(&self) -> LinterStatus {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -6,7 +6,8 @@ use request::{
|
|||||||
fast::DoFastApi,
|
fast::DoFastApi,
|
||||||
fast::SyncFastApi,
|
fast::SyncFastApi,
|
||||||
config::UpdateConfigurationApi,
|
config::UpdateConfigurationApi,
|
||||||
primitives::DoPrimitivesJudgeApi
|
primitives::DoPrimitivesJudgeApi,
|
||||||
|
linter::LinterStatusApi
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
@ -57,6 +58,7 @@ async fn main() {
|
|||||||
.custom_method("api/do-primitives-judge", DoPrimitivesJudgeApi)
|
.custom_method("api/do-primitives-judge", DoPrimitivesJudgeApi)
|
||||||
.custom_method("api/update-configuration", UpdateConfigurationApi)
|
.custom_method("api/update-configuration", UpdateConfigurationApi)
|
||||||
.custom_method("api/sync-fast", SyncFastApi)
|
.custom_method("api/sync-fast", SyncFastApi)
|
||||||
|
.custom_method("api/linter-status", LinterStatusApi)
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
Server::new(stdin, stdout, socket)
|
Server::new(stdin, stdout, socket)
|
||||||
|
@ -14,7 +14,6 @@ pub struct UpdateConfigurationApi;
|
|||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct UpdateConfigurationParams {
|
pub struct UpdateConfigurationParams {
|
||||||
configs: Vec<UpdateConfigurationItem>,
|
configs: Vec<UpdateConfigurationItem>,
|
||||||
#[serde(rename = "configType")]
|
|
||||||
config_type: String
|
config_type: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
94
src/request/linter.rs
Normal file
94
src/request/linter.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use std::{borrow::Cow, sync::Arc};
|
||||||
|
use std::future;
|
||||||
|
use log::info;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tower_lsp::jsonrpc::Result;
|
||||||
|
|
||||||
|
use crate::diagnostics::{AbstractLinterConfiguration, LinterStatus};
|
||||||
|
use crate::server::Backend;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LinterStatusApi;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct LinterStatusParams {
|
||||||
|
language_id: String,
|
||||||
|
linter_name: String,
|
||||||
|
linter_path: String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl <'a>tower_lsp::jsonrpc::Method<&'a Arc<Backend>, (LinterStatusParams, ), Result<LinterStatus>> for LinterStatusApi {
|
||||||
|
type Future = future::Ready<Result<LinterStatus>>;
|
||||||
|
|
||||||
|
fn invoke(&self, _server: &'a Arc<Backend>, _params: (LinterStatusParams, )) -> Self::Future {
|
||||||
|
let request_param = _params.0;
|
||||||
|
|
||||||
|
let language_id = request_param.language_id;
|
||||||
|
let linter_name = request_param.linter_name;
|
||||||
|
let linter_path = request_param.linter_path;
|
||||||
|
let linter_status = get_linter_status(
|
||||||
|
&_server,
|
||||||
|
&language_id,
|
||||||
|
&linter_name,
|
||||||
|
&linter_path
|
||||||
|
);
|
||||||
|
future::ready(linter_status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_linter_status(
|
||||||
|
backend: &Arc<Backend>,
|
||||||
|
language_id: &str,
|
||||||
|
linter_name: &str,
|
||||||
|
#[allow(unused)]
|
||||||
|
linter_path: &str
|
||||||
|
) -> Result<LinterStatus> {
|
||||||
|
let configuration = backend.server.configuration.read().unwrap();
|
||||||
|
|
||||||
|
// 获取对应语言的配置项目
|
||||||
|
let configuration = match language_id {
|
||||||
|
"verilog" => &configuration.vlog_linter_configuration,
|
||||||
|
"systemverilog" => &configuration.svlog_linter_configuration,
|
||||||
|
"vhdl" => &configuration.vhdl_linter_configuration,
|
||||||
|
_ => {
|
||||||
|
return Err(tower_lsp::jsonrpc::Error {
|
||||||
|
code: tower_lsp::jsonrpc::ErrorCode::InvalidRequest,
|
||||||
|
message: Cow::Owned(format!("无效的语言 ID {}", language_id)),
|
||||||
|
data: None
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 再根据 linter name 进行分类讨论
|
||||||
|
match linter_name {
|
||||||
|
"iverilog" => {
|
||||||
|
Ok(configuration.iverilog.linter_status())
|
||||||
|
}
|
||||||
|
|
||||||
|
"vivado" => {
|
||||||
|
Ok(configuration.vivado.linter_status())
|
||||||
|
}
|
||||||
|
|
||||||
|
"modelsim" => {
|
||||||
|
Ok(configuration.modelsim.linter_status())
|
||||||
|
}
|
||||||
|
|
||||||
|
"verible" => {
|
||||||
|
Ok(configuration.verible.linter_status())
|
||||||
|
}
|
||||||
|
|
||||||
|
"verilator" => {
|
||||||
|
Ok(configuration.verilator.linter_status())
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
return Err(tower_lsp::jsonrpc::Error {
|
||||||
|
code: tower_lsp::jsonrpc::ErrorCode::InvalidRequest,
|
||||||
|
message: Cow::Owned(format!("无效的语言 ID {}", language_id)),
|
||||||
|
data: None
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,3 +3,4 @@ pub mod config;
|
|||||||
pub mod primitives;
|
pub mod primitives;
|
||||||
pub mod fast;
|
pub mod fast;
|
||||||
pub mod test;
|
pub mod test;
|
||||||
|
pub mod linter;
|
@ -118,9 +118,9 @@ impl Default for LspConfiguration {
|
|||||||
include_dirs: Vec::new(),
|
include_dirs: Vec::new(),
|
||||||
source_dirs: Vec::new(),
|
source_dirs: Vec::new(),
|
||||||
linter_mode: DigitalLinterMode::FULL,
|
linter_mode: DigitalLinterMode::FULL,
|
||||||
vlog_linter_configuration: DigitalLinterConfiguration::default(),
|
vlog_linter_configuration: DigitalLinterConfiguration::new("verilog"),
|
||||||
vhdl_linter_configuration: DigitalLinterConfiguration::default(),
|
vhdl_linter_configuration: DigitalLinterConfiguration::new("vhdl"),
|
||||||
svlog_linter_configuration: DigitalLinterConfiguration::default(),
|
svlog_linter_configuration: DigitalLinterConfiguration::new("systemverilog"),
|
||||||
log_level: LogLevel::Info,
|
log_level: LogLevel::Info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -667,14 +667,12 @@ pub fn sv_parser_pipeline(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("debug, parse: {:?}", path);
|
|
||||||
let syntax_tree = recovery_sv_parse_with_retry(
|
let syntax_tree = recovery_sv_parse_with_retry(
|
||||||
doc,
|
doc,
|
||||||
uri,
|
uri,
|
||||||
last_change_range,
|
last_change_range,
|
||||||
include_dirs
|
include_dirs
|
||||||
);
|
);
|
||||||
info!("finish parse {:?}", path);
|
|
||||||
|
|
||||||
// 更新 scope tree
|
// 更新 scope tree
|
||||||
let mut scope_tree = match &syntax_tree {
|
let mut scope_tree = match &syntax_tree {
|
||||||
|
9
src/utils/command.rs
Normal file
9
src/utils/command.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
pub fn is_command_valid(command: &str) -> bool {
|
||||||
|
// 尝试执行命令
|
||||||
|
match Command::new(command).output() {
|
||||||
|
Ok(output) => output.status.success(),
|
||||||
|
Err(_) => false,
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ use ropey::RopeSlice;
|
|||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
use vhdl_lang::{ast::ObjectClass, AnyEntKind, Concurrent, Object, Overloaded, SrcPos, Type};
|
use vhdl_lang::{ast::ObjectClass, AnyEntKind, Concurrent, Object, Overloaded, SrcPos, Type};
|
||||||
|
|
||||||
|
pub mod command;
|
||||||
pub mod fast;
|
pub mod fast;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
pub use file::*;
|
pub use file::*;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user