From e726fffd99f72bd77a6d4024abbad85ce05ece73 Mon Sep 17 00:00:00 2001 From: LSTM-Kirigaya <1193466151@qq.com> Date: Fri, 6 Dec 2024 23:24:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=AF=8A=E6=96=AD=E5=99=A8?= =?UTF-8?q?=E6=9E=B6=E6=9E=84=E9=87=8D=E6=96=B0=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/lsp.code-snippets | 9 ++++ src/diagnostics/common.rs | 66 +++++++++++++++++++++++++ src/diagnostics/iverilog.rs | 74 ++++++++++++++++++++++++++++ src/diagnostics/mod.rs | 80 ++++++++++++++++++------------ src/diagnostics/modelsim.rs | 82 +++++++++++++++++++++++-------- src/diagnostics/verible.rs | 67 ++++++++++++++++++++++--- src/diagnostics/verilator.rs | 64 +++++++++++++++++++++--- src/diagnostics/vivado.rs | 66 +++++++++++++++++++++++-- src/main.rs | 4 +- src/request/config.rs | 1 - src/request/linter.rs | 94 ++++++++++++++++++++++++++++++++++++ src/request/mod.rs | 3 +- src/server.rs | 8 +-- src/sources.rs | 2 - src/utils/command.rs | 9 ++++ src/utils/mod.rs | 1 + 16 files changed, 553 insertions(+), 77 deletions(-) create mode 100644 src/diagnostics/common.rs create mode 100644 src/diagnostics/iverilog.rs create mode 100644 src/request/linter.rs create mode 100644 src/utils/command.rs diff --git a/.vscode/lsp.code-snippets b/.vscode/lsp.code-snippets index 865456b..1d545db 100644 --- a/.vscode/lsp.code-snippets +++ b/.vscode/lsp.code-snippets @@ -35,5 +35,14 @@ "\t}", "}", ] + }, + "new": { + "scope": "rust", + "prefix": "new", + "body": [ + "pub fn new($1) -> Self {", + "\t$2", + "}" + ] } } \ No newline at end of file diff --git a/src/diagnostics/common.rs b/src/diagnostics/common.rs new file mode 100644 index 0000000..0a5a40e --- /dev/null +++ b/src/diagnostics/common.rs @@ -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; +} \ No newline at end of file diff --git a/src/diagnostics/iverilog.rs b/src/diagnostics/iverilog.rs new file mode 100644 index 0000000..e3db3ed --- /dev/null +++ b/src/diagnostics/iverilog.rs @@ -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, +} + +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() + } + } + } +} diff --git a/src/diagnostics/mod.rs b/src/diagnostics/mod.rs index 811adb0..d1a4b5a 100644 --- a/src/diagnostics/mod.rs +++ b/src/diagnostics/mod.rs @@ -1,16 +1,19 @@ -use std::fs::OpenOptions; - use crate::{server::{LspConfiguration, LspServer}, utils::get_language_id_by_uri}; use log::info; use ropey::Rope; use serde::Deserialize; use tower_lsp::lsp_types::*; +pub mod common; + +pub mod iverilog; pub mod verible; pub mod verilator; pub mod vivado; pub mod modelsim; +pub use common::*; +pub use iverilog::*; pub use verible::*; pub use verilator::*; pub use vivado::*; @@ -19,6 +22,10 @@ pub use modelsim::*; /// description /// 诊断功能需要提供两套函数,一套函数用于从给定路径读取文件并给出诊断结果;一套用于从 lsp 的文件缓冲区直接读取文本然后给出诊断结果。 /// 前者用于扫描整个项目使用,后者在用户实时修改代码时,给出实时的诊断信息。 +/// +/// 诊断模块的每一个子诊断器都需要实现如下的函数 +/// - provide_diagnostics: 提供一次诊断 +/// - /// 获取诊断核心函数 pub fn provide_diagnostics( @@ -55,7 +62,7 @@ pub fn provide_diagnostics( info!("verilator linter enter"); } else if linter_configuration.verible.linter.enabled { - info!("verilator linter enter"); + info!("verible linter enter"); } else if linter_configuration.modelsim.linter.enabled { info!("modelsim linter enter"); @@ -103,27 +110,37 @@ pub fn update_diagnostics_configuration( linter_configuration.modelsim.linter.enabled = false; linter_configuration.vivado.linter.enabled = false; - if linter_configuration.verilator.linter.name == linter_name { - linter_configuration.verilator.linter.enabled = true; - linter_configuration.verilator.linter.path = linter_path.to_string(); - info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.verilator.linter.path); - - } else if linter_configuration.verible.linter.name == linter_name { - linter_configuration.verible.linter.enabled = true; - linter_configuration.verible.linter.path = linter_path.to_string(); - info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.verible.linter.path); - - } else if linter_configuration.modelsim.linter.name == linter_name { - linter_configuration.modelsim.linter.enabled = true; - linter_configuration.modelsim.linter.path = linter_path.to_string(); - info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.modelsim.linter.path); - - } else if linter_configuration.vivado.linter.name == linter_name { - linter_configuration.vivado.linter.enabled = true; - linter_configuration.vivado.linter.path = linter_path.to_string(); - info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.vivado.linter.path); - + 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.path = linter_path.to_string(); + info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.verilator.linter.path); + } + "verible" => { + linter_configuration.verible.linter.enabled = true; + linter_configuration.verible.linter.path = linter_path.to_string(); + info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.verible.linter.path); + } + "modelsim" => { + linter_configuration.modelsim.linter.enabled = true; + linter_configuration.modelsim.linter.path = linter_path.to_string(); + info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.modelsim.linter.path); + } + "vivado" => { + linter_configuration.vivado.linter.enabled = true; + linter_configuration.vivado.linter.path = linter_path.to_string(); + info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.vivado.linter.path); + } + _ => { + info!("未找到匹配的诊断器: {}", linter_name); + } } + } @@ -141,6 +158,8 @@ pub enum DigitalLinterMode { #[derive(Debug, Deserialize)] #[derive(serde::Serialize)] pub struct DigitalLinterConfiguration { + // iverilog 相关的工具配置 + pub iverilog: IverilogConfiguration, // verible 相关的工具配置 pub verible: VeribleConfiguration, // verilator 相关的工具配置 @@ -151,13 +170,14 @@ pub struct DigitalLinterConfiguration { pub vivado: VivadoConfiguration } -impl Default for DigitalLinterConfiguration { - fn default() -> Self { +impl DigitalLinterConfiguration { + pub fn new(language_id: &str) -> Self { DigitalLinterConfiguration { - verible: VeribleConfiguration::default(), - verilator: VerilatorConfiguration::default(), - modelsim: ModelsimConfiguration::default(), - vivado: VivadoConfiguration::default() + iverilog: IverilogConfiguration::new(language_id), + verible: VeribleConfiguration::new(language_id), + verilator: VerilatorConfiguration::new(language_id), + modelsim: ModelsimConfiguration::new(language_id), + vivado: VivadoConfiguration::new(language_id) } } -} \ No newline at end of file +} diff --git a/src/diagnostics/modelsim.rs b/src/diagnostics/modelsim.rs index ec8e4af..ebb85ec 100644 --- a/src/diagnostics/modelsim.rs +++ b/src/diagnostics/modelsim.rs @@ -1,15 +1,19 @@ +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)] -#[serde(default)] pub struct ModelsimConfiguration { - pub linter: ModelsimLinter, - pub format: ModelsimFormat, + pub language_id: String, + pub linter: ModelsimLinter } #[derive(Debug, Serialize, Deserialize)] -#[serde(default)] pub struct ModelsimLinter { pub name: String, /// 目前是否启动 @@ -18,19 +22,12 @@ pub struct ModelsimLinter { pub args: Vec, } -#[derive(Debug, Serialize, Deserialize)] -#[serde(default)] -pub struct ModelsimFormat { - pub enabled: bool, - pub path: String, - pub args: Vec, -} impl Default for ModelsimLinter { fn default() -> Self { Self { name: "modelsim".to_string(), - enabled: true, + enabled: false, path: "Modelsim-verilog-syntax".to_string(), args: Vec::new(), } @@ -38,16 +35,61 @@ impl Default for ModelsimLinter { } -impl Default for ModelsimFormat { - fn default() -> Self { - Self { - enabled: true, - path: "Modelsim-verilog-format".to_string(), - args: Vec::new(), +impl AbstractLinterConfiguration for ModelsimConfiguration { + fn new(language_id: &str) -> Self { + ModelsimConfiguration { + language_id: language_id.to_string(), + linter: ModelsimLinter::default() } } -} + + fn provide_diagnostics(&self) { -pub fn provide_diagnostics() { + } + 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() + } + } + } } \ No newline at end of file diff --git a/src/diagnostics/verible.rs b/src/diagnostics/verible.rs index f9477c9..88c0b27 100644 --- a/src/diagnostics/verible.rs +++ b/src/diagnostics/verible.rs @@ -4,16 +4,20 @@ use ropey::Rope; use std::process::{Command, Stdio}; use tower_lsp::lsp_types::*; +use crate::utils::command::is_command_valid; + +use super::{AbstractLinterConfiguration, LinterStatus}; + + #[derive(Default, Debug, Serialize, Deserialize)] -#[serde(default)] pub struct VeribleConfiguration { + pub language_id: String, pub linter: VeribleLinter, pub format: VeribleFormat, } #[derive(Debug, Serialize, Deserialize)] -#[serde(default)] pub struct VeribleLinter { pub name: String, /// 目前是否启动 @@ -23,7 +27,6 @@ pub struct VeribleLinter { } #[derive(Debug, Serialize, Deserialize)] -#[serde(default)] pub struct VeribleFormat { pub enabled: bool, pub path: String, @@ -34,7 +37,7 @@ impl Default for VeribleLinter { fn default() -> Self { Self { name: "verible".to_string(), - enabled: true, + enabled: false, path: "verible-verilog-syntax".to_string(), args: Vec::new(), } @@ -45,16 +48,14 @@ impl Default for VeribleLinter { impl Default for VeribleFormat { fn default() -> Self { Self { - enabled: true, + enabled: false, path: "verible-verilog-format".to_string(), args: Vec::new(), } } } -pub fn provide_diagnostics() { -} /// syntax checking using verible-verilog-syntax @@ -112,3 +113,55 @@ fn verible_syntax( 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() + } + } + } +} \ No newline at end of file diff --git a/src/diagnostics/verilator.rs b/src/diagnostics/verilator.rs index 5322250..f5b68be 100644 --- a/src/diagnostics/verilator.rs +++ b/src/diagnostics/verilator.rs @@ -5,14 +5,17 @@ use std::path::PathBuf; use std::process::{Command, Stdio}; use tower_lsp::lsp_types::*; +use crate::utils::command::is_command_valid; + +use super::{AbstractLinterConfiguration, LinterStatus}; + #[derive(Debug, Default, Serialize, Deserialize)] -#[serde(default)] pub struct VerilatorConfiguration { + pub language_id: String, pub linter: VerilatorLinter, } #[derive(Debug, Serialize, Deserialize)] -#[serde(default)] pub struct VerilatorLinter { pub name: String, /// 目前是否启动 @@ -25,7 +28,7 @@ impl Default for VerilatorLinter { fn default() -> Self { Self { name: "verilator".to_string(), - enabled: true, + enabled: false, path: "verilator".to_string(), args: vec![ "--lint-only".to_string(), @@ -36,10 +39,6 @@ impl Default for VerilatorLinter { } } -pub fn provide_diagnostics() { - -} - /// convert captured severity string to DiagnosticSeverity fn verilator_severity(severity: &str) -> Option { @@ -123,3 +122,54 @@ fn verilator_syntax( 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() + } + } + } +} \ No newline at end of file diff --git a/src/diagnostics/vivado.rs b/src/diagnostics/vivado.rs index ee7f528..9171d6f 100644 --- a/src/diagnostics/vivado.rs +++ b/src/diagnostics/vivado.rs @@ -1,13 +1,16 @@ use serde::{Deserialize, Serialize}; +use crate::utils::command::is_command_valid; + +use super::{AbstractLinterConfiguration, LinterStatus}; + #[derive(Debug, Default, Serialize, Deserialize)] -#[serde(default)] pub struct VivadoConfiguration { + pub language_id: String, pub linter: VivadoLinter, } #[derive(Debug, Serialize, Deserialize)] -#[serde(default)] pub struct VivadoLinter { pub name: String, /// 目前是否启动 @@ -20,7 +23,7 @@ impl Default for VivadoLinter { fn default() -> Self { Self { name: "vivado".to_string(), - enabled: true, + enabled: false, path: "Vivado".to_string(), args: vec![ "--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() + } + } + } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e425645..6de28de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,8 @@ use request::{ fast::DoFastApi, fast::SyncFastApi, config::UpdateConfigurationApi, - primitives::DoPrimitivesJudgeApi + primitives::DoPrimitivesJudgeApi, + linter::LinterStatusApi }; use log::info; @@ -57,6 +58,7 @@ async fn main() { .custom_method("api/do-primitives-judge", DoPrimitivesJudgeApi) .custom_method("api/update-configuration", UpdateConfigurationApi) .custom_method("api/sync-fast", SyncFastApi) + .custom_method("api/linter-status", LinterStatusApi) .finish(); Server::new(stdin, stdout, socket) diff --git a/src/request/config.rs b/src/request/config.rs index f6eb28f..22d28f8 100644 --- a/src/request/config.rs +++ b/src/request/config.rs @@ -14,7 +14,6 @@ pub struct UpdateConfigurationApi; #[serde(rename_all = "camelCase")] pub struct UpdateConfigurationParams { configs: Vec, - #[serde(rename = "configType")] config_type: String } diff --git a/src/request/linter.rs b/src/request/linter.rs new file mode 100644 index 0000000..ad05270 --- /dev/null +++ b/src/request/linter.rs @@ -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, (LinterStatusParams, ), Result> for LinterStatusApi { + type Future = future::Ready>; + + fn invoke(&self, _server: &'a Arc, _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, + language_id: &str, + linter_name: &str, + #[allow(unused)] + linter_path: &str +) -> Result { + 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 + }); + } + } +} \ No newline at end of file diff --git a/src/request/mod.rs b/src/request/mod.rs index d42d4ce..863f180 100644 --- a/src/request/mod.rs +++ b/src/request/mod.rs @@ -2,4 +2,5 @@ pub mod notification; pub mod config; pub mod primitives; pub mod fast; -pub mod test; \ No newline at end of file +pub mod test; +pub mod linter; \ No newline at end of file diff --git a/src/server.rs b/src/server.rs index 423c929..e42e5b6 100644 --- a/src/server.rs +++ b/src/server.rs @@ -26,7 +26,7 @@ pub struct LspServer { pub vhdl_keyword_completiom_items: Vec, /// 相关的配置项目 pub configuration: Arc>, - + #[allow(unused)] pub log_handle: Mutex>, } @@ -118,9 +118,9 @@ impl Default for LspConfiguration { include_dirs: Vec::new(), source_dirs: Vec::new(), linter_mode: DigitalLinterMode::FULL, - vlog_linter_configuration: DigitalLinterConfiguration::default(), - vhdl_linter_configuration: DigitalLinterConfiguration::default(), - svlog_linter_configuration: DigitalLinterConfiguration::default(), + vlog_linter_configuration: DigitalLinterConfiguration::new("verilog"), + vhdl_linter_configuration: DigitalLinterConfiguration::new("vhdl"), + svlog_linter_configuration: DigitalLinterConfiguration::new("systemverilog"), log_level: LogLevel::Info, } } diff --git a/src/sources.rs b/src/sources.rs index 1f95a15..93ddcd5 100644 --- a/src/sources.rs +++ b/src/sources.rs @@ -667,14 +667,12 @@ pub fn sv_parser_pipeline( return; } - info!("debug, parse: {:?}", path); let syntax_tree = recovery_sv_parse_with_retry( doc, uri, last_change_range, include_dirs ); - info!("finish parse {:?}", path); // 更新 scope tree let mut scope_tree = match &syntax_tree { diff --git a/src/utils/command.rs b/src/utils/command.rs new file mode 100644 index 0000000..11c8887 --- /dev/null +++ b/src/utils/command.rs @@ -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, + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index dd394e0..081efae 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -6,6 +6,7 @@ use ropey::RopeSlice; use tower_lsp::lsp_types::*; use vhdl_lang::{ast::ObjectClass, AnyEntKind, Concurrent, Object, Overloaded, SrcPos, Type}; +pub mod command; pub mod fast; pub mod file; pub use file::*;