完成 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::*;
|
use crate::utils::*;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
@ -7,7 +7,7 @@ use tower_lsp::lsp_types::*;
|
|||||||
mod sv;
|
mod sv;
|
||||||
mod vhdl;
|
mod vhdl;
|
||||||
|
|
||||||
impl LSPServer {
|
impl LspServer {
|
||||||
pub fn code_lens(&self, params: CodeLensParams) -> Option<Vec<CodeLens>> {
|
pub fn code_lens(&self, params: CodeLensParams) -> Option<Vec<CodeLens>> {
|
||||||
let language_id = get_language_id_by_uri(¶ms.text_document.uri);
|
let language_id = get_language_id_by_uri(¶ms.text_document.uri);
|
||||||
match language_id.as_str() {
|
match language_id.as_str() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::{path::PathBuf, str::FromStr};
|
use std::{path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
use crate::{core, server::LSPServer};
|
use crate::{core, server::LspServer};
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
@ -9,7 +9,7 @@ use super::to_escape_path;
|
|||||||
|
|
||||||
pub fn code_lens(
|
pub fn code_lens(
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
params: &CodeLensParams
|
params: &CodeLensParams
|
||||||
) -> Option<Vec<CodeLens>> {
|
) -> Option<Vec<CodeLens>> {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
|
|
||||||
use crate::server::LSPServer;
|
use crate::server::LspServer;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
pub fn code_lens(
|
pub fn code_lens(
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
params: &CodeLensParams
|
params: &CodeLensParams
|
||||||
) -> Option<Vec<CodeLens>> {
|
) -> Option<Vec<CodeLens>> {
|
||||||
|
@ -4,7 +4,7 @@ use log::info;
|
|||||||
use ropey::RopeSlice;
|
use ropey::RopeSlice;
|
||||||
use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind, CompletionItemLabelDetails, CompletionList, Position, Url};
|
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> {
|
pub fn include_path_completion(uri: &Url, line: &RopeSlice, pos: Position) -> Option<CompletionList> {
|
||||||
let line_text = line.as_str().unwrap_or("");
|
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(
|
pub fn get_dot_completion(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
line: &RopeSlice,
|
line: &RopeSlice,
|
||||||
url: &Url,
|
url: &Url,
|
||||||
pos: &Position,
|
pos: &Position,
|
||||||
@ -142,7 +142,7 @@ fn is_port_completion(line: &RopeSlice, pos: &Position) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_position_port_param_completion(
|
fn get_position_port_param_completion(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
line: &RopeSlice,
|
line: &RopeSlice,
|
||||||
url: &Url,
|
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::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
pub mod keyword;
|
pub mod keyword;
|
||||||
@ -10,7 +10,7 @@ pub use sys_tasks::provide_vlog_sys_tasks_completions;
|
|||||||
mod vhdl;
|
mod vhdl;
|
||||||
mod sv;
|
mod sv;
|
||||||
|
|
||||||
impl LSPServer {
|
impl LspServer {
|
||||||
pub fn completion(&self, params: CompletionParams) -> Option<CompletionResponse> {
|
pub fn completion(&self, params: CompletionParams) -> Option<CompletionResponse> {
|
||||||
let language_id = get_language_id_by_uri(¶ms.text_document_position.text_document.uri);
|
let language_id = get_language_id_by_uri(¶ms.text_document_position.text_document.uri);
|
||||||
match language_id.as_str() {
|
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 log::info;
|
||||||
use ropey::{Rope, RopeSlice};
|
use ropey::{Rope, RopeSlice};
|
||||||
use tower_lsp::lsp_types::*;
|
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 doc = ¶ms.text_document_position;
|
||||||
let uri = ¶ms.text_document_position.text_document.uri;
|
let uri = ¶ms.text_document_position.text_document.uri;
|
||||||
let pos = doc.position;
|
let pos = doc.position;
|
||||||
@ -305,7 +303,7 @@ fn make_instantiation_code(module: &crate::core::hdlparam::Module) -> String {
|
|||||||
|
|
||||||
/// 自动补全例化模块
|
/// 自动补全例化模块
|
||||||
fn make_module_completions(
|
fn make_module_completions(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
token: &str,
|
token: &str,
|
||||||
language_id: &str
|
language_id: &str
|
||||||
) -> Vec<CompletionItem> {
|
) -> Vec<CompletionItem> {
|
||||||
|
@ -6,13 +6,13 @@ use ropey::{Rope, RopeSlice};
|
|||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
use crate::{hover::feature::make_vhdl_module_profile_code, utils::{from_lsp_pos, to_escape_path}};
|
use crate::{hover::feature::make_vhdl_module_profile_code, utils::{from_lsp_pos, to_escape_path}};
|
||||||
#[allow(unused)]
|
#[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.
|
/// Called when the client requests a completion.
|
||||||
/// This function looks in the source code to find suitable options and then returns them
|
/// 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 doc = ¶ms.text_document_position;
|
||||||
let uri = ¶ms.text_document_position.text_document.uri;
|
let uri = ¶ms.text_document_position.text_document.uri;
|
||||||
let language_id = get_language_id_by_uri(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(
|
fn make_module_completions(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
token: &str,
|
token: &str,
|
||||||
language_id: &str
|
language_id: &str
|
||||||
) -> Vec<CompletionItem> {
|
) -> Vec<CompletionItem> {
|
||||||
|
@ -5,7 +5,7 @@ use regex::Regex;
|
|||||||
use ropey::RopeSlice;
|
use ropey::RopeSlice;
|
||||||
use tower_lsp::lsp_types::{GotoDefinitionResponse, LocationLink, Position, Range, Url};
|
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 的文件
|
/// 跳转到 include 的文件
|
||||||
pub fn goto_include_definition(uri: &Url, line: &RopeSlice, pos: Position) -> Option<GotoDefinitionResponse> {
|
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();
|
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 let Some((macro_text, range)) = get_word_range_at_position(line, pos, macro_text_regex) {
|
||||||
if macro_text.starts_with("`") {
|
if macro_text.starts_with("`") {
|
||||||
@ -103,7 +103,7 @@ pub fn goto_macro_definition(server: &LSPServer, line: &RopeSlice, pos: Position
|
|||||||
|
|
||||||
|
|
||||||
fn goto_instantiation<'a>(
|
fn goto_instantiation<'a>(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
fast: &'a FastHdlparam,
|
fast: &'a FastHdlparam,
|
||||||
token_name: &str,
|
token_name: &str,
|
||||||
pos: &Position,
|
pos: &Position,
|
||||||
@ -207,7 +207,7 @@ fn goto_instantiation<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn goto_position_port_param_definition(
|
pub fn goto_position_port_param_definition(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
line: &RopeSlice,
|
line: &RopeSlice,
|
||||||
url: &Url,
|
url: &Url,
|
||||||
pos: Position
|
pos: Position
|
||||||
@ -235,7 +235,7 @@ pub fn goto_position_port_param_definition(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn goto_module_declaration_definition(
|
pub fn goto_module_declaration_definition(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
token_name: &str
|
token_name: &str
|
||||||
) -> Option<GotoDefinitionResponse> {
|
) -> Option<GotoDefinitionResponse> {
|
||||||
let hdl_param = server.srcs.hdl_param.clone();
|
let hdl_param = server.srcs.hdl_param.clone();
|
||||||
@ -276,7 +276,7 @@ pub fn goto_module_declaration_definition(
|
|||||||
|
|
||||||
fn goto_common_module_declaration_definition(
|
fn goto_common_module_declaration_definition(
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
token_name: &str,
|
token_name: &str,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
@ -301,7 +301,7 @@ fn goto_common_module_declaration_definition(
|
|||||||
|
|
||||||
fn goto_ip_module_declaration_definition(
|
fn goto_ip_module_declaration_definition(
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
token_name: &str,
|
token_name: &str,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
@ -331,7 +331,7 @@ fn goto_ip_module_declaration_definition(
|
|||||||
|
|
||||||
fn goto_primitives_module_declaration_definition(
|
fn goto_primitives_module_declaration_definition(
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
token_name: &str,
|
token_name: &str,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::core::hdlparam::{self, FastHdlparam};
|
use crate::core::hdlparam::{self, FastHdlparam};
|
||||||
use crate::utils::get_language_id_by_uri;
|
use crate::utils::get_language_id_by_uri;
|
||||||
use crate::server::LSPServer;
|
use crate::server::LspServer;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
@ -19,7 +19,7 @@ pub use extract_defs::*;
|
|||||||
mod sv;
|
mod sv;
|
||||||
mod vhdl;
|
mod vhdl;
|
||||||
|
|
||||||
impl LSPServer {
|
impl LspServer {
|
||||||
pub fn goto_definition(&self, params: GotoDefinitionParams) -> Option<GotoDefinitionResponse> {
|
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);
|
let language_id = get_language_id_by_uri(¶ms.text_document_position_params.text_document.uri);
|
||||||
match language_id.as_str() {
|
match language_id.as_str() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::utils::get_definition_token;
|
use crate::utils::get_definition_token;
|
||||||
use crate::server::LSPServer;
|
use crate::server::LspServer;
|
||||||
use crate::sources::LSPSupport;
|
use crate::sources::LSPSupport;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
@ -8,7 +8,7 @@ use tower_lsp::lsp_types::*;
|
|||||||
|
|
||||||
use super::{feature::*, Definition, Scope};
|
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 doc = ¶ms.text_document_position_params.text_document.uri;
|
||||||
let pos = params.text_document_position_params.position;
|
let pos = params.text_document_position_params.position;
|
||||||
let file_id = server.srcs.get_id(doc).to_owned();
|
let file_id = server.srcs.get_id(doc).to_owned();
|
||||||
|
@ -3,11 +3,11 @@ use std::{path::PathBuf, str::FromStr};
|
|||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
use tower_lsp::lsp_types::*;
|
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};
|
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 doc = ¶ms.text_document_position_params.text_document.uri;
|
||||||
let pos = params.text_document_position_params.position;
|
let pos = params.text_document_position_params.position;
|
||||||
let file_id = server.srcs.get_id(doc).to_owned();
|
let file_id = server.srcs.get_id(doc).to_owned();
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use crate::server::ProjectConfig;
|
use std::fs::OpenOptions;
|
||||||
use regex::Regex;
|
|
||||||
|
use crate::{server::{LspConfiguration, LspServer}, utils::get_language_id_by_uri};
|
||||||
|
use log::info;
|
||||||
use ropey::Rope;
|
use ropey::Rope;
|
||||||
use std::path::PathBuf;
|
use serde::Deserialize;
|
||||||
use std::process::{Command, Stdio};
|
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
use walkdir::DirEntry;
|
|
||||||
|
|
||||||
pub mod verible;
|
pub mod verible;
|
||||||
pub mod verilator;
|
pub mod verilator;
|
||||||
@ -16,202 +16,148 @@ pub use verilator::*;
|
|||||||
pub use vivado::*;
|
pub use vivado::*;
|
||||||
pub use modelsim::*;
|
pub use modelsim::*;
|
||||||
|
|
||||||
|
/// description
|
||||||
|
/// 诊断功能需要提供两套函数,一套函数用于从给定路径读取文件并给出诊断结果;一套用于从 lsp 的文件缓冲区直接读取文本然后给出诊断结果。
|
||||||
|
/// 前者用于扫描整个项目使用,后者在用户实时修改代码时,给出实时的诊断信息。
|
||||||
|
|
||||||
/// 获取诊断核心函数
|
/// 获取诊断核心函数
|
||||||
pub fn provide_diagnostics(
|
pub fn provide_diagnostics(
|
||||||
uri: Url,
|
uri: Url,
|
||||||
rope: &Rope,
|
rope: &Rope,
|
||||||
#[allow(unused_variables)] files: Vec<Url>,
|
#[allow(unused_variables)]
|
||||||
configuration: &ProjectConfig,
|
files: Vec<Url>,
|
||||||
|
configuration: &LspConfiguration,
|
||||||
) -> PublishDiagnosticsParams {
|
) -> 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");
|
||||||
|
|
||||||
if !(cfg!(test) && (uri.to_string().starts_with("file:///test"))) {
|
} else if linter_configuration.vivado.linter.enabled {
|
||||||
let diagnostics = {
|
info!("vivado linter enter");
|
||||||
if configuration.verilator.syntax.enabled {
|
|
||||||
if let Ok(path) = uri.to_file_path() {
|
}
|
||||||
match verilator_syntax(
|
|
||||||
rope,
|
PublishDiagnosticsParams {
|
||||||
path,
|
uri, diagnostics,
|
||||||
&configuration.verilator.syntax.path,
|
version: None
|
||||||
&configuration.verilator.syntax.args,
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 根据输入的名字选择诊断器
|
||||||
|
/// - `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
|
||||||
) {
|
) {
|
||||||
Some(diags) => diags,
|
let mut configuration = server.configuration.write().unwrap();
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 选择对应语言的 lsp
|
||||||
pub fn is_hidden(entry: &DirEntry) -> bool {
|
let linter_configuration = match language_id {
|
||||||
entry
|
"vhdl" => Some(&mut configuration.vhdl_linter_configuration),
|
||||||
.file_name()
|
"verilog" => Some(&mut configuration.vlog_linter_configuration),
|
||||||
.to_str()
|
"systemverilog" => Some(&mut configuration.svlog_linter_configuration),
|
||||||
.map(|s| s.starts_with('.'))
|
_ => None
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// 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
|
if linter_configuration.is_none() {
|
||||||
// included files
|
info!("未知语言 {} 试图配置诊断器", language_id);
|
||||||
if caps.name("filepath")?.as_str() != file_path.to_str().unwrap_or("") {
|
return;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
let severity = verilator_severity(caps.name("severity")?.as_str());
|
|
||||||
let line: u32 = caps.name("line")?.as_str().to_string().parse().ok()?;
|
let linter_configuration = linter_configuration.unwrap();
|
||||||
let col: u32 = caps.name("col").map_or("1", |m| m.as_str()).parse().ok()?;
|
|
||||||
let pos = Position::new(line - 1, col - 1);
|
linter_configuration.verilator.linter.enabled = false;
|
||||||
let msg = match severity {
|
linter_configuration.verible.linter.enabled = false;
|
||||||
Some(DiagnosticSeverity::ERROR) => caps.name("message")?.as_str().to_string(),
|
linter_configuration.modelsim.linter.enabled = false;
|
||||||
Some(DiagnosticSeverity::WARNING) => format!(
|
linter_configuration.vivado.linter.enabled = false;
|
||||||
"{}: {}",
|
|
||||||
caps.name("warning_type")?.as_str(),
|
if linter_configuration.verilator.linter.name == linter_name {
|
||||||
caps.name("message")?.as_str()
|
linter_configuration.verilator.linter.enabled = true;
|
||||||
),
|
linter_configuration.verilator.linter.path = linter_path.to_string();
|
||||||
_ => "".to_string(),
|
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.verilator.linter.path);
|
||||||
};
|
|
||||||
diags.push(Diagnostic::new(
|
} else if linter_configuration.verible.linter.name == linter_name {
|
||||||
Range::new(pos, pos),
|
linter_configuration.verible.linter.enabled = true;
|
||||||
severity,
|
linter_configuration.verible.linter.path = linter_path.to_string();
|
||||||
None,
|
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.verible.linter.path);
|
||||||
Some("verilator".to_string()),
|
|
||||||
msg,
|
} else if linter_configuration.modelsim.linter.name == linter_name {
|
||||||
None,
|
linter_configuration.modelsim.linter.enabled = true;
|
||||||
None,
|
linter_configuration.modelsim.linter.path = linter_path.to_string();
|
||||||
));
|
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.modelsim.linter.path);
|
||||||
}
|
|
||||||
Some(diags)
|
} else if linter_configuration.vivado.linter.name == linter_name {
|
||||||
} else {
|
linter_configuration.vivado.linter.enabled = true;
|
||||||
None
|
linter_configuration.vivado.linter.path = linter_path.to_string();
|
||||||
|
info!("{} 诊断器 {} 已经激活, 工作负载为 {}", language_id, linter_name, linter_configuration.vivado.linter.path);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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();
|
#[derive(Debug, Deserialize)]
|
||||||
let re = RE.get_or_init(|| {
|
#[derive(serde::Serialize)]
|
||||||
Regex::new(
|
pub enum DigitalLinterMode {
|
||||||
r"^.+:(?P<line>\d*):(?P<startcol>\d*)(?:-(?P<endcol>\d*))?:\s(?P<message>.*)\s.*$",
|
/// 全局诊断,将所有设计源直接进行诊断,并报错,无论文件是否打开
|
||||||
)
|
FULL,
|
||||||
.unwrap()
|
/// 单文件关闭时,对应报错去除,打开哪个文件就对哪个文件进行诊断
|
||||||
});
|
SINGLE,
|
||||||
// write file to stdin, read output from stdout
|
/// 全局关闭,即整个工程都不进行工程报错
|
||||||
rope.write_to(child.stdin.as_mut()?).ok()?;
|
NONE
|
||||||
let output = child.wait_with_output().ok()?;
|
}
|
||||||
if !output.status.success() {
|
|
||||||
let mut diags: Vec<Diagnostic> = Vec::new();
|
#[derive(Debug, Deserialize)]
|
||||||
let raw_output = String::from_utf8(output.stdout).ok()?;
|
#[derive(serde::Serialize)]
|
||||||
for error in raw_output.lines() {
|
pub struct DigitalLinterConfiguration {
|
||||||
let caps = re.captures(error)?;
|
// verible 相关的工具配置
|
||||||
let line: u32 = caps.name("line")?.as_str().parse().ok()?;
|
pub verible: VeribleConfiguration,
|
||||||
let startcol: u32 = caps.name("startcol")?.as_str().parse().ok()?;
|
// verilator 相关的工具配置
|
||||||
let endcol: Option<u32> = match caps.name("endcol").map(|e| e.as_str().parse()) {
|
pub verilator: VerilatorConfiguration,
|
||||||
Some(Ok(e)) => Some(e),
|
// modelsim 相关的工具配置
|
||||||
None => None,
|
pub modelsim: ModelsimConfiguration,
|
||||||
Some(Err(_)) => return None,
|
// vivado 相关的工具配置
|
||||||
};
|
pub vivado: VivadoConfiguration
|
||||||
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(
|
impl Default for DigitalLinterConfiguration {
|
||||||
Range::new(start_pos, end_pos),
|
fn default() -> Self {
|
||||||
Some(DiagnosticSeverity::ERROR),
|
DigitalLinterConfiguration {
|
||||||
None,
|
verible: VeribleConfiguration::default(),
|
||||||
Some("verible".to_string()),
|
verilator: VerilatorConfiguration::default(),
|
||||||
caps.name("message")?.as_str().to_string(),
|
modelsim: ModelsimConfiguration::default(),
|
||||||
None,
|
vivado: VivadoConfiguration::default()
|
||||||
None,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Some(diags)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,53 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
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() {
|
pub fn provide_diagnostics() {
|
||||||
|
|
||||||
}
|
}
|
@ -1,15 +1,22 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
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)]
|
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct VeribleConfiguration {
|
pub struct VeribleConfiguration {
|
||||||
pub syntax: VeribleSyntax,
|
pub linter: VeribleLinter,
|
||||||
pub format: VeribleFormat,
|
pub format: VeribleFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct VeribleSyntax {
|
pub struct VeribleLinter {
|
||||||
|
pub name: String,
|
||||||
|
/// 目前是否启动
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub args: Vec<String>,
|
pub args: Vec<String>,
|
||||||
@ -23,9 +30,10 @@ pub struct VeribleFormat {
|
|||||||
pub args: Vec<String>,
|
pub args: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for VeribleSyntax {
|
impl Default for VeribleLinter {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
name: "verible".to_string(),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
path: "verible-verilog-syntax".to_string(),
|
path: "verible-verilog-syntax".to_string(),
|
||||||
args: Vec::new(),
|
args: Vec::new(),
|
||||||
@ -47,3 +55,60 @@ impl Default for VeribleFormat {
|
|||||||
pub fn provide_diagnostics() {
|
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 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)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct VerilatorConfiguration {
|
pub struct VerilatorConfiguration {
|
||||||
pub syntax: VerilatorSyntax,
|
pub linter: VerilatorLinter,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct VerilatorSyntax {
|
pub struct VerilatorLinter {
|
||||||
|
pub name: String,
|
||||||
|
/// 目前是否启动
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub args: Vec<String>,
|
pub args: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for VerilatorSyntax {
|
impl Default for VerilatorLinter {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
name: "verilator".to_string(),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
path: "verilator".to_string(),
|
path: "verilator".to_string(),
|
||||||
args: vec![
|
args: vec![
|
||||||
@ -31,3 +39,87 @@ impl Default for VerilatorSyntax {
|
|||||||
pub fn provide_diagnostics() {
|
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)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct VivadoConfiguration {
|
pub struct VivadoConfiguration {
|
||||||
pub syntax: VivadoSyntax,
|
pub linter: VivadoLinter,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct VivadoSyntax {
|
pub struct VivadoLinter {
|
||||||
|
pub name: String,
|
||||||
|
/// 目前是否启动
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub args: Vec<String>,
|
pub args: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for VivadoSyntax {
|
impl Default for VivadoLinter {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
name: "vivado".to_string(),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
path: "Vivado".to_string(),
|
path: "Vivado".to_string(),
|
||||||
args: vec![
|
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::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
mod sv;
|
mod sv;
|
||||||
mod vhdl;
|
mod vhdl;
|
||||||
|
|
||||||
impl LSPServer {
|
impl LspServer {
|
||||||
pub fn document_highlight(
|
pub fn document_highlight(
|
||||||
&self,
|
&self,
|
||||||
params: DocumentHighlightParams,
|
params: DocumentHighlightParams,
|
||||||
|
@ -3,10 +3,10 @@ use log::info;
|
|||||||
use sv_parser::{RefNode, SyntaxTree};
|
use sv_parser::{RefNode, SyntaxTree};
|
||||||
use tower_lsp::lsp_types::*;
|
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(
|
pub fn document_highlight(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
token: &str,
|
token: &str,
|
||||||
file: &Source,
|
file: &Source,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
|
@ -2,10 +2,10 @@ use log::info;
|
|||||||
use sv_parser::{RefNode, SyntaxTree};
|
use sv_parser::{RefNode, SyntaxTree};
|
||||||
use tower_lsp::lsp_types::*;
|
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(
|
pub fn document_highlight(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
token: &str,
|
token: &str,
|
||||||
file: &Source,
|
file: &Source,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use tower_lsp::lsp_types::*;
|
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 sv;
|
||||||
mod vhdl;
|
mod vhdl;
|
||||||
|
|
||||||
impl LSPServer {
|
impl LspServer {
|
||||||
pub fn document_symbol(&self, params: DocumentSymbolParams) -> Option<DocumentSymbolResponse> {
|
pub fn document_symbol(&self, params: DocumentSymbolParams) -> Option<DocumentSymbolResponse> {
|
||||||
let uri = ¶ms.text_document.uri;
|
let uri = ¶ms.text_document.uri;
|
||||||
let language_id = get_language_id_by_uri(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::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
pub fn document_symbol(
|
pub fn document_symbol(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
params: &DocumentSymbolParams
|
params: &DocumentSymbolParams
|
||||||
) -> Option<DocumentSymbolResponse> {
|
) -> Option<DocumentSymbolResponse> {
|
||||||
let uri = ¶ms.text_document.uri;
|
let uri = ¶ms.text_document.uri;
|
||||||
|
@ -4,9 +4,9 @@ use std::{path::PathBuf, str::FromStr};
|
|||||||
use log::info;
|
use log::info;
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
use vhdl_lang::{EntHierarchy, Token};
|
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");
|
// info!("enter document symbol");
|
||||||
|
|
||||||
let uri = ¶ms.text_document.uri;
|
let uri = ¶ms.text_document.uri;
|
||||||
|
@ -1,60 +1,62 @@
|
|||||||
use crate::server::LSPServer;
|
use crate::server::LspServer;
|
||||||
use crate::sources::LSPSupport;
|
use crate::sources::LSPSupport;
|
||||||
use log::info;
|
use log::info;
|
||||||
use ropey::Rope;
|
use ropey::Rope;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
impl LSPServer {
|
impl LspServer {
|
||||||
pub fn formatting(&self, params: DocumentFormattingParams) -> Option<Vec<TextEdit>> {
|
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()?;
|
|
||||||
|
|
||||||
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
|
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
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn range_formatting(&self, params: DocumentRangeFormattingParams) -> Option<Vec<TextEdit>> {
|
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()?;
|
|
||||||
|
|
||||||
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
|
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
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use regex::Regex;
|
|||||||
use ropey::RopeSlice;
|
use ropey::RopeSlice;
|
||||||
use tower_lsp::lsp_types::{Hover, HoverContents, LanguageString, MarkedString, Position, Range, Url};
|
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};
|
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();
|
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 let Some((macro_text, range)) = get_word_range_at_position(line, pos, macro_text_regex) {
|
||||||
if macro_text.starts_with("`") {
|
if macro_text.starts_with("`") {
|
||||||
@ -222,7 +222,7 @@ pub fn hover_macro(server: &LSPServer, line: &RopeSlice, pos: Position, language
|
|||||||
|
|
||||||
|
|
||||||
fn goto_instantiation<'a>(
|
fn goto_instantiation<'a>(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
fast: &'a FastHdlparam,
|
fast: &'a FastHdlparam,
|
||||||
token_name: &str,
|
token_name: &str,
|
||||||
pos: &Position,
|
pos: &Position,
|
||||||
@ -313,7 +313,7 @@ fn goto_instantiation<'a>(
|
|||||||
/// 计算 position 赋值的 port 或者 param
|
/// 计算 position 赋值的 port 或者 param
|
||||||
/// 比如 .clk ( clk ) 中的 .clk
|
/// 比如 .clk ( clk ) 中的 .clk
|
||||||
pub fn hover_position_port_param(
|
pub fn hover_position_port_param(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
line: &RopeSlice,
|
line: &RopeSlice,
|
||||||
url: &Url,
|
url: &Url,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
@ -441,7 +441,7 @@ fn make_param_desc_hover(file_type: &str, param: &crate::core::hdlparam::Paramet
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn hover_module_declaration(
|
pub fn hover_module_declaration(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
token_name: &str,
|
token_name: &str,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
language_id: &str
|
language_id: &str
|
||||||
@ -486,7 +486,7 @@ pub fn hover_module_declaration(
|
|||||||
|
|
||||||
fn hover_common_module_declaration(
|
fn hover_common_module_declaration(
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
token_name: &str,
|
token_name: &str,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
@ -545,7 +545,7 @@ fn hover_common_module_declaration(
|
|||||||
|
|
||||||
fn hover_ip_module_declaration(
|
fn hover_ip_module_declaration(
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
token_name: &str,
|
token_name: &str,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
@ -613,7 +613,7 @@ fn hover_ip_module_declaration(
|
|||||||
|
|
||||||
fn hover_primitives_module_declaration(
|
fn hover_primitives_module_declaration(
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
token_name: &str,
|
token_name: &str,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::server::LSPServer;
|
use crate::server::LspServer;
|
||||||
use crate::utils::*;
|
use crate::utils::*;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
@ -9,7 +9,7 @@ pub mod feature;
|
|||||||
mod sv;
|
mod sv;
|
||||||
mod vhdl;
|
mod vhdl;
|
||||||
|
|
||||||
impl LSPServer {
|
impl LspServer {
|
||||||
pub fn hover(&self, params: HoverParams) -> Option<Hover> {
|
pub fn hover(&self, params: HoverParams) -> Option<Hover> {
|
||||||
let language_id = get_language_id_by_uri(¶ms.text_document_position_params.text_document.uri);
|
let language_id = get_language_id_by_uri(¶ms.text_document_position_params.text_document.uri);
|
||||||
match language_id.as_str() {
|
match language_id.as_str() {
|
||||||
|
@ -3,7 +3,7 @@ use log::info;
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use ropey::Rope;
|
use ropey::Rope;
|
||||||
use tower_lsp::lsp_types::*;
|
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 super::feature::*;
|
||||||
use std::{path::PathBuf, str::FromStr, sync::RwLockReadGuard};
|
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};
|
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 doc = ¶ms.text_document_position_params.text_document.uri;
|
||||||
let pos: Position = params.text_document_position_params.position;
|
let pos: Position = params.text_document_position_params.position;
|
||||||
let file_id: usize = server.srcs.get_id(doc).to_owned();
|
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
|
/// 计算正常 symbol 的 hover
|
||||||
fn hover_common_symbol(
|
fn hover_common_symbol(
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
token: &String,
|
token: &String,
|
||||||
symbol_definition: &GenericDec,
|
symbol_definition: &GenericDec,
|
||||||
@ -294,7 +294,7 @@ fn hover_common_symbol(
|
|||||||
make_hover_with_comment(&file.text, def_line, &language_id, false)
|
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 = PathBuf::from_str(doc.path()).unwrap();
|
||||||
let pathbuf = to_escape_path(&pathbuf);
|
let pathbuf = to_escape_path(&pathbuf);
|
||||||
let path_string = pathbuf.to_str().unwrap().replace("\\", "/");
|
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) {
|
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
|
true
|
||||||
} else if let Some(_) = hdlparam.walk_instantiation(&path_string, find_instance_range) {
|
} 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
|
true
|
||||||
} else {
|
} else {
|
||||||
// info!("[LSPServer] in hover: it is not instance");
|
// info!("[LspServer] in hover: it is not instance");
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,11 @@ use log::info;
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use ropey::Rope;
|
use ropey::Rope;
|
||||||
use tower_lsp::lsp_types::*;
|
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};
|
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 doc = ¶ms.text_document_position_params.text_document.uri;
|
||||||
let pos: Position = params.text_document_position_params.position;
|
let pos: Position = params.text_document_position_params.position;
|
||||||
let file_id: usize = server.srcs.get_id(doc).to_owned();
|
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(
|
fn hover_common_symbol(
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
token: &String,
|
token: &String,
|
||||||
symbol_definition: &GenericDec,
|
symbol_definition: &GenericDec,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::server::LSPServer;
|
use crate::server::LspServer;
|
||||||
use crate::utils::*;
|
use crate::utils::*;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
@ -7,7 +7,7 @@ use tower_lsp::lsp_types::*;
|
|||||||
mod sv;
|
mod sv;
|
||||||
mod vhdl;
|
mod vhdl;
|
||||||
|
|
||||||
impl LSPServer {
|
impl LspServer {
|
||||||
pub fn inlay_hint(&self, params: InlayHintParams) -> Option<Vec<InlayHint>> {
|
pub fn inlay_hint(&self, params: InlayHintParams) -> Option<Vec<InlayHint>> {
|
||||||
let language_id = get_language_id_by_uri(¶ms.text_document.uri);
|
let language_id = get_language_id_by_uri(¶ms.text_document.uri);
|
||||||
match language_id.as_str() {
|
match language_id.as_str() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::{collections::HashMap, path::PathBuf, str::FromStr};
|
use std::{collections::HashMap, path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
use crate::{core, server::LSPServer};
|
use crate::{core, server::LspServer};
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
use ropey::Rope;
|
use ropey::Rope;
|
||||||
@ -8,7 +8,7 @@ use tower_lsp::lsp_types::*;
|
|||||||
|
|
||||||
use super::{get_language_id_by_path_str, to_escape_path};
|
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 uri = ¶ms.text_document.uri;
|
||||||
let path = PathBuf::from_str(uri.path()).unwrap();
|
let path = PathBuf::from_str(uri.path()).unwrap();
|
||||||
let path = to_escape_path(&path);
|
let path = to_escape_path(&path);
|
||||||
@ -58,7 +58,7 @@ fn is_visible_range(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn make_instparam_hints(
|
fn make_instparam_hints(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
params: &InlayHintParams,
|
params: &InlayHintParams,
|
||||||
instance: &core::hdlparam::Instance,
|
instance: &core::hdlparam::Instance,
|
||||||
rope: &Rope
|
rope: &Rope
|
||||||
@ -106,7 +106,7 @@ fn find_instport_inlay_hints_position(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn make_instport_hints(
|
fn make_instport_hints(
|
||||||
server: &LSPServer,
|
server: &LspServer,
|
||||||
params: &InlayHintParams,
|
params: &InlayHintParams,
|
||||||
instance: &core::hdlparam::Instance,
|
instance: &core::hdlparam::Instance,
|
||||||
rope: &Rope
|
rope: &Rope
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::server::LSPServer;
|
use crate::server::LspServer;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
use tower_lsp::lsp_types::*;
|
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
|
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 serde_json::Value;
|
||||||
use tower_lsp::jsonrpc::Result;
|
use tower_lsp::jsonrpc::Result;
|
||||||
|
|
||||||
use crate::server::Backend;
|
use crate::{diagnostics::update_diagnostics_configuration, server::Backend};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct UpdateConfigurationApi;
|
pub struct UpdateConfigurationApi;
|
||||||
@ -33,21 +33,75 @@ impl <'a>tower_lsp::jsonrpc::Method<&'a Arc<Backend>, (UpdateConfigurationParams
|
|||||||
let configs = request_param.configs;
|
let configs = request_param.configs;
|
||||||
|
|
||||||
// 用于未来进行配置分区
|
// 用于未来进行配置分区
|
||||||
#[allow(unused)]
|
|
||||||
let config_type = request_param.config_type;
|
let config_type = request_param.config_type;
|
||||||
|
|
||||||
update_configuration(configs, &_server);
|
update_configuration(configs, config_type, &_server);
|
||||||
future::ready(Ok(()))
|
future::ready(Ok(()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 前端配置文件的更新
|
||||||
fn update_configuration(
|
fn update_configuration(
|
||||||
configs: Vec<UpdateConfigurationItem>,
|
configs: Vec<UpdateConfigurationItem>,
|
||||||
|
config_type: String,
|
||||||
backend: &Arc<Backend>
|
backend: &Arc<Backend>
|
||||||
) {
|
) {
|
||||||
let mut lsp_configuration = backend.server.srcs.lsp_configuration.write().unwrap();
|
let mut lsp_configuration = backend.server.srcs.lsp_configuration.write().unwrap();
|
||||||
|
|
||||||
|
match config_type.as_str() {
|
||||||
|
// 所有配置同步到 lsp_configuration 中
|
||||||
|
"lsp" => {
|
||||||
for config in configs {
|
for config in configs {
|
||||||
info!("name: {}, value: {}", config.name, config.value);
|
info!("update config, name: {}, value: {}", config.name, config.value);
|
||||||
lsp_configuration.insert(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::core::cache_storage::CacheManager;
|
||||||
use crate::diagnostics::{VeribleConfiguration, VerilatorConfiguration};
|
use crate::diagnostics::{DigitalLinterConfiguration, DigitalLinterMode, ModelsimConfiguration, VeribleConfiguration, VerilatorConfiguration, VivadoConfiguration};
|
||||||
use crate::sources::*;
|
use crate::sources::*;
|
||||||
use crate::completion::{keyword::*, provide_vlog_sys_tasks_completions};
|
use crate::completion::{keyword::*, provide_vlog_sys_tasks_completions};
|
||||||
use flexi_logger::LoggerHandle;
|
use flexi_logger::LoggerHandle;
|
||||||
@ -11,7 +11,7 @@ use std::sync::{Arc, Mutex, RwLock};
|
|||||||
use tower_lsp::jsonrpc::Result;
|
use tower_lsp::jsonrpc::Result;
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
use tower_lsp::{Client, LanguageServer};
|
use tower_lsp::{Client, LanguageServer};
|
||||||
pub struct LSPServer {
|
pub struct LspServer {
|
||||||
/// 文件和 ast 相关的
|
/// 文件和 ast 相关的
|
||||||
pub srcs: Sources,
|
pub srcs: Sources,
|
||||||
/// 缓存
|
/// 缓存
|
||||||
@ -25,23 +25,24 @@ pub struct LSPServer {
|
|||||||
/// vhdl 关键词的自动补全
|
/// vhdl 关键词的自动补全
|
||||||
pub vhdl_keyword_completiom_items: Vec<CompletionItem>,
|
pub vhdl_keyword_completiom_items: Vec<CompletionItem>,
|
||||||
/// 相关的配置项目
|
/// 相关的配置项目
|
||||||
pub configuration: Arc<RwLock<ProjectConfig>>,
|
pub configuration: Arc<RwLock<LspConfiguration>>,
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub log_handle: Mutex<Option<LoggerHandle>>,
|
pub log_handle: Mutex<Option<LoggerHandle>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LSPServer {
|
impl LspServer {
|
||||||
pub fn new(log_handle: Option<LoggerHandle>) -> LSPServer {
|
pub fn new(log_handle: Option<LoggerHandle>) -> LspServer {
|
||||||
let user_home = dirs_next::home_dir().unwrap();
|
let user_home = dirs_next::home_dir().unwrap();
|
||||||
let dide_home = user_home.join(".digital-ide");
|
let dide_home = user_home.join(".digital-ide");
|
||||||
LSPServer {
|
LspServer {
|
||||||
srcs: Sources::new(),
|
srcs: Sources::new(),
|
||||||
cache: CacheManager::new(dide_home),
|
cache: CacheManager::new(dide_home),
|
||||||
vlog_keyword_completion_items: keyword_completions(VLOG_KEYWORDS),
|
vlog_keyword_completion_items: keyword_completions(VLOG_KEYWORDS),
|
||||||
vhdl_keyword_completiom_items: keyword_completions(VHDL_KEYWORDS),
|
vhdl_keyword_completiom_items: keyword_completions(VHDL_KEYWORDS),
|
||||||
vlog_sys_tasks_completion_items: provide_vlog_sys_tasks_completions(),
|
vlog_sys_tasks_completion_items: provide_vlog_sys_tasks_completions(),
|
||||||
vlog_directives: other_completions(DIRECTIVES),
|
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),
|
log_handle: Mutex::new(log_handle),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,7 +50,7 @@ impl LSPServer {
|
|||||||
|
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
pub client: Client,
|
pub client: Client,
|
||||||
pub server: LSPServer
|
pub server: LspServer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -57,7 +58,7 @@ impl Backend {
|
|||||||
pub fn new(client: Client, log_handle: LoggerHandle) -> Backend {
|
pub fn new(client: Client, log_handle: LoggerHandle) -> Backend {
|
||||||
Backend {
|
Backend {
|
||||||
client,
|
client,
|
||||||
server: LSPServer::new(Some(log_handle)),
|
server: LspServer::new(Some(log_handle)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,7 +79,7 @@ pub enum LogLevel {
|
|||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct ProjectConfig {
|
pub struct LspConfiguration {
|
||||||
// 用户工作目录的路径
|
// 用户工作目录的路径
|
||||||
pub workspace_folder: Option<Url>,
|
pub workspace_folder: Option<Url>,
|
||||||
// 插件安装的根路径
|
// 插件安装的根路径
|
||||||
@ -93,29 +94,33 @@ pub struct ProjectConfig {
|
|||||||
// list of directories to recursively search for SystemVerilog/Verilog sources
|
// list of directories to recursively search for SystemVerilog/Verilog sources
|
||||||
pub source_dirs: Vec<String>,
|
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
|
// log level
|
||||||
pub log_level: LogLevel
|
pub log_level: LogLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ProjectConfig {
|
impl Default for LspConfiguration {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
ProjectConfig {
|
LspConfiguration {
|
||||||
workspace_folder: None,
|
workspace_folder: None,
|
||||||
extension_path: "".to_string(),
|
extension_path: "".to_string(),
|
||||||
tool_chain: "xilinx".to_string(),
|
tool_chain: "xilinx".to_string(),
|
||||||
auto_search_workdir: true,
|
auto_search_workdir: true,
|
||||||
include_dirs: Vec::new(),
|
include_dirs: Vec::new(),
|
||||||
source_dirs: Vec::new(),
|
source_dirs: Vec::new(),
|
||||||
verible: VeribleConfiguration::default(),
|
linter_mode: DigitalLinterMode::FULL,
|
||||||
verilator: VerilatorConfiguration::default(),
|
vlog_linter_configuration: DigitalLinterConfiguration::default(),
|
||||||
|
vhdl_linter_configuration: DigitalLinterConfiguration::default(),
|
||||||
|
svlog_linter_configuration: DigitalLinterConfiguration::default(),
|
||||||
log_level: LogLevel::Info,
|
log_level: LogLevel::Info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,11 +153,15 @@ impl LanguageServer for Backend {
|
|||||||
info!("extensionPath: {:?}", configure.extension_path);
|
info!("extensionPath: {:?}", configure.extension_path);
|
||||||
info!("toolChain: {:?}", configure.tool_chain);
|
info!("toolChain: {:?}", configure.tool_chain);
|
||||||
|
|
||||||
|
// 初始化原语系统
|
||||||
self.server.srcs.init_primitive(
|
self.server.srcs.init_primitive(
|
||||||
&configure.tool_chain,
|
&configure.tool_chain,
|
||||||
&configure.extension_path
|
&configure.extension_path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 初始化诊断器
|
||||||
|
|
||||||
|
|
||||||
let text_document_sync = TextDocumentSyncCapability::Options(
|
let text_document_sync = TextDocumentSyncCapability::Options(
|
||||||
TextDocumentSyncOptions {
|
TextDocumentSyncOptions {
|
||||||
open_close: Some(true),
|
open_close: Some(true),
|
||||||
|
@ -6,9 +6,9 @@ use crate::core::vhdl_parser::vhdl_parse_str;
|
|||||||
use crate::definition::def_types::*;
|
use crate::definition::def_types::*;
|
||||||
use crate::definition::get_scopes_from_syntax_tree;
|
use crate::definition::get_scopes_from_syntax_tree;
|
||||||
use crate::definition::get_scopes_from_vhdl_fast;
|
use crate::definition::get_scopes_from_vhdl_fast;
|
||||||
use crate::diagnostics::{provide_diagnostics, is_hidden};
|
use crate::diagnostics::provide_diagnostics;
|
||||||
use crate::server::LSPServer;
|
use crate::server::LspServer;
|
||||||
use crate::server::ProjectConfig;
|
use crate::server::LspConfiguration;
|
||||||
use crate::utils::to_escape_path;
|
use crate::utils::to_escape_path;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
@ -33,7 +33,7 @@ use thread::JoinHandle;
|
|||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
impl LSPServer {
|
impl LspServer {
|
||||||
pub fn did_open(&self, params: DidOpenTextDocumentParams) -> PublishDiagnosticsParams {
|
pub fn did_open(&self, params: DidOpenTextDocumentParams) -> PublishDiagnosticsParams {
|
||||||
let document: TextDocumentItem = params.text_document;
|
let document: TextDocumentItem = params.text_document;
|
||||||
let uri = document.uri.clone();
|
let uri = document.uri.clone();
|
||||||
@ -216,28 +216,6 @@ pub struct SourceMeta {
|
|||||||
pub parse_handle: JoinHandle<()>,
|
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
|
/// The Sources struct manages all source files
|
||||||
pub struct Sources {
|
pub struct Sources {
|
||||||
@ -302,7 +280,7 @@ impl Sources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 增加一个 hdl 文件,并为该文件添加单独的解析线程
|
/// 增加一个 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
|
#[allow(clippy::mutex_atomic)] // https://github.com/rust-lang/rust-clippy/issues/1516
|
||||||
let valid_parse = Arc::new((Mutex::new(false), Condvar::new()));
|
let valid_parse = Arc::new((Mutex::new(false), Condvar::new()));
|
||||||
@ -662,7 +640,7 @@ pub fn recovery_sv_parse(
|
|||||||
|
|
||||||
pub fn sv_parser_pipeline(
|
pub fn sv_parser_pipeline(
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
conf: &Arc<RwLock<ProjectConfig>>,
|
conf: &Arc<RwLock<LspConfiguration>>,
|
||||||
source_handle: &Arc<RwLock<Source>>,
|
source_handle: &Arc<RwLock<Source>>,
|
||||||
scope_handle: &Arc<RwLock<Option<GenericScope>>>,
|
scope_handle: &Arc<RwLock<Option<GenericScope>>>,
|
||||||
hdl_param_handle: &Arc<HdlParam>,
|
hdl_param_handle: &Arc<HdlParam>,
|
||||||
@ -744,7 +722,7 @@ pub fn sv_parser_pipeline(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn vhdl_parser_pipeline(
|
pub fn vhdl_parser_pipeline(
|
||||||
conf: &Arc<RwLock<ProjectConfig>>,
|
conf: &Arc<RwLock<LspConfiguration>>,
|
||||||
source_handle: &Arc<RwLock<Source>>,
|
source_handle: &Arc<RwLock<Source>>,
|
||||||
scope_handle: &Arc<RwLock<Option<GenericScope>>>,
|
scope_handle: &Arc<RwLock<Option<GenericScope>>>,
|
||||||
project_handle: &Arc<RwLock<Option<VhdlProject>>>,
|
project_handle: &Arc<RwLock<Option<VhdlProject>>>,
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
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 名字,寻找 fast 中存在的第一个 macro
|
||||||
/// macro 可以以 ` 开头
|
/// macro 可以以 ` 开头
|
||||||
pub fn find_macros(&self, macro_name: &str) -> Option<(Define, String)> {
|
pub fn find_macros(&self, macro_name: &str) -> Option<(Define, String)> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user