完成 linter 后端请求接口和基本数据结构
This commit is contained in:
parent
8e2b373702
commit
7824b74c9a
@ -1,4 +1,4 @@
|
||||
use crate::server::LSPServer;
|
||||
use crate::server::LspServer;
|
||||
use crate::utils::*;
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
@ -7,7 +7,7 @@ use tower_lsp::lsp_types::*;
|
||||
mod sv;
|
||||
mod vhdl;
|
||||
|
||||
impl LSPServer {
|
||||
impl LspServer {
|
||||
pub fn code_lens(&self, params: CodeLensParams) -> Option<Vec<CodeLens>> {
|
||||
let language_id = get_language_id_by_uri(¶ms.text_document.uri);
|
||||
match language_id.as_str() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::{path::PathBuf, str::FromStr};
|
||||
|
||||
use crate::{core, server::LSPServer};
|
||||
use crate::{core, server::LspServer};
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
use tower_lsp::lsp_types::*;
|
||||
@ -9,7 +9,7 @@ use super::to_escape_path;
|
||||
|
||||
pub fn code_lens(
|
||||
#[allow(unused)]
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
#[allow(unused)]
|
||||
params: &CodeLensParams
|
||||
) -> Option<Vec<CodeLens>> {
|
||||
|
@ -1,12 +1,12 @@
|
||||
|
||||
use crate::server::LSPServer;
|
||||
use crate::server::LspServer;
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
pub fn code_lens(
|
||||
#[allow(unused)]
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
#[allow(unused)]
|
||||
params: &CodeLensParams
|
||||
) -> Option<Vec<CodeLens>> {
|
||||
|
@ -4,7 +4,7 @@ use log::info;
|
||||
use ropey::RopeSlice;
|
||||
use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind, CompletionItemLabelDetails, CompletionList, Position, Url};
|
||||
|
||||
use crate::{server::LSPServer, utils::{resolve_path, to_escape_path}};
|
||||
use crate::{server::LspServer, utils::{resolve_path, to_escape_path}};
|
||||
|
||||
pub fn include_path_completion(uri: &Url, line: &RopeSlice, pos: Position) -> Option<CompletionList> {
|
||||
let line_text = line.as_str().unwrap_or("");
|
||||
@ -88,7 +88,7 @@ pub fn include_path_completion(uri: &Url, line: &RopeSlice, pos: Position) -> Op
|
||||
}
|
||||
|
||||
pub fn get_dot_completion(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
line: &RopeSlice,
|
||||
url: &Url,
|
||||
pos: &Position,
|
||||
@ -142,7 +142,7 @@ fn is_port_completion(line: &RopeSlice, pos: &Position) -> bool {
|
||||
}
|
||||
|
||||
fn get_position_port_param_completion(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
#[allow(unused)]
|
||||
line: &RopeSlice,
|
||||
url: &Url,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{server::LSPServer, utils::get_language_id_by_uri};
|
||||
use crate::{server::LspServer, utils::get_language_id_by_uri};
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
pub mod keyword;
|
||||
@ -10,7 +10,7 @@ pub use sys_tasks::provide_vlog_sys_tasks_completions;
|
||||
mod vhdl;
|
||||
mod sv;
|
||||
|
||||
impl LSPServer {
|
||||
impl LspServer {
|
||||
pub fn completion(&self, params: CompletionParams) -> Option<CompletionResponse> {
|
||||
let language_id = get_language_id_by_uri(¶ms.text_document_position.text_document.uri);
|
||||
match language_id.as_str() {
|
||||
|
@ -1,12 +1,10 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::{completion::feature::{get_dot_completion, include_path_completion}, core, hover::feature::make_module_profile_code, server::LSPServer, sources::LSPSupport, utils::get_language_id_by_uri};
|
||||
use crate::{completion::feature::{get_dot_completion, include_path_completion}, core, hover::feature::make_module_profile_code, server::LspServer, sources::LSPSupport, utils::get_language_id_by_uri};
|
||||
use log::info;
|
||||
use ropey::{Rope, RopeSlice};
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
|
||||
pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<CompletionResponse> {
|
||||
pub fn completion(server: &LspServer, params: &CompletionParams) -> Option<CompletionResponse> {
|
||||
let doc = ¶ms.text_document_position;
|
||||
let uri = ¶ms.text_document_position.text_document.uri;
|
||||
let pos = doc.position;
|
||||
@ -305,7 +303,7 @@ fn make_instantiation_code(module: &crate::core::hdlparam::Module) -> String {
|
||||
|
||||
/// 自动补全例化模块
|
||||
fn make_module_completions(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
token: &str,
|
||||
language_id: &str
|
||||
) -> Vec<CompletionItem> {
|
||||
|
@ -6,13 +6,13 @@ use ropey::{Rope, RopeSlice};
|
||||
use tower_lsp::lsp_types::*;
|
||||
use crate::{hover::feature::make_vhdl_module_profile_code, utils::{from_lsp_pos, to_escape_path}};
|
||||
#[allow(unused)]
|
||||
use crate::{server::LSPServer, sources::LSPSupport, utils::get_language_id_by_uri};
|
||||
use crate::{server::LspServer, sources::LSPSupport, utils::get_language_id_by_uri};
|
||||
|
||||
|
||||
|
||||
/// Called when the client requests a completion.
|
||||
/// This function looks in the source code to find suitable options and then returns them
|
||||
pub fn completion(server: &LSPServer, params: &CompletionParams) -> Option<CompletionResponse> {
|
||||
pub fn completion(server: &LspServer, params: &CompletionParams) -> Option<CompletionResponse> {
|
||||
let doc = ¶ms.text_document_position;
|
||||
let uri = ¶ms.text_document_position.text_document.uri;
|
||||
let language_id = get_language_id_by_uri(uri);
|
||||
@ -214,7 +214,7 @@ fn get_completion_token(text: &Rope, line: RopeSlice, pos: Position) -> String {
|
||||
}
|
||||
|
||||
fn make_module_completions(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
token: &str,
|
||||
language_id: &str
|
||||
) -> Vec<CompletionItem> {
|
||||
|
@ -5,7 +5,7 @@ use regex::Regex;
|
||||
use ropey::RopeSlice;
|
||||
use tower_lsp::lsp_types::{GotoDefinitionResponse, LocationLink, Position, Range, Url};
|
||||
|
||||
use crate::{core::{self, hdlparam::{self, FastHdlparam}}, server::LSPServer, utils::{get_word_range_at_position, resolve_path, to_escape_path}};
|
||||
use crate::{core::{self, hdlparam::{self, FastHdlparam}}, server::LspServer, utils::{get_word_range_at_position, resolve_path, to_escape_path}};
|
||||
|
||||
/// 跳转到 include 的文件
|
||||
pub fn goto_include_definition(uri: &Url, line: &RopeSlice, pos: Position) -> Option<GotoDefinitionResponse> {
|
||||
@ -73,7 +73,7 @@ pub fn goto_include_definition(uri: &Url, line: &RopeSlice, pos: Position) -> Op
|
||||
|
||||
|
||||
/// 跳转到宏定义
|
||||
pub fn goto_macro_definition(server: &LSPServer, line: &RopeSlice, pos: Position) -> Option<GotoDefinitionResponse> {
|
||||
pub fn goto_macro_definition(server: &LspServer, line: &RopeSlice, pos: Position) -> Option<GotoDefinitionResponse> {
|
||||
let macro_text_regex = Regex::new(r"[`0-9a-zA-Z]").unwrap();
|
||||
if let Some((macro_text, range)) = get_word_range_at_position(line, pos, macro_text_regex) {
|
||||
if macro_text.starts_with("`") {
|
||||
@ -103,7 +103,7 @@ pub fn goto_macro_definition(server: &LSPServer, line: &RopeSlice, pos: Position
|
||||
|
||||
|
||||
fn goto_instantiation<'a>(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
fast: &'a FastHdlparam,
|
||||
token_name: &str,
|
||||
pos: &Position,
|
||||
@ -207,7 +207,7 @@ fn goto_instantiation<'a>(
|
||||
}
|
||||
|
||||
pub fn goto_position_port_param_definition(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
line: &RopeSlice,
|
||||
url: &Url,
|
||||
pos: Position
|
||||
@ -235,7 +235,7 @@ pub fn goto_position_port_param_definition(
|
||||
}
|
||||
|
||||
pub fn goto_module_declaration_definition(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
token_name: &str
|
||||
) -> Option<GotoDefinitionResponse> {
|
||||
let hdl_param = server.srcs.hdl_param.clone();
|
||||
@ -276,7 +276,7 @@ pub fn goto_module_declaration_definition(
|
||||
|
||||
fn goto_common_module_declaration_definition(
|
||||
#[allow(unused)]
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
#[allow(unused)]
|
||||
token_name: &str,
|
||||
#[allow(unused)]
|
||||
@ -301,7 +301,7 @@ fn goto_common_module_declaration_definition(
|
||||
|
||||
fn goto_ip_module_declaration_definition(
|
||||
#[allow(unused)]
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
#[allow(unused)]
|
||||
token_name: &str,
|
||||
#[allow(unused)]
|
||||
@ -331,7 +331,7 @@ fn goto_ip_module_declaration_definition(
|
||||
|
||||
fn goto_primitives_module_declaration_definition(
|
||||
#[allow(unused)]
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
#[allow(unused)]
|
||||
token_name: &str,
|
||||
#[allow(unused)]
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::core::hdlparam::{self, FastHdlparam};
|
||||
use crate::utils::get_language_id_by_uri;
|
||||
use crate::server::LSPServer;
|
||||
use crate::server::LspServer;
|
||||
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
@ -19,7 +19,7 @@ pub use extract_defs::*;
|
||||
mod sv;
|
||||
mod vhdl;
|
||||
|
||||
impl LSPServer {
|
||||
impl LspServer {
|
||||
pub fn goto_definition(&self, params: GotoDefinitionParams) -> Option<GotoDefinitionResponse> {
|
||||
let language_id = get_language_id_by_uri(¶ms.text_document_position_params.text_document.uri);
|
||||
match language_id.as_str() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::utils::get_definition_token;
|
||||
use crate::server::LSPServer;
|
||||
use crate::server::LspServer;
|
||||
use crate::sources::LSPSupport;
|
||||
|
||||
#[allow(unused)]
|
||||
@ -8,7 +8,7 @@ use tower_lsp::lsp_types::*;
|
||||
|
||||
use super::{feature::*, Definition, Scope};
|
||||
|
||||
pub fn goto_definition(server: &LSPServer, params: &GotoDefinitionParams) -> Option<GotoDefinitionResponse> {
|
||||
pub fn goto_definition(server: &LspServer, params: &GotoDefinitionParams) -> Option<GotoDefinitionResponse> {
|
||||
let doc = ¶ms.text_document_position_params.text_document.uri;
|
||||
let pos = params.text_document_position_params.position;
|
||||
let file_id = server.srcs.get_id(doc).to_owned();
|
||||
|
@ -3,11 +3,11 @@ use std::{path::PathBuf, str::FromStr};
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
use tower_lsp::lsp_types::*;
|
||||
use crate::{server::LSPServer, utils::{from_lsp_pos, get_definition_token, srcpos_to_location, to_escape_path}};
|
||||
use crate::{server::LspServer, utils::{from_lsp_pos, get_definition_token, srcpos_to_location, to_escape_path}};
|
||||
|
||||
use super::{Definition, Scope};
|
||||
|
||||
pub fn goto_vhdl_definition(server: &LSPServer, params: &GotoDefinitionParams) -> Option<GotoDefinitionResponse> {
|
||||
pub fn goto_vhdl_definition(server: &LspServer, params: &GotoDefinitionParams) -> Option<GotoDefinitionResponse> {
|
||||
let doc = ¶ms.text_document_position_params.text_document.uri;
|
||||
let pos = params.text_document_position_params.position;
|
||||
let file_id = server.srcs.get_id(doc).to_owned();
|
||||
|
@ -1,10 +1,10 @@
|
||||
use crate::server::ProjectConfig;
|
||||
use regex::Regex;
|
||||
use std::fs::OpenOptions;
|
||||
|
||||
use crate::{server::{LspConfiguration, LspServer}, utils::get_language_id_by_uri};
|
||||
use log::info;
|
||||
use ropey::Rope;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
use serde::Deserialize;
|
||||
use tower_lsp::lsp_types::*;
|
||||
use walkdir::DirEntry;
|
||||
|
||||
pub mod verible;
|
||||
pub mod verilator;
|
||||
@ -16,202 +16,148 @@ pub use verilator::*;
|
||||
pub use vivado::*;
|
||||
pub use modelsim::*;
|
||||
|
||||
/// description
|
||||
/// 诊断功能需要提供两套函数,一套函数用于从给定路径读取文件并给出诊断结果;一套用于从 lsp 的文件缓冲区直接读取文本然后给出诊断结果。
|
||||
/// 前者用于扫描整个项目使用,后者在用户实时修改代码时,给出实时的诊断信息。
|
||||
|
||||
/// 获取诊断核心函数
|
||||
pub fn provide_diagnostics(
|
||||
uri: Url,
|
||||
rope: &Rope,
|
||||
#[allow(unused_variables)] files: Vec<Url>,
|
||||
configuration: &ProjectConfig,
|
||||
#[allow(unused_variables)]
|
||||
files: Vec<Url>,
|
||||
configuration: &LspConfiguration,
|
||||
) -> PublishDiagnosticsParams {
|
||||
let mut diagnostics = Vec::<Diagnostic>::new();
|
||||
let language_id = get_language_id_by_uri(&uri);
|
||||
|
||||
// 选择对应语言的 lsp
|
||||
let linter_configuration = match language_id.as_str() {
|
||||
"vhdl" => Some(&configuration.vhdl_linter_configuration),
|
||||
"verilog" => Some(&configuration.vlog_linter_configuration),
|
||||
"systemverilog" => Some(&configuration.svlog_linter_configuration),
|
||||
_ => None
|
||||
};
|
||||
|
||||
if linter_configuration.is_none() {
|
||||
info!("未知语言 {} 试图发起诊断", language_id);
|
||||
return PublishDiagnosticsParams {
|
||||
uri, diagnostics,
|
||||
version: None
|
||||
};
|
||||
}
|
||||
|
||||
let linter_configuration = linter_configuration.unwrap();
|
||||
|
||||
// 根据配置决定使用哪一个诊断器
|
||||
// 外层代码需要保证只有一个 linter.enable 为 true
|
||||
if linter_configuration.verilator.linter.enabled {
|
||||
info!("verilator linter enter");
|
||||
|
||||
} else if linter_configuration.verible.linter.enabled {
|
||||
info!("verilator linter enter");
|
||||
|
||||
} else if linter_configuration.modelsim.linter.enabled {
|
||||
info!("modelsim linter enter");
|
||||
|
||||
} else if linter_configuration.vivado.linter.enabled {
|
||||
info!("vivado linter enter");
|
||||
|
||||
}
|
||||
|
||||
PublishDiagnosticsParams {
|
||||
uri, diagnostics,
|
||||
version: None
|
||||
}
|
||||
}
|
||||
|
||||
/// 根据输入的名字选择诊断器
|
||||
/// - `linter_name` 为 `"vivado" | "modelsim" | "verilator" | "verible" | "iverilog"`
|
||||
/// - `language_id` 为 `"vhdl" | "verilog" | "systemverilog"`
|
||||
/// - `linter_path` 为第三方的可执行文件的路径
|
||||
pub fn update_diagnostics_configuration(
|
||||
server: &LspServer,
|
||||
linter_name: &str,
|
||||
language_id: &str,
|
||||
linter_path: &str
|
||||
) {
|
||||
let mut configuration = server.configuration.write().unwrap();
|
||||
|
||||
// 选择对应语言的 lsp
|
||||
let linter_configuration = match language_id {
|
||||
"vhdl" => Some(&mut configuration.vhdl_linter_configuration),
|
||||
"verilog" => Some(&mut configuration.vlog_linter_configuration),
|
||||
"systemverilog" => Some(&mut configuration.svlog_linter_configuration),
|
||||
_ => None
|
||||
};
|
||||
|
||||
if linter_configuration.is_none() {
|
||||
info!("未知语言 {} 试图配置诊断器", language_id);
|
||||
return;
|
||||
}
|
||||
|
||||
let linter_configuration = linter_configuration.unwrap();
|
||||
|
||||
linter_configuration.verilator.linter.enabled = false;
|
||||
linter_configuration.verible.linter.enabled = false;
|
||||
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);
|
||||
|
||||
if !(cfg!(test) && (uri.to_string().starts_with("file:///test"))) {
|
||||
let diagnostics = {
|
||||
if configuration.verilator.syntax.enabled {
|
||||
if let Ok(path) = uri.to_file_path() {
|
||||
match verilator_syntax(
|
||||
rope,
|
||||
path,
|
||||
&configuration.verilator.syntax.path,
|
||||
&configuration.verilator.syntax.args,
|
||||
) {
|
||||
Some(diags) => diags,
|
||||
None => Vec::new(),
|
||||
}
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
} else if configuration.verible.syntax.enabled {
|
||||
match verible_syntax(rope, &configuration.verible.syntax.path, &configuration.verible.syntax.args) {
|
||||
Some(diags) => diags,
|
||||
None => Vec::new(),
|
||||
}
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
};
|
||||
PublishDiagnosticsParams {
|
||||
uri,
|
||||
diagnostics,
|
||||
version: None,
|
||||
}
|
||||
} else {
|
||||
PublishDiagnosticsParams {
|
||||
uri,
|
||||
diagnostics: Vec::new(),
|
||||
version: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn is_hidden(entry: &DirEntry) -> bool {
|
||||
entry
|
||||
.file_name()
|
||||
.to_str()
|
||||
.map(|s| s.starts_with('.'))
|
||||
.unwrap_or(false)
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(serde::Serialize)]
|
||||
pub enum DigitalLinterMode {
|
||||
/// 全局诊断,将所有设计源直接进行诊断,并报错,无论文件是否打开
|
||||
FULL,
|
||||
/// 单文件关闭时,对应报错去除,打开哪个文件就对哪个文件进行诊断
|
||||
SINGLE,
|
||||
/// 全局关闭,即整个工程都不进行工程报错
|
||||
NONE
|
||||
}
|
||||
|
||||
|
||||
/// convert captured severity string to DiagnosticSeverity
|
||||
fn verilator_severity(severity: &str) -> Option<DiagnosticSeverity> {
|
||||
match severity {
|
||||
"Error" => Some(DiagnosticSeverity::ERROR),
|
||||
s if s.starts_with("Warning") => Some(DiagnosticSeverity::WARNING),
|
||||
// NOTE: afaik, verilator doesn't have an info or hint severity
|
||||
_ => Some(DiagnosticSeverity::INFORMATION),
|
||||
}
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct DigitalLinterConfiguration {
|
||||
// verible 相关的工具配置
|
||||
pub verible: VeribleConfiguration,
|
||||
// verilator 相关的工具配置
|
||||
pub verilator: VerilatorConfiguration,
|
||||
// modelsim 相关的工具配置
|
||||
pub modelsim: ModelsimConfiguration,
|
||||
// vivado 相关的工具配置
|
||||
pub vivado: VivadoConfiguration
|
||||
}
|
||||
|
||||
/// syntax checking using verilator --lint-only
|
||||
fn verilator_syntax(
|
||||
rope: &Rope,
|
||||
file_path: PathBuf,
|
||||
verilator_syntax_path: &str,
|
||||
verilator_syntax_args: &[String],
|
||||
) -> Option<Vec<Diagnostic>> {
|
||||
let mut child = Command::new(verilator_syntax_path)
|
||||
.stdin(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.args(verilator_syntax_args)
|
||||
.arg(file_path.to_str()?)
|
||||
.spawn()
|
||||
.ok()?;
|
||||
|
||||
static RE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();
|
||||
let re = RE.get_or_init(|| {
|
||||
Regex::new(
|
||||
r"%(?P<severity>Error|Warning)(-(?P<warning_type>[A-Z0-9_]+))?: (?P<filepath>[^:]+):(?P<line>\d+):((?P<col>\d+):)? ?(?P<message>.*)",
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
// write file to stdin, read output from stdout
|
||||
rope.write_to(child.stdin.as_mut()?).ok()?;
|
||||
let output = child.wait_with_output().ok()?;
|
||||
if !output.status.success() {
|
||||
let mut diags: Vec<Diagnostic> = Vec::new();
|
||||
let raw_output = String::from_utf8(output.stderr).ok()?;
|
||||
let filtered_output = raw_output
|
||||
.lines()
|
||||
.filter(|line| line.starts_with('%'))
|
||||
.collect::<Vec<&str>>();
|
||||
for error in filtered_output {
|
||||
let caps = match re.captures(error) {
|
||||
Some(caps) => caps,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
// check if diagnostic is for this file, since verilator can provide diagnostics for
|
||||
// included files
|
||||
if caps.name("filepath")?.as_str() != file_path.to_str().unwrap_or("") {
|
||||
continue;
|
||||
}
|
||||
let severity = verilator_severity(caps.name("severity")?.as_str());
|
||||
let line: u32 = caps.name("line")?.as_str().to_string().parse().ok()?;
|
||||
let col: u32 = caps.name("col").map_or("1", |m| m.as_str()).parse().ok()?;
|
||||
let pos = Position::new(line - 1, col - 1);
|
||||
let msg = match severity {
|
||||
Some(DiagnosticSeverity::ERROR) => caps.name("message")?.as_str().to_string(),
|
||||
Some(DiagnosticSeverity::WARNING) => format!(
|
||||
"{}: {}",
|
||||
caps.name("warning_type")?.as_str(),
|
||||
caps.name("message")?.as_str()
|
||||
),
|
||||
_ => "".to_string(),
|
||||
};
|
||||
diags.push(Diagnostic::new(
|
||||
Range::new(pos, pos),
|
||||
severity,
|
||||
None,
|
||||
Some("verilator".to_string()),
|
||||
msg,
|
||||
None,
|
||||
None,
|
||||
));
|
||||
impl Default for DigitalLinterConfiguration {
|
||||
fn default() -> Self {
|
||||
DigitalLinterConfiguration {
|
||||
verible: VeribleConfiguration::default(),
|
||||
verilator: VerilatorConfiguration::default(),
|
||||
modelsim: ModelsimConfiguration::default(),
|
||||
vivado: VivadoConfiguration::default()
|
||||
}
|
||||
Some(diags)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// syntax checking using verible-verilog-syntax
|
||||
fn verible_syntax(
|
||||
rope: &Rope,
|
||||
verible_syntax_path: &str,
|
||||
verible_syntax_args: &[String],
|
||||
) -> Option<Vec<Diagnostic>> {
|
||||
let mut child = Command::new(verible_syntax_path)
|
||||
.stdin(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.args(verible_syntax_args)
|
||||
.arg("-")
|
||||
.spawn()
|
||||
.ok()?;
|
||||
|
||||
static RE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();
|
||||
let re = RE.get_or_init(|| {
|
||||
Regex::new(
|
||||
r"^.+:(?P<line>\d*):(?P<startcol>\d*)(?:-(?P<endcol>\d*))?:\s(?P<message>.*)\s.*$",
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
// write file to stdin, read output from stdout
|
||||
rope.write_to(child.stdin.as_mut()?).ok()?;
|
||||
let output = child.wait_with_output().ok()?;
|
||||
if !output.status.success() {
|
||||
let mut diags: Vec<Diagnostic> = Vec::new();
|
||||
let raw_output = String::from_utf8(output.stdout).ok()?;
|
||||
for error in raw_output.lines() {
|
||||
let caps = re.captures(error)?;
|
||||
let line: u32 = caps.name("line")?.as_str().parse().ok()?;
|
||||
let startcol: u32 = caps.name("startcol")?.as_str().parse().ok()?;
|
||||
let endcol: Option<u32> = match caps.name("endcol").map(|e| e.as_str().parse()) {
|
||||
Some(Ok(e)) => Some(e),
|
||||
None => None,
|
||||
Some(Err(_)) => return None,
|
||||
};
|
||||
let start_pos = Position::new(line - 1, startcol - 1);
|
||||
let end_pos = Position::new(line - 1, endcol.unwrap_or(startcol) - 1);
|
||||
diags.push(Diagnostic::new(
|
||||
Range::new(start_pos, end_pos),
|
||||
Some(DiagnosticSeverity::ERROR),
|
||||
None,
|
||||
Some("verible".to_string()),
|
||||
caps.name("message")?.as_str().to_string(),
|
||||
None,
|
||||
None,
|
||||
));
|
||||
}
|
||||
Some(diags)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
@ -1,5 +1,53 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct ModelsimConfiguration {
|
||||
pub linter: ModelsimLinter,
|
||||
pub format: ModelsimFormat,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct ModelsimLinter {
|
||||
pub name: String,
|
||||
/// 目前是否启动
|
||||
pub enabled: bool,
|
||||
pub path: 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 {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: "modelsim".to_string(),
|
||||
enabled: true,
|
||||
path: "Modelsim-verilog-syntax".to_string(),
|
||||
args: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Default for ModelsimFormat {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
path: "Modelsim-verilog-format".to_string(),
|
||||
args: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn provide_diagnostics() {
|
||||
|
||||
}
|
@ -1,15 +1,22 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use regex::Regex;
|
||||
use ropey::Rope;
|
||||
use std::process::{Command, Stdio};
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct VeribleConfiguration {
|
||||
pub syntax: VeribleSyntax,
|
||||
pub linter: VeribleLinter,
|
||||
pub format: VeribleFormat,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct VeribleSyntax {
|
||||
pub struct VeribleLinter {
|
||||
pub name: String,
|
||||
/// 目前是否启动
|
||||
pub enabled: bool,
|
||||
pub path: String,
|
||||
pub args: Vec<String>,
|
||||
@ -23,9 +30,10 @@ pub struct VeribleFormat {
|
||||
pub args: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for VeribleSyntax {
|
||||
impl Default for VeribleLinter {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: "verible".to_string(),
|
||||
enabled: true,
|
||||
path: "verible-verilog-syntax".to_string(),
|
||||
args: Vec::new(),
|
||||
@ -47,3 +55,60 @@ impl Default for VeribleFormat {
|
||||
pub fn provide_diagnostics() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// syntax checking using verible-verilog-syntax
|
||||
fn verible_syntax(
|
||||
rope: &Rope,
|
||||
verible_syntax_path: &str,
|
||||
verible_syntax_args: &[String],
|
||||
) -> Option<Vec<Diagnostic>> {
|
||||
let mut child = Command::new(verible_syntax_path)
|
||||
.stdin(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.args(verible_syntax_args)
|
||||
.arg("-")
|
||||
.spawn()
|
||||
.ok()?;
|
||||
|
||||
static RE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();
|
||||
let re = RE.get_or_init(|| {
|
||||
Regex::new(
|
||||
r"^.+:(?P<line>\d*):(?P<startcol>\d*)(?:-(?P<endcol>\d*))?:\s(?P<message>.*)\s.*$",
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
// write file to stdin, read output from stdout
|
||||
rope.write_to(child.stdin.as_mut()?).ok()?;
|
||||
|
||||
let output = child.wait_with_output().ok()?;
|
||||
if !output.status.success() {
|
||||
let mut diags: Vec<Diagnostic> = Vec::new();
|
||||
let raw_output = String::from_utf8(output.stdout).ok()?;
|
||||
for error in raw_output.lines() {
|
||||
let caps = re.captures(error)?;
|
||||
let line: u32 = caps.name("line")?.as_str().parse().ok()?;
|
||||
let startcol: u32 = caps.name("startcol")?.as_str().parse().ok()?;
|
||||
let endcol: Option<u32> = match caps.name("endcol").map(|e| e.as_str().parse()) {
|
||||
Some(Ok(e)) => Some(e),
|
||||
None => None,
|
||||
Some(Err(_)) => return None,
|
||||
};
|
||||
let start_pos = Position::new(line - 1, startcol - 1);
|
||||
let end_pos = Position::new(line - 1, endcol.unwrap_or(startcol) - 1);
|
||||
diags.push(Diagnostic::new(
|
||||
Range::new(start_pos, end_pos),
|
||||
Some(DiagnosticSeverity::ERROR),
|
||||
None,
|
||||
Some("verible".to_string()),
|
||||
caps.name("message")?.as_str().to_string(),
|
||||
None,
|
||||
None,
|
||||
));
|
||||
}
|
||||
Some(diags)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,30 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use regex::Regex;
|
||||
use ropey::Rope;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct VerilatorConfiguration {
|
||||
pub syntax: VerilatorSyntax,
|
||||
pub linter: VerilatorLinter,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct VerilatorSyntax {
|
||||
pub struct VerilatorLinter {
|
||||
pub name: String,
|
||||
/// 目前是否启动
|
||||
pub enabled: bool,
|
||||
pub path: String,
|
||||
pub args: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for VerilatorSyntax {
|
||||
impl Default for VerilatorLinter {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: "verilator".to_string(),
|
||||
enabled: true,
|
||||
path: "verilator".to_string(),
|
||||
args: vec![
|
||||
@ -31,3 +39,87 @@ impl Default for VerilatorSyntax {
|
||||
pub fn provide_diagnostics() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// convert captured severity string to DiagnosticSeverity
|
||||
fn verilator_severity(severity: &str) -> Option<DiagnosticSeverity> {
|
||||
match severity {
|
||||
"Error" => Some(DiagnosticSeverity::ERROR),
|
||||
s if s.starts_with("Warning") => Some(DiagnosticSeverity::WARNING),
|
||||
// NOTE: afaik, verilator doesn't have an info or hint severity
|
||||
_ => Some(DiagnosticSeverity::INFORMATION),
|
||||
}
|
||||
}
|
||||
|
||||
/// syntax checking using verilator --lint-only
|
||||
fn verilator_syntax(
|
||||
rope: &Rope,
|
||||
file_path: PathBuf,
|
||||
verilator_syntax_path: &str,
|
||||
verilator_syntax_args: &[String],
|
||||
) -> Option<Vec<Diagnostic>> {
|
||||
let mut child = Command::new(verilator_syntax_path)
|
||||
.stdin(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.args(verilator_syntax_args)
|
||||
.arg(file_path.to_str()?)
|
||||
.spawn()
|
||||
.ok()?;
|
||||
|
||||
static RE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();
|
||||
let re = RE.get_or_init(|| {
|
||||
Regex::new(
|
||||
r"%(?P<severity>Error|Warning)(-(?P<warning_type>[A-Z0-9_]+))?: (?P<filepath>[^:]+):(?P<line>\d+):((?P<col>\d+):)? ?(?P<message>.*)",
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
// write file to stdin, read output from stdout
|
||||
rope.write_to(child.stdin.as_mut()?).ok()?;
|
||||
let output = child.wait_with_output().ok()?;
|
||||
if !output.status.success() {
|
||||
let mut diags: Vec<Diagnostic> = Vec::new();
|
||||
let raw_output = String::from_utf8(output.stderr).ok()?;
|
||||
let filtered_output = raw_output
|
||||
.lines()
|
||||
.filter(|line| line.starts_with('%'))
|
||||
.collect::<Vec<&str>>();
|
||||
for error in filtered_output {
|
||||
let caps = match re.captures(error) {
|
||||
Some(caps) => caps,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
// check if diagnostic is for this file, since verilator can provide diagnostics for
|
||||
// included files
|
||||
if caps.name("filepath")?.as_str() != file_path.to_str().unwrap_or("") {
|
||||
continue;
|
||||
}
|
||||
let severity = verilator_severity(caps.name("severity")?.as_str());
|
||||
let line: u32 = caps.name("line")?.as_str().to_string().parse().ok()?;
|
||||
let col: u32 = caps.name("col").map_or("1", |m| m.as_str()).parse().ok()?;
|
||||
let pos = Position::new(line - 1, col - 1);
|
||||
let msg = match severity {
|
||||
Some(DiagnosticSeverity::ERROR) => caps.name("message")?.as_str().to_string(),
|
||||
Some(DiagnosticSeverity::WARNING) => format!(
|
||||
"{}: {}",
|
||||
caps.name("warning_type")?.as_str(),
|
||||
caps.name("message")?.as_str()
|
||||
),
|
||||
_ => "".to_string(),
|
||||
};
|
||||
diags.push(Diagnostic::new(
|
||||
Range::new(pos, pos),
|
||||
severity,
|
||||
None,
|
||||
Some("verilator".to_string()),
|
||||
msg,
|
||||
None,
|
||||
None,
|
||||
));
|
||||
}
|
||||
Some(diags)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -3,20 +3,23 @@ use serde::{Deserialize, Serialize};
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct VivadoConfiguration {
|
||||
pub syntax: VivadoSyntax,
|
||||
pub linter: VivadoLinter,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct VivadoSyntax {
|
||||
pub struct VivadoLinter {
|
||||
pub name: String,
|
||||
/// 目前是否启动
|
||||
pub enabled: bool,
|
||||
pub path: String,
|
||||
pub args: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for VivadoSyntax {
|
||||
impl Default for VivadoLinter {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: "vivado".to_string(),
|
||||
enabled: true,
|
||||
path: "Vivado".to_string(),
|
||||
args: vec![
|
||||
|
@ -1,10 +1,10 @@
|
||||
use crate::{server::LSPServer, utils::{get_definition_token, get_language_id_by_uri}};
|
||||
use crate::{server::LspServer, utils::{get_definition_token, get_language_id_by_uri}};
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
mod sv;
|
||||
mod vhdl;
|
||||
|
||||
impl LSPServer {
|
||||
impl LspServer {
|
||||
pub fn document_highlight(
|
||||
&self,
|
||||
params: DocumentHighlightParams,
|
||||
|
@ -3,10 +3,10 @@ use log::info;
|
||||
use sv_parser::{RefNode, SyntaxTree};
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
use crate::{definition::{get_ident, Scope}, server::LSPServer, sources::{LSPSupport, ParseIR, Source}};
|
||||
use crate::{definition::{get_ident, Scope}, server::LspServer, sources::{LSPSupport, ParseIR, Source}};
|
||||
|
||||
pub fn document_highlight(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
token: &str,
|
||||
file: &Source,
|
||||
pos: Position,
|
||||
|
@ -2,10 +2,10 @@ use log::info;
|
||||
use sv_parser::{RefNode, SyntaxTree};
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
use crate::{definition::{get_ident, Scope}, server::LSPServer, sources::{LSPSupport, ParseIR, Source}};
|
||||
use crate::{definition::{get_ident, Scope}, server::LspServer, sources::{LSPSupport, ParseIR, Source}};
|
||||
|
||||
pub fn document_highlight(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
token: &str,
|
||||
file: &Source,
|
||||
pos: Position,
|
||||
|
@ -1,11 +1,11 @@
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
use crate::{server::LSPServer, utils::get_language_id_by_uri};
|
||||
use crate::{server::LspServer, utils::get_language_id_by_uri};
|
||||
|
||||
mod sv;
|
||||
mod vhdl;
|
||||
|
||||
impl LSPServer {
|
||||
impl LspServer {
|
||||
pub fn document_symbol(&self, params: DocumentSymbolParams) -> Option<DocumentSymbolResponse> {
|
||||
let uri = ¶ms.text_document.uri;
|
||||
let language_id = get_language_id_by_uri(uri);
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::{definition::Scope, server::LSPServer};
|
||||
use crate::{definition::Scope, server::LspServer};
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
pub fn document_symbol(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
params: &DocumentSymbolParams
|
||||
) -> Option<DocumentSymbolResponse> {
|
||||
let uri = ¶ms.text_document.uri;
|
||||
|
@ -4,9 +4,9 @@ use std::{path::PathBuf, str::FromStr};
|
||||
use log::info;
|
||||
use tower_lsp::lsp_types::*;
|
||||
use vhdl_lang::{EntHierarchy, Token};
|
||||
use crate::{definition::Scope, server::LSPServer, utils::{to_escape_path, to_lsp_range, to_symbol_kind}};
|
||||
use crate::{definition::Scope, server::LspServer, utils::{to_escape_path, to_lsp_range, to_symbol_kind}};
|
||||
|
||||
pub fn document_symbol(server: &LSPServer, params: &DocumentSymbolParams) -> Option<DocumentSymbolResponse> {
|
||||
pub fn document_symbol(server: &LspServer, params: &DocumentSymbolParams) -> Option<DocumentSymbolResponse> {
|
||||
// info!("enter document symbol");
|
||||
|
||||
let uri = ¶ms.text_document.uri;
|
||||
|
@ -1,60 +1,62 @@
|
||||
use crate::server::LSPServer;
|
||||
use crate::server::LspServer;
|
||||
use crate::sources::LSPSupport;
|
||||
use log::info;
|
||||
use ropey::Rope;
|
||||
use std::process::{Command, Stdio};
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
impl LSPServer {
|
||||
impl LspServer {
|
||||
pub fn formatting(&self, params: DocumentFormattingParams) -> Option<Vec<TextEdit>> {
|
||||
let uri = params.text_document.uri;
|
||||
info!("formatting {}", &uri);
|
||||
let file_id = self.srcs.get_id(&uri).to_owned();
|
||||
self.srcs.wait_parse_ready(file_id, false);
|
||||
let file = self.srcs.get_file(file_id)?;
|
||||
let file = file.read().ok()?;
|
||||
None
|
||||
// let uri = params.text_document.uri;
|
||||
// info!("formatting {}", &uri);
|
||||
// let file_id = self.srcs.get_id(&uri).to_owned();
|
||||
// self.srcs.wait_parse_ready(file_id, false);
|
||||
// let file = self.srcs.get_file(file_id)?;
|
||||
// let file = file.read().ok()?;
|
||||
|
||||
let conf = self.configuration.read().unwrap();
|
||||
if conf.verible.format.enabled {
|
||||
Some(vec![TextEdit::new(
|
||||
Range::new(
|
||||
file.text.char_to_pos(0),
|
||||
file.text.char_to_pos(file.text.len_chars()),
|
||||
),
|
||||
format_document(
|
||||
&file.text,
|
||||
None,
|
||||
&conf.verible.format.path,
|
||||
&conf.verible.format.args,
|
||||
)?,
|
||||
)])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
// let conf = self.configuration.read().unwrap();
|
||||
// if conf.verible.format.enabled {
|
||||
// Some(vec![TextEdit::new(
|
||||
// Range::new(
|
||||
// file.text.char_to_pos(0),
|
||||
// file.text.char_to_pos(file.text.len_chars()),
|
||||
// ),
|
||||
// format_document(
|
||||
// &file.text,
|
||||
// None,
|
||||
// &conf.verible.format.path,
|
||||
// &conf.verible.format.args,
|
||||
// )?,
|
||||
// )])
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn range_formatting(&self, params: DocumentRangeFormattingParams) -> Option<Vec<TextEdit>> {
|
||||
let uri = params.text_document.uri;
|
||||
info!("range formatting {}", &uri);
|
||||
let file_id = self.srcs.get_id(&uri).to_owned();
|
||||
self.srcs.wait_parse_ready(file_id, false);
|
||||
let file = self.srcs.get_file(file_id)?;
|
||||
let file = file.read().ok()?;
|
||||
None
|
||||
// let uri = params.text_document.uri;
|
||||
// info!("range formatting {}", &uri);
|
||||
// let file_id = self.srcs.get_id(&uri).to_owned();
|
||||
// self.srcs.wait_parse_ready(file_id, false);
|
||||
// let file = self.srcs.get_file(file_id)?;
|
||||
// let file = file.read().ok()?;
|
||||
|
||||
let conf = self.configuration.read().unwrap();
|
||||
if conf.verible.format.enabled {
|
||||
Some(vec![TextEdit::new(
|
||||
file.text.char_range_to_range(0..file.text.len_chars()),
|
||||
format_document(
|
||||
&file.text,
|
||||
Some(params.range),
|
||||
&conf.verible.format.path,
|
||||
&conf.verible.format.args,
|
||||
)?,
|
||||
)])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
// let conf = self.configuration.read().unwrap();
|
||||
// if conf.verible.format.enabled {
|
||||
// Some(vec![TextEdit::new(
|
||||
// file.text.char_range_to_range(0..file.text.len_chars()),
|
||||
// format_document(
|
||||
// &file.text,
|
||||
// Some(params.range),
|
||||
// &conf.verible.format.path,
|
||||
// &conf.verible.format.args,
|
||||
// )?,
|
||||
// )])
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ use regex::Regex;
|
||||
use ropey::RopeSlice;
|
||||
use tower_lsp::lsp_types::{Hover, HoverContents, LanguageString, MarkedString, Position, Range, Url};
|
||||
|
||||
use crate::{core::{self, hdlparam::{Define, FastHdlparam}, primitive_parser::PrimitiveText}, server::LSPServer};
|
||||
use crate::{core::{self, hdlparam::{Define, FastHdlparam}, primitive_parser::PrimitiveText}, server::LspServer};
|
||||
|
||||
use super::{get_language_id_by_path_str, get_word_range_at_position, resolve_path, to_escape_path};
|
||||
|
||||
@ -198,7 +198,7 @@ fn make_macro_define_content(macro_define: &Define) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hover_macro(server: &LSPServer, line: &RopeSlice, pos: Position, language_id: &str) -> Option<Hover> {
|
||||
pub fn hover_macro(server: &LspServer, line: &RopeSlice, pos: Position, language_id: &str) -> Option<Hover> {
|
||||
let macro_text_regex = Regex::new(r"[`_0-9a-zA-Z]").unwrap();
|
||||
if let Some((macro_text, range)) = get_word_range_at_position(line, pos, macro_text_regex) {
|
||||
if macro_text.starts_with("`") {
|
||||
@ -222,7 +222,7 @@ pub fn hover_macro(server: &LSPServer, line: &RopeSlice, pos: Position, language
|
||||
|
||||
|
||||
fn goto_instantiation<'a>(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
fast: &'a FastHdlparam,
|
||||
token_name: &str,
|
||||
pos: &Position,
|
||||
@ -313,7 +313,7 @@ fn goto_instantiation<'a>(
|
||||
/// 计算 position 赋值的 port 或者 param
|
||||
/// 比如 .clk ( clk ) 中的 .clk
|
||||
pub fn hover_position_port_param(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
line: &RopeSlice,
|
||||
url: &Url,
|
||||
pos: Position,
|
||||
@ -441,7 +441,7 @@ fn make_param_desc_hover(file_type: &str, param: &crate::core::hdlparam::Paramet
|
||||
}
|
||||
|
||||
pub fn hover_module_declaration(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
token_name: &str,
|
||||
#[allow(unused)]
|
||||
language_id: &str
|
||||
@ -486,7 +486,7 @@ pub fn hover_module_declaration(
|
||||
|
||||
fn hover_common_module_declaration(
|
||||
#[allow(unused)]
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
#[allow(unused)]
|
||||
token_name: &str,
|
||||
#[allow(unused)]
|
||||
@ -545,7 +545,7 @@ fn hover_common_module_declaration(
|
||||
|
||||
fn hover_ip_module_declaration(
|
||||
#[allow(unused)]
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
#[allow(unused)]
|
||||
token_name: &str,
|
||||
#[allow(unused)]
|
||||
@ -613,7 +613,7 @@ fn hover_ip_module_declaration(
|
||||
|
||||
fn hover_primitives_module_declaration(
|
||||
#[allow(unused)]
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
#[allow(unused)]
|
||||
token_name: &str,
|
||||
#[allow(unused)]
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::server::LSPServer;
|
||||
use crate::server::LspServer;
|
||||
use crate::utils::*;
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
@ -9,7 +9,7 @@ pub mod feature;
|
||||
mod sv;
|
||||
mod vhdl;
|
||||
|
||||
impl LSPServer {
|
||||
impl LspServer {
|
||||
pub fn hover(&self, params: HoverParams) -> Option<Hover> {
|
||||
let language_id = get_language_id_by_uri(¶ms.text_document_position_params.text_document.uri);
|
||||
match language_id.as_str() {
|
||||
|
@ -3,7 +3,7 @@ use log::info;
|
||||
use regex::Regex;
|
||||
use ropey::Rope;
|
||||
use tower_lsp::lsp_types::*;
|
||||
use crate::{core::hdlparam::{Instance, Module}, hover::{to_escape_path, BracketMatchResult, BracketMatcher}, server::LSPServer, sources::LSPSupport};
|
||||
use crate::{core::hdlparam::{Instance, Module}, hover::{to_escape_path, BracketMatchResult, BracketMatcher}, server::LspServer, sources::LSPSupport};
|
||||
use super::feature::*;
|
||||
use std::{path::PathBuf, str::FromStr, sync::RwLockReadGuard};
|
||||
|
||||
@ -11,7 +11,7 @@ use crate::definition::*;
|
||||
|
||||
use super::{get_definition_token, get_language_id_by_uri};
|
||||
|
||||
pub fn hover(server: &LSPServer, params: &HoverParams) -> Option<Hover> {
|
||||
pub fn hover(server: &LspServer, params: &HoverParams) -> Option<Hover> {
|
||||
let doc = ¶ms.text_document_position_params.text_document.uri;
|
||||
let pos: Position = params.text_document_position_params.position;
|
||||
let file_id: usize = server.srcs.get_id(doc).to_owned();
|
||||
@ -224,7 +224,7 @@ fn make_hover_with_comment(doc: &Rope, line: usize, language_id: &str, exclude_c
|
||||
/// 计算正常 symbol 的 hover
|
||||
fn hover_common_symbol(
|
||||
#[allow(unused)]
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
#[allow(unused)]
|
||||
token: &String,
|
||||
symbol_definition: &GenericDec,
|
||||
@ -294,7 +294,7 @@ fn hover_common_symbol(
|
||||
make_hover_with_comment(&file.text, def_line, &language_id, false)
|
||||
}
|
||||
|
||||
fn hover_for_module(server: &LSPServer, pos: Position, doc: &Url) -> bool {
|
||||
fn hover_for_module(server: &LspServer, pos: Position, doc: &Url) -> bool {
|
||||
let pathbuf = PathBuf::from_str(doc.path()).unwrap();
|
||||
let pathbuf = to_escape_path(&pathbuf);
|
||||
let path_string = pathbuf.to_str().unwrap().replace("\\", "/");
|
||||
@ -309,13 +309,13 @@ fn hover_for_module(server: &LSPServer, pos: Position, doc: &Url) -> bool {
|
||||
};
|
||||
|
||||
if let Some(_) = hdlparam.walk_module(&path_string, find_module_range) {
|
||||
// info!("[LSPServer] in hover: it is module");
|
||||
// info!("[LspServer] in hover: it is module");
|
||||
true
|
||||
} else if let Some(_) = hdlparam.walk_instantiation(&path_string, find_instance_range) {
|
||||
// info!("[LSPServer] in hover: it is instance");
|
||||
// info!("[LspServer] in hover: it is instance");
|
||||
true
|
||||
} else {
|
||||
// info!("[LSPServer] in hover: it is not instance");
|
||||
// info!("[LspServer] in hover: it is not instance");
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ use log::info;
|
||||
use regex::Regex;
|
||||
use ropey::Rope;
|
||||
use tower_lsp::lsp_types::*;
|
||||
use crate::{core::hdlparam::{Instance, Module}, definition::{Definition, DefinitionType, GenericDec, Scope}, hover::{BracketMatchResult, BracketMatcher}, server::LSPServer, sources::LSPSupport};
|
||||
use crate::{core::hdlparam::{Instance, Module}, definition::{Definition, DefinitionType, GenericDec, Scope}, hover::{BracketMatchResult, BracketMatcher}, server::LspServer, sources::LSPSupport};
|
||||
|
||||
use super::{from_lsp_pos, get_definition_token, get_language_id_by_uri, to_escape_path};
|
||||
|
||||
pub fn hover(server: &LSPServer, params: &HoverParams) -> Option<Hover> {
|
||||
pub fn hover(server: &LspServer, params: &HoverParams) -> Option<Hover> {
|
||||
let doc = ¶ms.text_document_position_params.text_document.uri;
|
||||
let pos: Position = params.text_document_position_params.position;
|
||||
let file_id: usize = server.srcs.get_id(doc).to_owned();
|
||||
@ -239,7 +239,7 @@ fn make_hover_with_comment(doc: &Rope, line: usize, language_id: &str, exclude_c
|
||||
|
||||
fn hover_common_symbol(
|
||||
#[allow(unused)]
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
#[allow(unused)]
|
||||
token: &String,
|
||||
symbol_definition: &GenericDec,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::server::LSPServer;
|
||||
use crate::server::LspServer;
|
||||
use crate::utils::*;
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
@ -7,7 +7,7 @@ use tower_lsp::lsp_types::*;
|
||||
mod sv;
|
||||
mod vhdl;
|
||||
|
||||
impl LSPServer {
|
||||
impl LspServer {
|
||||
pub fn inlay_hint(&self, params: InlayHintParams) -> Option<Vec<InlayHint>> {
|
||||
let language_id = get_language_id_by_uri(¶ms.text_document.uri);
|
||||
match language_id.as_str() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::{collections::HashMap, path::PathBuf, str::FromStr};
|
||||
|
||||
use crate::{core, server::LSPServer};
|
||||
use crate::{core, server::LspServer};
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
use ropey::Rope;
|
||||
@ -8,7 +8,7 @@ use tower_lsp::lsp_types::*;
|
||||
|
||||
use super::{get_language_id_by_path_str, to_escape_path};
|
||||
|
||||
pub fn inlay_hint(server: &LSPServer, params: &InlayHintParams) -> Option<Vec<InlayHint>> {
|
||||
pub fn inlay_hint(server: &LspServer, params: &InlayHintParams) -> Option<Vec<InlayHint>> {
|
||||
let uri = ¶ms.text_document.uri;
|
||||
let path = PathBuf::from_str(uri.path()).unwrap();
|
||||
let path = to_escape_path(&path);
|
||||
@ -58,7 +58,7 @@ fn is_visible_range(
|
||||
}
|
||||
|
||||
fn make_instparam_hints(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
params: &InlayHintParams,
|
||||
instance: &core::hdlparam::Instance,
|
||||
rope: &Rope
|
||||
@ -106,7 +106,7 @@ fn find_instport_inlay_hints_position(
|
||||
}
|
||||
|
||||
fn make_instport_hints(
|
||||
server: &LSPServer,
|
||||
server: &LspServer,
|
||||
params: &InlayHintParams,
|
||||
instance: &core::hdlparam::Instance,
|
||||
rope: &Rope
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::server::LSPServer;
|
||||
use crate::server::LspServer;
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
pub fn inlay_hint(server: &LSPServer, params: &InlayHintParams) -> Option<Vec<InlayHint>> {
|
||||
pub fn inlay_hint(server: &LspServer, params: &InlayHintParams) -> Option<Vec<InlayHint>> {
|
||||
None
|
||||
}
|
9
src/request/README.md
Normal file
9
src/request/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
request 负责实现前后端非 LSP 协议的通信,比如前端把配置文件同步到后端,前端获取 AST 的一部分数据用于前端的界面功能。
|
||||
|
||||
|
||||
request 是单向的,只能由前端主动发起。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
前端 --编码发送--> request.rs --解码处理--> 后端
|
||||
```
|
@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use tower_lsp::jsonrpc::Result;
|
||||
|
||||
use crate::server::Backend;
|
||||
use crate::{diagnostics::update_diagnostics_configuration, server::Backend};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UpdateConfigurationApi;
|
||||
@ -33,21 +33,75 @@ impl <'a>tower_lsp::jsonrpc::Method<&'a Arc<Backend>, (UpdateConfigurationParams
|
||||
let configs = request_param.configs;
|
||||
|
||||
// 用于未来进行配置分区
|
||||
#[allow(unused)]
|
||||
let config_type = request_param.config_type;
|
||||
|
||||
update_configuration(configs, &_server);
|
||||
update_configuration(configs, config_type, &_server);
|
||||
future::ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
/// 前端配置文件的更新
|
||||
fn update_configuration(
|
||||
configs: Vec<UpdateConfigurationItem>,
|
||||
config_type: String,
|
||||
backend: &Arc<Backend>
|
||||
) {
|
||||
let mut lsp_configuration = backend.server.srcs.lsp_configuration.write().unwrap();
|
||||
for config in configs {
|
||||
info!("name: {}, value: {}", config.name, config.value);
|
||||
lsp_configuration.insert(config.name, config.value);
|
||||
|
||||
match config_type.as_str() {
|
||||
// 所有配置同步到 lsp_configuration 中
|
||||
"lsp" => {
|
||||
for config in configs {
|
||||
info!("update config, name: {}, value: {}", config.name, config.value);
|
||||
lsp_configuration.insert(config.name, config.value);
|
||||
}
|
||||
},
|
||||
|
||||
// 针对当前项目选择的诊断器的更新
|
||||
// 此时 configs 的长度必然为 2
|
||||
// configs.0 含有当前选择的诊断器的名字的信息,比如 "digital-ide.function.lsp.linter.vlog.diagnostor": "vivado"
|
||||
// configs.1 含有第三方诊断器的合法路径相关的信息,比如 "path": "/opt/xilinx/Vivado/2022.2/bin/xvlog"
|
||||
"linter" => {
|
||||
if configs.len() < 2 {
|
||||
info!("update_configuration, type : {}, 发生错误,原因:configs 数量不为 2", config_type);
|
||||
return;
|
||||
}
|
||||
|
||||
let linter_name_configuration = &configs[0];
|
||||
let linter_path_configuration = &configs[1];
|
||||
|
||||
// something like 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()
|
||||
);
|
||||
|
||||
// 从 linter_name_configuration.name 解析出 language_id
|
||||
let language_id = {
|
||||
// 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
|
||||
}
|
||||
};
|
||||
|
||||
let linter_name = linter_name_configuration.value.as_str().unwrap();
|
||||
let linter_path = linter_path_configuration.value.as_str().unwrap();
|
||||
|
||||
update_diagnostics_configuration(
|
||||
&backend.server,
|
||||
linter_name,
|
||||
language_id,
|
||||
linter_path
|
||||
);
|
||||
},
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::core::cache_storage::CacheManager;
|
||||
use crate::diagnostics::{VeribleConfiguration, VerilatorConfiguration};
|
||||
use crate::diagnostics::{DigitalLinterConfiguration, DigitalLinterMode, ModelsimConfiguration, VeribleConfiguration, VerilatorConfiguration, VivadoConfiguration};
|
||||
use crate::sources::*;
|
||||
use crate::completion::{keyword::*, provide_vlog_sys_tasks_completions};
|
||||
use flexi_logger::LoggerHandle;
|
||||
@ -11,7 +11,7 @@ use std::sync::{Arc, Mutex, RwLock};
|
||||
use tower_lsp::jsonrpc::Result;
|
||||
use tower_lsp::lsp_types::*;
|
||||
use tower_lsp::{Client, LanguageServer};
|
||||
pub struct LSPServer {
|
||||
pub struct LspServer {
|
||||
/// 文件和 ast 相关的
|
||||
pub srcs: Sources,
|
||||
/// 缓存
|
||||
@ -25,23 +25,24 @@ pub struct LSPServer {
|
||||
/// vhdl 关键词的自动补全
|
||||
pub vhdl_keyword_completiom_items: Vec<CompletionItem>,
|
||||
/// 相关的配置项目
|
||||
pub configuration: Arc<RwLock<ProjectConfig>>,
|
||||
pub configuration: Arc<RwLock<LspConfiguration>>,
|
||||
|
||||
#[allow(unused)]
|
||||
pub log_handle: Mutex<Option<LoggerHandle>>,
|
||||
}
|
||||
|
||||
impl LSPServer {
|
||||
pub fn new(log_handle: Option<LoggerHandle>) -> LSPServer {
|
||||
impl LspServer {
|
||||
pub fn new(log_handle: Option<LoggerHandle>) -> LspServer {
|
||||
let user_home = dirs_next::home_dir().unwrap();
|
||||
let dide_home = user_home.join(".digital-ide");
|
||||
LSPServer {
|
||||
LspServer {
|
||||
srcs: Sources::new(),
|
||||
cache: CacheManager::new(dide_home),
|
||||
vlog_keyword_completion_items: keyword_completions(VLOG_KEYWORDS),
|
||||
vhdl_keyword_completiom_items: keyword_completions(VHDL_KEYWORDS),
|
||||
vlog_sys_tasks_completion_items: provide_vlog_sys_tasks_completions(),
|
||||
vlog_directives: other_completions(DIRECTIVES),
|
||||
configuration: Arc::new(RwLock::new(ProjectConfig::default())),
|
||||
configuration: Arc::new(RwLock::new(LspConfiguration::default())),
|
||||
log_handle: Mutex::new(log_handle),
|
||||
}
|
||||
}
|
||||
@ -49,7 +50,7 @@ impl LSPServer {
|
||||
|
||||
pub struct Backend {
|
||||
pub client: Client,
|
||||
pub server: LSPServer
|
||||
pub server: LspServer
|
||||
}
|
||||
|
||||
|
||||
@ -57,7 +58,7 @@ impl Backend {
|
||||
pub fn new(client: Client, log_handle: LoggerHandle) -> Backend {
|
||||
Backend {
|
||||
client,
|
||||
server: LSPServer::new(Some(log_handle)),
|
||||
server: LspServer::new(Some(log_handle)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -78,7 +79,7 @@ pub enum LogLevel {
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct ProjectConfig {
|
||||
pub struct LspConfiguration {
|
||||
// 用户工作目录的路径
|
||||
pub workspace_folder: Option<Url>,
|
||||
// 插件安装的根路径
|
||||
@ -93,29 +94,33 @@ pub struct ProjectConfig {
|
||||
// list of directories to recursively search for SystemVerilog/Verilog sources
|
||||
pub source_dirs: Vec<String>,
|
||||
|
||||
// verible 相关的工具配置
|
||||
pub verible: VeribleConfiguration,
|
||||
// verilator 相关的工具配置
|
||||
pub verilator: VerilatorConfiguration,
|
||||
|
||||
// pub modelsim: String,
|
||||
// pub vivado: String,
|
||||
|
||||
// 下方是和 linter 相关的配置
|
||||
// 诊断模式
|
||||
pub linter_mode: DigitalLinterMode,
|
||||
// vlog 的诊断配置
|
||||
pub vlog_linter_configuration: DigitalLinterConfiguration,
|
||||
// vhdl 的诊断配置
|
||||
pub vhdl_linter_configuration: DigitalLinterConfiguration,
|
||||
// svlog 的诊断配置
|
||||
pub svlog_linter_configuration: DigitalLinterConfiguration,
|
||||
// log level
|
||||
pub log_level: LogLevel
|
||||
}
|
||||
|
||||
impl Default for ProjectConfig {
|
||||
impl Default for LspConfiguration {
|
||||
fn default() -> Self {
|
||||
ProjectConfig {
|
||||
LspConfiguration {
|
||||
workspace_folder: None,
|
||||
extension_path: "".to_string(),
|
||||
tool_chain: "xilinx".to_string(),
|
||||
auto_search_workdir: true,
|
||||
include_dirs: Vec::new(),
|
||||
source_dirs: Vec::new(),
|
||||
verible: VeribleConfiguration::default(),
|
||||
verilator: VerilatorConfiguration::default(),
|
||||
linter_mode: DigitalLinterMode::FULL,
|
||||
vlog_linter_configuration: DigitalLinterConfiguration::default(),
|
||||
vhdl_linter_configuration: DigitalLinterConfiguration::default(),
|
||||
svlog_linter_configuration: DigitalLinterConfiguration::default(),
|
||||
log_level: LogLevel::Info,
|
||||
}
|
||||
}
|
||||
@ -148,11 +153,15 @@ impl LanguageServer for Backend {
|
||||
info!("extensionPath: {:?}", configure.extension_path);
|
||||
info!("toolChain: {:?}", configure.tool_chain);
|
||||
|
||||
// 初始化原语系统
|
||||
self.server.srcs.init_primitive(
|
||||
&configure.tool_chain,
|
||||
&configure.extension_path
|
||||
);
|
||||
|
||||
// 初始化诊断器
|
||||
|
||||
|
||||
let text_document_sync = TextDocumentSyncCapability::Options(
|
||||
TextDocumentSyncOptions {
|
||||
open_close: Some(true),
|
||||
|
@ -6,9 +6,9 @@ use crate::core::vhdl_parser::vhdl_parse_str;
|
||||
use crate::definition::def_types::*;
|
||||
use crate::definition::get_scopes_from_syntax_tree;
|
||||
use crate::definition::get_scopes_from_vhdl_fast;
|
||||
use crate::diagnostics::{provide_diagnostics, is_hidden};
|
||||
use crate::server::LSPServer;
|
||||
use crate::server::ProjectConfig;
|
||||
use crate::diagnostics::provide_diagnostics;
|
||||
use crate::server::LspServer;
|
||||
use crate::server::LspConfiguration;
|
||||
use crate::utils::to_escape_path;
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
@ -33,7 +33,7 @@ use thread::JoinHandle;
|
||||
use tower_lsp::lsp_types::*;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
impl LSPServer {
|
||||
impl LspServer {
|
||||
pub fn did_open(&self, params: DidOpenTextDocumentParams) -> PublishDiagnosticsParams {
|
||||
let document: TextDocumentItem = params.text_document;
|
||||
let uri = document.uri.clone();
|
||||
@ -216,28 +216,6 @@ pub struct SourceMeta {
|
||||
pub parse_handle: JoinHandle<()>,
|
||||
}
|
||||
|
||||
/// find SystemVerilog/Verilog sources recursively from opened files
|
||||
fn find_src_paths(dirs: &[PathBuf]) -> Vec<PathBuf> {
|
||||
let mut paths: Vec<PathBuf> = Vec::new();
|
||||
|
||||
for dir in dirs {
|
||||
let walker = WalkDir::new(dir).into_iter();
|
||||
for entry in walker.filter_entry(|e| !is_hidden(e)) {
|
||||
let entry = entry.unwrap();
|
||||
if entry.file_type().is_file() && entry.path().extension().is_some() {
|
||||
let extension = entry.path().extension().unwrap();
|
||||
|
||||
if extension == "sv" || extension == "svh" || extension == "v" || extension == "vh" {
|
||||
let entry_path = entry.path().to_path_buf();
|
||||
if !paths.contains(&entry_path) {
|
||||
paths.push(entry_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
paths
|
||||
}
|
||||
|
||||
/// The Sources struct manages all source files
|
||||
pub struct Sources {
|
||||
@ -302,7 +280,7 @@ impl Sources {
|
||||
}
|
||||
|
||||
/// 增加一个 hdl 文件,并为该文件添加单独的解析线程
|
||||
pub fn add(&self, server: &LSPServer, doc: TextDocumentItem) {
|
||||
pub fn add(&self, server: &LspServer, doc: TextDocumentItem) {
|
||||
// 对于当前的文件增加一个解析线程,不断进行解析和同步
|
||||
#[allow(clippy::mutex_atomic)] // https://github.com/rust-lang/rust-clippy/issues/1516
|
||||
let valid_parse = Arc::new((Mutex::new(false), Condvar::new()));
|
||||
@ -662,7 +640,7 @@ pub fn recovery_sv_parse(
|
||||
|
||||
pub fn sv_parser_pipeline(
|
||||
#[allow(unused)]
|
||||
conf: &Arc<RwLock<ProjectConfig>>,
|
||||
conf: &Arc<RwLock<LspConfiguration>>,
|
||||
source_handle: &Arc<RwLock<Source>>,
|
||||
scope_handle: &Arc<RwLock<Option<GenericScope>>>,
|
||||
hdl_param_handle: &Arc<HdlParam>,
|
||||
@ -744,7 +722,7 @@ pub fn sv_parser_pipeline(
|
||||
}
|
||||
|
||||
pub fn vhdl_parser_pipeline(
|
||||
conf: &Arc<RwLock<ProjectConfig>>,
|
||||
conf: &Arc<RwLock<LspConfiguration>>,
|
||||
source_handle: &Arc<RwLock<Source>>,
|
||||
scope_handle: &Arc<RwLock<Option<GenericScope>>>,
|
||||
project_handle: &Arc<RwLock<Option<VhdlProject>>>,
|
||||
|
@ -1,9 +1,9 @@
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
|
||||
use crate::{core::hdlparam::Define, server::LSPServer};
|
||||
use crate::{core::hdlparam::Define, server::LspServer};
|
||||
|
||||
impl LSPServer {
|
||||
impl LspServer {
|
||||
/// 根据输入的 macro 名字,寻找 fast 中存在的第一个 macro
|
||||
/// macro 可以以 ` 开头
|
||||
pub fn find_macros(&self, macro_name: &str) -> Option<(Define, String)> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user