完成诊断器架构重新设计
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}",
|
||||
"}",
|
||||
]
|
||||
},
|
||||
"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 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct ModelsimFormat {
|
||||
pub enabled: bool,
|
||||
pub path: String,
|
||||
pub args: Vec<String>,
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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<DiagnosticSeverity> {
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -14,7 +14,6 @@ pub struct UpdateConfigurationApi;
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UpdateConfigurationParams {
|
||||
configs: Vec<UpdateConfigurationItem>,
|
||||
#[serde(rename = "configType")]
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -2,4 +2,5 @@ pub mod notification;
|
||||
pub mod config;
|
||||
pub mod primitives;
|
||||
pub mod fast;
|
||||
pub mod test;
|
||||
pub mod test;
|
||||
pub mod linter;
|
@ -26,7 +26,7 @@ pub struct LspServer {
|
||||
pub vhdl_keyword_completiom_items: Vec<CompletionItem>,
|
||||
/// 相关的配置项目
|
||||
pub configuration: Arc<RwLock<LspConfiguration>>,
|
||||
|
||||
|
||||
#[allow(unused)]
|
||||
pub log_handle: Mutex<Option<LoggerHandle>>,
|
||||
}
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
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 vhdl_lang::{ast::ObjectClass, AnyEntKind, Concurrent, Object, Overloaded, SrcPos, Type};
|
||||
|
||||
pub mod command;
|
||||
pub mod fast;
|
||||
pub mod file;
|
||||
pub use file::*;
|
||||
|
Loading…
x
Reference in New Issue
Block a user