完成 linter 的诊断 pipeline 架构实现
This commit is contained in:
parent
e726fffd99
commit
723ee40a4e
@ -26,11 +26,32 @@ pub struct CacheItem {
|
||||
pub cache_name: String
|
||||
}
|
||||
|
||||
impl Default for CacheItem {
|
||||
fn default() -> Self {
|
||||
CacheItem {
|
||||
file_name: "".to_string(),
|
||||
size: 0,
|
||||
version: "".to_string(),
|
||||
cache_name: "".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct CacheInfo {
|
||||
// version
|
||||
pub version: Option<String>,
|
||||
/// 解析类型文件缓存的根目录
|
||||
pub parser_cache: Option<PathBuf>,
|
||||
/// 第三方 linter 文件缓存的根目录
|
||||
pub linter_cache: Option<PathBuf>,
|
||||
}
|
||||
|
||||
/// 用于进行高效 IR 缓存的模块
|
||||
pub struct CacheManager {
|
||||
/// 缓存文件夹根目录
|
||||
pub root_dir: PathBuf,
|
||||
pub cache_info: Arc<RwLock<CacheInfo>>,
|
||||
/// meta 文件内容
|
||||
pub meta_name: String,
|
||||
/// meta 内容
|
||||
@ -40,23 +61,52 @@ pub struct CacheManager {
|
||||
|
||||
impl CacheManager {
|
||||
pub fn new(root_dir: PathBuf) -> Self {
|
||||
// 读入 meta 文件
|
||||
let meta_name = "index.cache";
|
||||
let meta_path = root_dir.join(meta_name);
|
||||
let meta = get_or_init_meta(&meta_path);
|
||||
|
||||
// 如果不存在 root dir,则创建
|
||||
if !root_dir.exists() {
|
||||
match fs::create_dir_all(&root_dir) {
|
||||
Ok(_) => {},
|
||||
Err(err) => info!("error happen when create {root_dir:?}: {err:?}")
|
||||
}
|
||||
}
|
||||
let cache_info = Arc::new(RwLock::new(CacheInfo {
|
||||
version: None,
|
||||
parser_cache: None,
|
||||
linter_cache: None,
|
||||
}));
|
||||
|
||||
CacheManager {
|
||||
root_dir,
|
||||
cache_info,
|
||||
meta_name: meta_name.to_string(),
|
||||
meta: Arc::new(RwLock::new(meta))
|
||||
meta: Arc::new(RwLock::new(HashMap::<String, CacheItem>::new()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&self, version: &str) {
|
||||
let root_dir = &self.root_dir;
|
||||
let mut cache_info = self.cache_info.write().unwrap();
|
||||
cache_info.version = Some(version.to_string());
|
||||
|
||||
let linter_cache = root_dir.join(version).join("lc");
|
||||
let parser_cache = root_dir.join(version).join("pc");
|
||||
|
||||
// 如果不存在指定的缓存文件夹,则创建
|
||||
// ~/digital-ide/{版本号}/
|
||||
// 📁 lc: linter的cache
|
||||
// 📁 pc: parser的cache
|
||||
CacheManager::check_dir(&linter_cache);
|
||||
CacheManager::check_dir(&parser_cache);
|
||||
|
||||
// 读入 meta 文件
|
||||
let meta_path = parser_cache.join(&self.meta_name);
|
||||
let meta = get_or_init_meta(&meta_path);
|
||||
let mut cache_meta = self.meta.write().unwrap();
|
||||
for (key, value) in meta.into_iter() {
|
||||
cache_meta.insert(key, value);
|
||||
}
|
||||
|
||||
info!("缓存系统初始化完成,pc: {:?}, lc: {:?}", parser_cache, linter_cache);
|
||||
cache_info.parser_cache = Some(parser_cache);
|
||||
cache_info.linter_cache = Some(linter_cache);
|
||||
}
|
||||
|
||||
fn check_dir(dir: &PathBuf) {
|
||||
if !dir.exists() {
|
||||
fs::create_dir_all(dir);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,6 +173,7 @@ impl CacheManager {
|
||||
hash_string
|
||||
}
|
||||
|
||||
/// 更新缓存,并写入磁盘
|
||||
pub fn update_cache(&self, path: &PathBuf, fast: FastHdlparam) {
|
||||
let path_string = path.to_str().unwrap();
|
||||
let version = self.get_version(path);
|
||||
@ -138,19 +189,23 @@ impl CacheManager {
|
||||
|
||||
let mut meta_handle = self.meta.write().unwrap();
|
||||
meta_handle.insert(path_string.to_string(), cache_item);
|
||||
|
||||
let cache_info = self.cache_info.read().unwrap();
|
||||
|
||||
// 准备必要的独立数据塞入线程进行调度
|
||||
let meta = (&*meta_handle).clone();
|
||||
let meta_save_path = self.root_dir.join(self.meta_name.clone());
|
||||
let cache_save_path = self.root_dir.join(cache_name);
|
||||
|
||||
std::thread::spawn(move || {
|
||||
info!("save meta to {meta_save_path:?}");
|
||||
let _ = k_serialize(&meta_save_path, meta);
|
||||
|
||||
info!("save index to {cache_save_path:?}");
|
||||
let _ = k_serialize(&cache_save_path, fast);
|
||||
});
|
||||
if let Some(parser_cache) = &cache_info.parser_cache {
|
||||
let meta = (&*meta_handle).clone();
|
||||
let meta_save_path = parser_cache.join(&self.meta_name);
|
||||
let cache_save_path = parser_cache.join(cache_name);
|
||||
|
||||
std::thread::spawn(move || {
|
||||
info!("save meta to {meta_save_path:?}");
|
||||
let _ = k_serialize(&meta_save_path, meta);
|
||||
|
||||
info!("save index to {cache_save_path:?}");
|
||||
let _ = k_serialize(&cache_save_path, fast);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
use std::{path::PathBuf, str::FromStr};
|
||||
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ropey::Rope;
|
||||
use tower_lsp::lsp_types::{Diagnostic, Url};
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@ -22,19 +25,21 @@ impl Default for LinterStatus {
|
||||
}
|
||||
|
||||
pub trait AbstractLinterConfiguration {
|
||||
fn new(language_id: &str) -> Self;
|
||||
/// - language_id: 语言 id
|
||||
/// - invoker: 调用可执行文件的名字,比如 `iverilog`,`xvlog`,`verible-verilog-syntax`
|
||||
/// - args: 调用执行器进行诊断的命令行参数(不包含文件路径)
|
||||
fn new(language_id: &str, invoker: &str, args: Vec<String>) -> Self;
|
||||
|
||||
/// 提供一次诊断
|
||||
fn provide_diagnostics(&self);
|
||||
|
||||
/// 提供一次诊断目前基于 uri 中的地址读取真实路径来获取诊断结果
|
||||
fn provide_diagnostics(&self, uri: &Url, rope: &Rope) -> Vec<Diagnostic>;
|
||||
|
||||
/// 获取工具在 Windows 下的后缀,比如 iverilog 就是 exe , xvlog 就是 bat
|
||||
fn get_windows_extension(&self) -> &str;
|
||||
|
||||
/// 获取 linter 安装路径,内部实现,内部调用
|
||||
fn get_linter_path(&self) -> &str;
|
||||
|
||||
/// 获取真实调用路径,比如
|
||||
///
|
||||
/// iverilog.exe 或者 /path/to/verilog.exe
|
||||
fn get_invoke_name(&self, execute_name: &str) -> String {
|
||||
let suffix = {
|
||||
|
@ -1,12 +1,14 @@
|
||||
use std::{path::PathBuf, str::FromStr};
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ropey::Rope;
|
||||
use tower_lsp::lsp_types::{Diagnostic, Url};
|
||||
|
||||
use crate::utils::command::is_command_valid;
|
||||
|
||||
use super::{AbstractLinterConfiguration, LinterStatus};
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct IverilogConfiguration {
|
||||
pub language_id: String,
|
||||
pub linter: IverilogLinter
|
||||
@ -15,33 +17,44 @@ pub struct IverilogConfiguration {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct IverilogLinter {
|
||||
pub name: String,
|
||||
pub exe_name: String,
|
||||
/// 目前是否启动
|
||||
pub enabled: bool,
|
||||
pub path: String,
|
||||
pub args: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for IverilogLinter {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
impl IverilogLinter {
|
||||
fn new(invoker: &str, args: Vec<String>) -> Self {
|
||||
IverilogLinter {
|
||||
name: "iverilog".to_string(),
|
||||
exe_name: invoker.to_string(),
|
||||
enabled: false,
|
||||
path: "iverilog".to_string(),
|
||||
args: Vec::new(),
|
||||
path: invoker.to_string(),
|
||||
args
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractLinterConfiguration for IverilogConfiguration {
|
||||
fn new(language_id: &str) -> Self {
|
||||
fn new(language_id: &str, invoker: &str, args: Vec<String>) -> Self {
|
||||
IverilogConfiguration {
|
||||
language_id: language_id.to_string(),
|
||||
linter: IverilogLinter::default()
|
||||
linter: IverilogLinter::new(invoker, args)
|
||||
}
|
||||
}
|
||||
|
||||
fn provide_diagnostics(&self) {
|
||||
fn provide_diagnostics(
|
||||
&self,
|
||||
uri: &Url,
|
||||
#[allow(unused)]
|
||||
rope: &Rope
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = Vec::<Diagnostic>::new();
|
||||
|
||||
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
fn get_windows_extension(&self) -> &str {
|
||||
|
@ -26,7 +26,6 @@ pub use modelsim::*;
|
||||
/// 诊断模块的每一个子诊断器都需要实现如下的函数
|
||||
/// - provide_diagnostics: 提供一次诊断
|
||||
/// -
|
||||
|
||||
/// 获取诊断核心函数
|
||||
pub fn provide_diagnostics(
|
||||
uri: Url,
|
||||
@ -58,27 +57,46 @@ pub fn provide_diagnostics(
|
||||
|
||||
// 根据配置决定使用哪一个诊断器
|
||||
// 外层代码需要保证只有一个 linter.enable 为 true
|
||||
if linter_configuration.verilator.linter.enabled {
|
||||
info!("verilator linter enter");
|
||||
|
||||
} else if linter_configuration.verible.linter.enabled {
|
||||
info!("verible linter enter");
|
||||
|
||||
} else if linter_configuration.modelsim.linter.enabled {
|
||||
info!("modelsim linter enter");
|
||||
|
||||
} else if linter_configuration.vivado.linter.enabled {
|
||||
info!("vivado linter enter");
|
||||
|
||||
match linter_configuration {
|
||||
config if config.iverilog.linter.enabled => {
|
||||
info!("iverilog linter enter");
|
||||
diagnostics.append(
|
||||
&mut config.iverilog.provide_diagnostics(&uri, rope)
|
||||
);
|
||||
}
|
||||
config if config.verilator.linter.enabled => {
|
||||
info!("verilator linter enter");
|
||||
diagnostics.append(
|
||||
&mut config.verilator.provide_diagnostics(&uri, rope)
|
||||
);
|
||||
}
|
||||
config if config.verible.linter.enabled => {
|
||||
info!("verible linter enter");
|
||||
diagnostics.append(
|
||||
&mut config.verible.provide_diagnostics(&uri, rope)
|
||||
);
|
||||
}
|
||||
config if config.modelsim.linter.enabled => {
|
||||
info!("modelsim linter enter");
|
||||
diagnostics.append(
|
||||
&mut config.modelsim.provide_diagnostics(&uri, rope)
|
||||
);
|
||||
}
|
||||
config if config.vivado.linter.enabled => {
|
||||
info!("vivado linter enter");
|
||||
diagnostics.append(
|
||||
&mut config.vivado.provide_diagnostics(&uri, rope)
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
PublishDiagnosticsParams {
|
||||
uri, diagnostics,
|
||||
version: None
|
||||
}
|
||||
}
|
||||
|
||||
/// 根据输入的名字选择诊断器
|
||||
/// 根据输入的名字选择诊断器,并更新所有诊断器的基本路径
|
||||
/// - `linter_name` 为 `"vivado" | "modelsim" | "verilator" | "verible" | "iverilog"`
|
||||
/// - `language_id` 为 `"vhdl" | "verilog" | "systemverilog"`
|
||||
/// - `linter_path` 为第三方的可执行文件的路径
|
||||
@ -114,27 +132,44 @@ pub fn update_diagnostics_configuration(
|
||||
"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);
|
||||
let invoke_name = linter_configuration.iverilog.get_invoke_name("iverilog");
|
||||
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
||||
}
|
||||
"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);
|
||||
let invoke_name = linter_configuration.verilator.get_invoke_name("verilator");
|
||||
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
||||
}
|
||||
"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);
|
||||
let invoke_name = linter_configuration.verible.get_invoke_name("verible-verilog-syntax");
|
||||
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
||||
}
|
||||
"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);
|
||||
let invoke_name = {
|
||||
if language_id == "vhdl" {
|
||||
linter_configuration.modelsim.get_invoke_name("vcom")
|
||||
} else {
|
||||
linter_configuration.modelsim.get_invoke_name("vlog")
|
||||
}
|
||||
};
|
||||
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
||||
}
|
||||
"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);
|
||||
let invoke_name = {
|
||||
if language_id == "vhdl" {
|
||||
linter_configuration.vivado.get_invoke_name("xvhdl")
|
||||
} else {
|
||||
linter_configuration.vivado.get_invoke_name("xvlog")
|
||||
}
|
||||
};
|
||||
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, invoke_name);
|
||||
}
|
||||
_ => {
|
||||
info!("未找到匹配的诊断器: {}", linter_name);
|
||||
@ -172,12 +207,128 @@ pub struct DigitalLinterConfiguration {
|
||||
|
||||
impl DigitalLinterConfiguration {
|
||||
pub fn new(language_id: &str) -> Self {
|
||||
DigitalLinterConfiguration {
|
||||
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)
|
||||
match language_id {
|
||||
"vhdl" => {
|
||||
DigitalLinterConfiguration {
|
||||
iverilog: IverilogConfiguration::new(
|
||||
language_id,
|
||||
"iverilog",
|
||||
vec![
|
||||
"-t null".to_string()
|
||||
]
|
||||
),
|
||||
verible: VeribleConfiguration::new(
|
||||
language_id,
|
||||
"verible-verilog-syntax",
|
||||
vec![]
|
||||
),
|
||||
verilator: VerilatorConfiguration::new(
|
||||
language_id,
|
||||
"verilator",
|
||||
vec![]
|
||||
),
|
||||
modelsim: ModelsimConfiguration::new(
|
||||
language_id,
|
||||
"vcom",
|
||||
vec![
|
||||
"-quiet".to_string(),
|
||||
"-nologo".to_string(),
|
||||
"-2008".to_string()
|
||||
]
|
||||
),
|
||||
vivado: VivadoConfiguration::new(
|
||||
language_id,
|
||||
"xvhdl",
|
||||
vec![
|
||||
"--nolog".to_string()
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
"systemverilog" => {
|
||||
DigitalLinterConfiguration {
|
||||
iverilog: IverilogConfiguration::new(
|
||||
language_id,
|
||||
"iverilog",
|
||||
vec![
|
||||
"-g2012".to_string()
|
||||
]
|
||||
),
|
||||
verible: VeribleConfiguration::new(
|
||||
language_id,
|
||||
"verible-verilog-syntax",
|
||||
vec![]
|
||||
),
|
||||
verilator: VerilatorConfiguration::new(
|
||||
language_id,
|
||||
"verilator",
|
||||
vec![
|
||||
"--lint-only".to_string(),
|
||||
"-sv".to_string(),
|
||||
"-Wall".to_string()
|
||||
]
|
||||
),
|
||||
modelsim: ModelsimConfiguration::new(
|
||||
language_id,
|
||||
"vlog",
|
||||
vec![
|
||||
"-quiet".to_string(),
|
||||
"-nologo".to_string(),
|
||||
"-sv".to_string()
|
||||
]
|
||||
),
|
||||
vivado: VivadoConfiguration::new(
|
||||
language_id,
|
||||
"xvlog",
|
||||
vec![
|
||||
"--sv".to_string(),
|
||||
"--nolog".to_string()
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 默认为 verilog
|
||||
_ => {
|
||||
DigitalLinterConfiguration {
|
||||
iverilog: IverilogConfiguration::new(
|
||||
language_id,
|
||||
"iverilog",
|
||||
vec![
|
||||
"-t null".to_string()
|
||||
]
|
||||
),
|
||||
verible: VeribleConfiguration::new(
|
||||
language_id,
|
||||
"verible-verilog-syntax",
|
||||
vec![]
|
||||
),
|
||||
verilator: VerilatorConfiguration::new(
|
||||
language_id,
|
||||
"verilator",
|
||||
vec![
|
||||
"--lint-only".to_string(),
|
||||
"-Wall".to_string()
|
||||
]
|
||||
),
|
||||
modelsim: ModelsimConfiguration::new(
|
||||
language_id,
|
||||
"vlog",
|
||||
vec![
|
||||
"-quiet".to_string(),
|
||||
"-nologo".to_string()
|
||||
]
|
||||
),
|
||||
vivado: VivadoConfiguration::new(
|
||||
language_id,
|
||||
"xvlog",
|
||||
vec![
|
||||
"--nolog".to_string()
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
use std::{path::PathBuf, str::FromStr};
|
||||
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::utils::command::is_command_valid;
|
||||
|
||||
use super::{AbstractLinterConfiguration, LinterStatus};
|
||||
use ropey::Rope;
|
||||
use tower_lsp::lsp_types::{Diagnostic, Url};
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ModelsimConfiguration {
|
||||
pub language_id: String,
|
||||
pub linter: ModelsimLinter
|
||||
@ -16,6 +16,7 @@ pub struct ModelsimConfiguration {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ModelsimLinter {
|
||||
pub name: String,
|
||||
pub exe_name: String,
|
||||
/// 目前是否启动
|
||||
pub enabled: bool,
|
||||
pub path: String,
|
||||
@ -23,28 +24,36 @@ pub struct ModelsimLinter {
|
||||
}
|
||||
|
||||
|
||||
impl Default for ModelsimLinter {
|
||||
fn default() -> Self {
|
||||
impl ModelsimLinter {
|
||||
fn new(invoker: &str, args: Vec<String>) -> Self {
|
||||
Self {
|
||||
name: "modelsim".to_string(),
|
||||
exe_name: invoker.to_string(),
|
||||
enabled: false,
|
||||
path: "Modelsim-verilog-syntax".to_string(),
|
||||
args: Vec::new(),
|
||||
path: invoker.to_string(),
|
||||
args,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl AbstractLinterConfiguration for ModelsimConfiguration {
|
||||
fn new(language_id: &str) -> Self {
|
||||
fn new(language_id: &str, invoker: &str, args: Vec<String>) -> Self {
|
||||
ModelsimConfiguration {
|
||||
language_id: language_id.to_string(),
|
||||
linter: ModelsimLinter::default()
|
||||
linter: ModelsimLinter::new(invoker, args)
|
||||
}
|
||||
}
|
||||
|
||||
fn provide_diagnostics(&self) {
|
||||
fn provide_diagnostics(
|
||||
&self,
|
||||
uri: &Url,
|
||||
#[allow(unused)]
|
||||
rope: &Rope
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = Vec::<Diagnostic>::new();
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
fn get_windows_extension(&self) -> &str {
|
||||
|
@ -10,7 +10,7 @@ use super::{AbstractLinterConfiguration, LinterStatus};
|
||||
|
||||
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct VeribleConfiguration {
|
||||
pub language_id: String,
|
||||
pub linter: VeribleLinter,
|
||||
@ -20,6 +20,7 @@ pub struct VeribleConfiguration {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct VeribleLinter {
|
||||
pub name: String,
|
||||
pub exe_name: String,
|
||||
/// 目前是否启动
|
||||
pub enabled: bool,
|
||||
pub path: String,
|
||||
@ -33,13 +34,14 @@ pub struct VeribleFormat {
|
||||
pub args: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for VeribleLinter {
|
||||
fn default() -> Self {
|
||||
impl VeribleLinter {
|
||||
fn new(invoker: &str, args: Vec<String>) -> Self {
|
||||
Self {
|
||||
name: "verible".to_string(),
|
||||
exe_name: invoker.to_string(),
|
||||
enabled: false,
|
||||
path: "verible-verilog-syntax".to_string(),
|
||||
args: Vec::new(),
|
||||
path: invoker.to_string(),
|
||||
args,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,16 +118,23 @@ fn verible_syntax(
|
||||
|
||||
|
||||
impl AbstractLinterConfiguration for VeribleConfiguration {
|
||||
fn new(language_id: &str) -> Self {
|
||||
fn new(language_id: &str, invoker: &str, args: Vec<String>) -> Self {
|
||||
VeribleConfiguration {
|
||||
language_id: language_id.to_string(),
|
||||
linter: VeribleLinter::default(),
|
||||
linter: VeribleLinter::new(invoker, args),
|
||||
format: VeribleFormat::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn provide_diagnostics(&self) {
|
||||
fn provide_diagnostics(
|
||||
&self,
|
||||
uri: &Url,
|
||||
#[allow(unused)]
|
||||
rope: &Rope
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = Vec::<Diagnostic>::new();
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
fn get_linter_path(&self) -> &str {
|
||||
|
@ -9,7 +9,7 @@ use crate::utils::command::is_command_valid;
|
||||
|
||||
use super::{AbstractLinterConfiguration, LinterStatus};
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct VerilatorConfiguration {
|
||||
pub language_id: String,
|
||||
pub linter: VerilatorLinter,
|
||||
@ -18,23 +18,21 @@ pub struct VerilatorConfiguration {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct VerilatorLinter {
|
||||
pub name: String,
|
||||
pub exe_name: String,
|
||||
/// 目前是否启动
|
||||
pub enabled: bool,
|
||||
pub path: String,
|
||||
pub args: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for VerilatorLinter {
|
||||
fn default() -> Self {
|
||||
impl VerilatorLinter {
|
||||
fn new(invoker: &str, args: Vec<String>) -> Self {
|
||||
Self {
|
||||
name: "verilator".to_string(),
|
||||
exe_name: invoker.to_string(),
|
||||
enabled: false,
|
||||
path: "verilator".to_string(),
|
||||
args: vec![
|
||||
"--lint-only".to_string(),
|
||||
"--sv".to_string(),
|
||||
"-Wall".to_string(),
|
||||
],
|
||||
path: invoker.to_string(),
|
||||
args,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -125,15 +123,22 @@ fn verilator_syntax(
|
||||
|
||||
|
||||
impl AbstractLinterConfiguration for VerilatorConfiguration {
|
||||
fn new(language_id: &str) -> Self {
|
||||
fn new(language_id: &str, invoker: &str, args: Vec<String>) -> Self {
|
||||
VerilatorConfiguration {
|
||||
language_id: language_id.to_string(),
|
||||
linter: VerilatorLinter::default()
|
||||
linter: VerilatorLinter::new(invoker, args)
|
||||
}
|
||||
}
|
||||
|
||||
fn provide_diagnostics(&self) {
|
||||
fn provide_diagnostics(
|
||||
&self,
|
||||
uri: &Url,
|
||||
#[allow(unused)]
|
||||
rope: &Rope
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = Vec::<Diagnostic>::new();
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
fn get_linter_path(&self) -> &str {
|
||||
|
@ -1,10 +1,13 @@
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::utils::command::is_command_valid;
|
||||
use ropey::Rope;
|
||||
use tower_lsp::lsp_types::{Diagnostic, Url};
|
||||
|
||||
use super::{AbstractLinterConfiguration, LinterStatus};
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct VivadoConfiguration {
|
||||
pub language_id: String,
|
||||
pub linter: VivadoLinter,
|
||||
@ -13,37 +16,42 @@ pub struct VivadoConfiguration {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct VivadoLinter {
|
||||
pub name: String,
|
||||
pub exe_name: String,
|
||||
/// 目前是否启动
|
||||
pub enabled: bool,
|
||||
pub path: String,
|
||||
pub args: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for VivadoLinter {
|
||||
fn default() -> Self {
|
||||
impl VivadoLinter {
|
||||
fn new(invoker: &str, args: Vec<String>) -> Self {
|
||||
Self {
|
||||
name: "vivado".to_string(),
|
||||
exe_name: invoker.to_string(),
|
||||
enabled: false,
|
||||
path: "Vivado".to_string(),
|
||||
args: vec![
|
||||
"--lint-only".to_string(),
|
||||
"--sv".to_string(),
|
||||
"-Wall".to_string(),
|
||||
],
|
||||
path: invoker.to_string(),
|
||||
args,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractLinterConfiguration for VivadoConfiguration {
|
||||
fn new(language_id: &str) -> Self {
|
||||
fn new(language_id: &str, invoker: &str, args: Vec<String>) -> Self {
|
||||
VivadoConfiguration {
|
||||
language_id: language_id.to_string(),
|
||||
linter: VivadoLinter::default()
|
||||
linter: VivadoLinter::new(invoker, args)
|
||||
}
|
||||
}
|
||||
|
||||
fn provide_diagnostics(&self) {
|
||||
fn provide_diagnostics(
|
||||
&self,
|
||||
uri: &Url,
|
||||
#[allow(unused)]
|
||||
rope: &Rope
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = Vec::<Diagnostic>::new();
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
fn get_linter_path(&self) -> &str {
|
||||
|
@ -69,9 +69,10 @@ fn update_configuration(
|
||||
let linter_name_configuration = &configs[0];
|
||||
let linter_path_configuration = &configs[1];
|
||||
|
||||
// something like digital-ide.function.lsp.linter.vlog.diagnostor
|
||||
// linter_name_config_name 形如 digital-ide.function.lsp.linter.vlog.diagnostor
|
||||
let linter_name_config_name = &linter_name_configuration.name;
|
||||
|
||||
// 同步到全局配置中
|
||||
lsp_configuration.insert(
|
||||
linter_name_config_name.to_string(),
|
||||
linter_name_configuration.value.clone()
|
||||
@ -82,12 +83,7 @@ fn update_configuration(
|
||||
// linter_name_config_name 形如 digital-ide.function.lsp.linter.vlog.diagnostor
|
||||
let mut cookies = linter_name_config_name.split(".");
|
||||
let name = cookies.nth(4).unwrap();
|
||||
match name {
|
||||
"vlog" => "verilog",
|
||||
"vhdl" => "vhdl",
|
||||
"svlog" => "systemverilog",
|
||||
_ => return
|
||||
}
|
||||
name
|
||||
};
|
||||
|
||||
let linter_name = linter_name_configuration.value.as_str().unwrap();
|
||||
|
@ -46,7 +46,6 @@ fn get_linter_status(
|
||||
linter_path: &str
|
||||
) -> Result<LinterStatus> {
|
||||
let configuration = backend.server.configuration.read().unwrap();
|
||||
|
||||
// 获取对应语言的配置项目
|
||||
let configuration = match language_id {
|
||||
"verilog" => &configuration.vlog_linter_configuration,
|
||||
@ -86,7 +85,7 @@ fn get_linter_status(
|
||||
_ => {
|
||||
return Err(tower_lsp::jsonrpc::Error {
|
||||
code: tower_lsp::jsonrpc::ErrorCode::InvalidRequest,
|
||||
message: Cow::Owned(format!("无效的语言 ID {}", language_id)),
|
||||
message: Cow::Owned(format!("无效的诊断器 {}", linter_name)),
|
||||
data: None
|
||||
});
|
||||
}
|
||||
|
@ -131,11 +131,7 @@ impl Default for LspConfiguration {
|
||||
impl LanguageServer for Backend {
|
||||
async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
|
||||
// 申明 LSP 的基本信息和提供的能力
|
||||
let server_info = Some(ServerInfo {
|
||||
name: "Digital IDE 专用 LSP 后端服务器".to_string(),
|
||||
version: Some("0.4.0".to_string())
|
||||
});
|
||||
|
||||
let mut version = "0.4.0".to_string();
|
||||
let root_uri = ¶ms.root_uri;
|
||||
|
||||
let mut configure = self.server.configuration.write().unwrap();
|
||||
@ -144,10 +140,16 @@ impl LanguageServer for Backend {
|
||||
if let Some(serde_json::Value::Object(options)) = params.initialization_options {
|
||||
let extension_path = options.get("extensionPath").unwrap().as_str().unwrap();
|
||||
let tool_chain = options.get("toolChain").unwrap().as_str().unwrap();
|
||||
version = options.get("version").unwrap().as_str().unwrap().to_string();
|
||||
configure.tool_chain = tool_chain.to_string();
|
||||
configure.extension_path = extension_path.to_string();
|
||||
}
|
||||
|
||||
let server_info = Some(ServerInfo {
|
||||
name: "Digital IDE 专用 LSP 后端服务器".to_string(),
|
||||
version: Some(version.to_string())
|
||||
});
|
||||
|
||||
info!("当前客户端初始化结果");
|
||||
info!("workspaceFolder: {:?}", configure.workspace_folder);
|
||||
info!("extensionPath: {:?}", configure.extension_path);
|
||||
@ -159,8 +161,8 @@ impl LanguageServer for Backend {
|
||||
&configure.extension_path
|
||||
);
|
||||
|
||||
// 初始化诊断器
|
||||
|
||||
// 初始化系统缓存路径
|
||||
self.server.cache.start(&version);
|
||||
|
||||
let text_document_sync = TextDocumentSyncCapability::Options(
|
||||
TextDocumentSyncOptions {
|
||||
|
@ -31,7 +31,6 @@ use sv_parser::*;
|
||||
use vhdl_lang::Project;
|
||||
use thread::JoinHandle;
|
||||
use tower_lsp::lsp_types::*;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
impl LspServer {
|
||||
pub fn did_open(&self, params: DidOpenTextDocumentParams) -> PublishDiagnosticsParams {
|
||||
@ -100,6 +99,8 @@ impl LspServer {
|
||||
}
|
||||
}
|
||||
|
||||
/// 保存时触发的行为
|
||||
/// - 提供诊断信息(主要是第三方诊断器,因为 save 后磁盘上的内容就和缓冲区中的一致了)
|
||||
pub fn did_save(&self, params: DidSaveTextDocumentParams) -> PublishDiagnosticsParams {
|
||||
let urls = self.srcs.names.read().unwrap().keys().cloned().collect();
|
||||
let file_id = self.srcs.get_id(¶ms.text_document.uri);
|
||||
|
@ -3,7 +3,7 @@ use std::process::Command;
|
||||
pub fn is_command_valid(command: &str) -> bool {
|
||||
// 尝试执行命令
|
||||
match Command::new(command).output() {
|
||||
Ok(output) => output.status.success(),
|
||||
Ok(_) => true,
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit b6ae8b8a1ff22609e2a837b12dd798226f299f71
|
||||
Subproject commit ba95abd436b0a032e0cfdcb9400ce2cfb678792f
|
Loading…
x
Reference in New Issue
Block a user