剥离 scope tree 逻辑到 core 模块中

This commit is contained in:
锦恢 2024-12-12 18:18:06 +08:00
parent 36ba7a350d
commit 7875a631a8
21 changed files with 365 additions and 267 deletions

View File

@ -7,3 +7,5 @@ pub mod vhdl_parser;
pub mod cache_storage;
pub mod primitive_parser;
pub mod scope_tree;

View File

@ -1,5 +1,3 @@
use std::ffi::OsStr;
#[allow(unused)]
use log::info;
use ropey::Rope;
@ -117,23 +115,24 @@ pub trait Scope: std::fmt::Debug + Definition + Sync + Send {
// first we need to go down the scope tree, to the scope the user is invoking a completion
// in
for scope in self.scopes() {
// 如果当前的 token 在这个 scope 中,那么需要递归获取这个 scope 中的所有补全项目
if &scope.url() == url && scope.start() <= byte_idx && byte_idx <= scope.end() {
completions = scope.get_completion(token, byte_idx, url);
break;
}
}
// 自动补全时,忽略大小写
let lower_case_token = token.to_lowercase();
// now that we are in the users scope, we can attempt to find a relevant completion
// we proceed back upwards through the scope tree, adding any definitions that match
// the users token
let completion_idents: Vec<String> = completions.iter().map(|x| x.label.clone()).collect();
for def in self.defs() {
// 寻找前缀相同的 symbol
for def in self.defs() {
if !completion_idents.contains(&def.ident()) && def.ident().to_lowercase().starts_with(&lower_case_token) {
completions.push(def.completion());
}
}
// 寻找前缀相同的 scope
for scope in self.scopes() {
if scope.starts_with(token) {
completions.push(scope.completion());
@ -155,7 +154,6 @@ pub trait Scope: std::fmt::Debug + Definition + Sync + Send {
// in
for scope in self.scopes() {
if &scope.url() == url && scope.start() <= byte_idx && byte_idx <= scope.end() {
eprintln!("checking dot completion: {}", scope.ident());
let result = scope.get_dot_completion(token, byte_idx, url, scope_tree);
if !result.is_empty() {
return result;

226
src/core/scope_tree/mod.rs Normal file
View File

@ -0,0 +1,226 @@
use crate::core::hdlparam::{self, FastHdlparam};
use ropey::Rope;
use sv_parser::*;
use tower_lsp::lsp_types::*;
// 定义有关 scope 相关的基础类的
pub mod common;
// 定义如何把 ast 转变为类似于 common 中的数据结构
pub mod parse;
use common::*;
use parse::*;
type ScopesAndDefs = Option<(Vec<Box<dyn Scope>>, Vec<Box<dyn Definition>>)>;
/// Take a given syntax node from a sv-parser syntax tree and extract out the definition/scope at
/// that point.
pub fn match_definitions(
syntax_tree: &SyntaxTree,
event_iter: &mut EventIter,
node: RefNode,
url: &Url,
) -> ScopesAndDefs {
let mut definitions: Vec<Box<dyn Definition>> = Vec::new();
let mut scopes: Vec<Box<dyn Scope>> = Vec::new();
match node {
RefNode::ModuleDeclaration(n) => {
let module = module_dec(syntax_tree, n, event_iter, url);
if module.is_some() {
scopes.push(Box::new(module?));
}
}
RefNode::InterfaceDeclaration(n) => {
let interface = interface_dec(syntax_tree, n, event_iter, url);
if interface.is_some() {
scopes.push(Box::new(interface?));
}
}
RefNode::UdpDeclaration(n) => {
let dec = udp_dec(syntax_tree, n, event_iter, url);
if dec.is_some() {
scopes.push(Box::new(dec?));
}
}
RefNode::ProgramDeclaration(n) => {
let dec = program_dec(syntax_tree, n, event_iter, url);
if dec.is_some() {
scopes.push(Box::new(dec?));
}
}
RefNode::PackageDeclaration(n) => {
let dec = package_dec(syntax_tree, n, event_iter, url);
if dec.is_some() {
scopes.push(Box::new(dec?));
}
}
RefNode::ConfigDeclaration(n) => {
let dec = config_dec(syntax_tree, n, event_iter, url);
if dec.is_some() {
scopes.push(Box::new(dec?));
}
}
RefNode::ClassDeclaration(n) => {
let dec = class_dec(syntax_tree, n, event_iter, url);
if dec.is_some() {
scopes.push(Box::new(dec?));
}
}
RefNode::PortDeclaration(n) => {
let ports = port_dec_non_ansi(syntax_tree, n, event_iter, url);
if ports.is_some() {
for port in ports? {
definitions.push(Box::new(port));
}
}
}
RefNode::NetDeclaration(n) => {
let nets = net_dec(syntax_tree, n, event_iter, url);
if nets.is_some() {
for net in nets? {
definitions.push(Box::new(net));
}
}
}
RefNode::DataDeclaration(n) => {
let vars = data_dec(syntax_tree, n, event_iter, url);
if let Some(vars) = vars {
for var in vars {
match var {
Declaration::Dec(dec) => definitions.push(Box::new(dec)),
Declaration::Import(dec) => definitions.push(Box::new(dec)),
Declaration::Scope(scope) => scopes.push(Box::new(scope)),
}
}
}
}
RefNode::ParameterDeclaration(n) => {
let vars = param_dec(syntax_tree, n, event_iter, url);
if vars.is_some() {
for var in vars? {
definitions.push(Box::new(var));
}
}
}
RefNode::LocalParameterDeclaration(n) => {
let vars = localparam_dec(syntax_tree, n, event_iter, url);
if vars.is_some() {
for var in vars? {
definitions.push(Box::new(var));
}
}
}
RefNode::FunctionDeclaration(n) => {
let dec = function_dec(syntax_tree, n, event_iter, url);
if dec.is_some() {
scopes.push(Box::new(dec?));
}
}
RefNode::TaskDeclaration(n) => {
let dec = task_dec(syntax_tree, n, event_iter, url);
if dec.is_some() {
scopes.push(Box::new(dec?));
}
}
RefNode::ModportDeclaration(n) => {
let decs = modport_dec(syntax_tree, n, event_iter, url);
if decs.is_some() {
for dec in decs? {
definitions.push(Box::new(dec));
}
}
}
RefNode::ModuleInstantiation(n) => {
let decs = module_inst(syntax_tree, n, event_iter, url);
if decs.is_some() {
for dec in decs? {
definitions.push(Box::new(dec));
}
}
}
RefNode::TextMacroDefinition(n) => {
let dec = text_macro_def(syntax_tree, n, event_iter, url);
if dec.is_some() {
definitions.push(Box::new(dec?));
}
}
_ => (),
}
Some((scopes, definitions))
}
/// convert the syntax tree to a scope tree
/// the root node is the global scope
pub fn get_scopes_from_syntax_tree(syntax_tree: &SyntaxTree, url: &Url) -> Option<GenericScope> {
let mut scopes: Vec<Box<dyn Scope>> = Vec::new();
let mut global_scope: GenericScope = GenericScope::new(url);
global_scope.ident = String::from("global");
let mut event_iter = syntax_tree.into_iter().event();
// iterate over each enter event and extract out any scopes or definitions
// match_definitions is recursively called so we get a tree in the end
while let Some(event) = event_iter.next() {
match event {
NodeEvent::Enter(node) => {
let mut result = match_definitions(syntax_tree, &mut event_iter, node, url)?;
global_scope.defs.append(&mut result.1);
scopes.append(&mut result.0);
}
NodeEvent::Leave(_) => (),
}
}
global_scope.scopes.append(&mut scopes);
Some(global_scope)
}
pub fn get_scopes_from_vhdl_fast(fast: &FastHdlparam, text: &Rope, url: &Url) -> Option<GenericScope> {
let mut scopes: Vec<Box<dyn Scope>> = Vec::new();
let mut global_scope: GenericScope = GenericScope::new(url);
global_scope.ident = String::from("global");
for module in &fast.content {
let mut scope: GenericScope = GenericScope::new(url);
scope.ident = module.name.clone();
let module_range = module.range.clone();
scope.start = position_to_byte_idx(text, &module_range.start);
scope.end = position_to_byte_idx(text, &module_range.end);
scope.byte_idx = scope.start + 7;
for parameter in &module.params {
let mut def = GenericDec::new(url);
def.ident = parameter.name.clone();
let parameter_range = parameter.range.clone();
def.byte_idx = position_to_byte_idx(text, &parameter_range.start);
def.completion_kind = CompletionItemKind::TYPE_PARAMETER;
def.symbol_kind = SymbolKind::TYPE_PARAMETER;
scope.defs.push(Box::new(def));
}
for port in &module.ports {
let mut port_def = PortDec::new(url);
port_def.ident = port.name.clone();
let port_range = port.range.clone();
port_def.byte_idx = position_to_byte_idx(text, &port_range.start);
port_def.type_str = port.dir_type.clone();
scope.defs.push(Box::new(port_def));
}
for inst in &module.instances {
let mut instance = ModInst::new(url);
instance.ident = inst.name.clone();
let inst_range = inst.range.clone();
instance.byte_idx = position_to_byte_idx(text, &inst_range.start);
instance.type_str = inst.inst_type.clone();
instance.mod_ident = inst.inst_type.clone();
scope.defs.push(Box::new(instance));
}
scopes.push(Box::new(scope));
}
global_scope.scopes.append(&mut scopes);
Some(global_scope)
}
fn position_to_byte_idx(text: &Rope, pos: &hdlparam::Position) -> usize {
let char = text.line_to_char(pos.line as usize) + pos.character as usize;
text.char_to_byte(char)
}

View File

@ -1,8 +1,10 @@
use crate::definition::def_types::*;
use crate::definition::match_definitions;
use super::common::*;
use super::match_definitions;
use sv_parser::*;
use tower_lsp::lsp_types::*;
/// 找到 node 的 名字,开始的位置和结束的位置
pub fn get_ident(tree: &SyntaxTree, node: RefNode) -> (String, usize) {
let loc = unwrap_locate!(node).unwrap();
@ -2341,6 +2343,7 @@ pub fn text_macro_def(
text_macro.ident = ident.0;
text_macro.byte_idx = ident.1;
let type_str = &mut text_macro.type_str;
advance_until_enter!(
type_str,
tree,
@ -2349,8 +2352,11 @@ pub fn text_macro_def(
&TextMacroIdentifier
);
// 自动补全用的
text_macro.completion_kind = CompletionItemKind::CONSTANT;
// document 用的
text_macro.symbol_kind = SymbolKind::FUNCTION;
// 内部用于标定当前类型的
text_macro.def_type = DefinitionType::Macro;
Some(text_macro)
}

View File

@ -1,21 +1,12 @@
use crate::core::hdlparam::{self, FastHdlparam};
use crate::utils::get_language_id_by_uri;
use crate::server::LspServer;
#[allow(unused)]
use log::info;
use ropey::Rope;
use sv_parser::*;
use tower_lsp::lsp_types::*;
pub mod def_types;
pub use def_types::*;
pub mod feature;
pub mod extract_defs;
pub use extract_defs::*;
mod sv;
mod vhdl;
@ -37,218 +28,3 @@ impl LspServer {
}
}
}
type ScopesAndDefs = Option<(Vec<Box<dyn Scope>>, Vec<Box<dyn Definition>>)>;
/// Take a given syntax node from a sv-parser syntax tree and extract out the definition/scope at
/// that point.
pub fn match_definitions(
syntax_tree: &SyntaxTree,
event_iter: &mut EventIter,
node: RefNode,
url: &Url,
) -> ScopesAndDefs {
let mut definitions: Vec<Box<dyn Definition>> = Vec::new();
let mut scopes: Vec<Box<dyn Scope>> = Vec::new();
match node {
RefNode::ModuleDeclaration(n) => {
let module = module_dec(syntax_tree, n, event_iter, url);
if module.is_some() {
scopes.push(Box::new(module?));
}
}
RefNode::InterfaceDeclaration(n) => {
let interface = interface_dec(syntax_tree, n, event_iter, url);
if interface.is_some() {
scopes.push(Box::new(interface?));
}
}
RefNode::UdpDeclaration(n) => {
let dec = udp_dec(syntax_tree, n, event_iter, url);
if dec.is_some() {
scopes.push(Box::new(dec?));
}
}
RefNode::ProgramDeclaration(n) => {
let dec = program_dec(syntax_tree, n, event_iter, url);
if dec.is_some() {
scopes.push(Box::new(dec?));
}
}
RefNode::PackageDeclaration(n) => {
let dec = package_dec(syntax_tree, n, event_iter, url);
if dec.is_some() {
scopes.push(Box::new(dec?));
}
}
RefNode::ConfigDeclaration(n) => {
let dec = config_dec(syntax_tree, n, event_iter, url);
if dec.is_some() {
scopes.push(Box::new(dec?));
}
}
RefNode::ClassDeclaration(n) => {
let dec = class_dec(syntax_tree, n, event_iter, url);
if dec.is_some() {
scopes.push(Box::new(dec?));
}
}
RefNode::PortDeclaration(n) => {
let ports = port_dec_non_ansi(syntax_tree, n, event_iter, url);
if ports.is_some() {
for port in ports? {
definitions.push(Box::new(port));
}
}
}
RefNode::NetDeclaration(n) => {
let nets = net_dec(syntax_tree, n, event_iter, url);
if nets.is_some() {
for net in nets? {
definitions.push(Box::new(net));
}
}
}
RefNode::DataDeclaration(n) => {
let vars = data_dec(syntax_tree, n, event_iter, url);
if let Some(vars) = vars {
for var in vars {
match var {
Declaration::Dec(dec) => definitions.push(Box::new(dec)),
Declaration::Import(dec) => definitions.push(Box::new(dec)),
Declaration::Scope(scope) => scopes.push(Box::new(scope)),
}
}
}
}
RefNode::ParameterDeclaration(n) => {
let vars = param_dec(syntax_tree, n, event_iter, url);
if vars.is_some() {
for var in vars? {
definitions.push(Box::new(var));
}
}
}
RefNode::LocalParameterDeclaration(n) => {
let vars = localparam_dec(syntax_tree, n, event_iter, url);
if vars.is_some() {
for var in vars? {
definitions.push(Box::new(var));
}
}
}
RefNode::FunctionDeclaration(n) => {
let dec = function_dec(syntax_tree, n, event_iter, url);
if dec.is_some() {
scopes.push(Box::new(dec?));
}
}
RefNode::TaskDeclaration(n) => {
let dec = task_dec(syntax_tree, n, event_iter, url);
if dec.is_some() {
scopes.push(Box::new(dec?));
}
}
RefNode::ModportDeclaration(n) => {
let decs = modport_dec(syntax_tree, n, event_iter, url);
if decs.is_some() {
for dec in decs? {
definitions.push(Box::new(dec));
}
}
}
RefNode::ModuleInstantiation(n) => {
let decs = module_inst(syntax_tree, n, event_iter, url);
if decs.is_some() {
for dec in decs? {
definitions.push(Box::new(dec));
}
}
}
RefNode::TextMacroDefinition(n) => {
let dec = text_macro_def(syntax_tree, n, event_iter, url);
if dec.is_some() {
definitions.push(Box::new(dec?));
}
}
_ => (),
}
Some((scopes, definitions))
}
/// convert the syntax tree to a scope tree
/// the root node is the global scope
pub fn get_scopes_from_syntax_tree(syntax_tree: &SyntaxTree, url: &Url) -> Option<GenericScope> {
let mut scopes: Vec<Box<dyn Scope>> = Vec::new();
let mut global_scope: GenericScope = GenericScope::new(url);
global_scope.ident = String::from("global");
let mut event_iter = syntax_tree.into_iter().event();
// iterate over each enter event and extract out any scopes or definitions
// match_definitions is recursively called so we get a tree in the end
while let Some(event) = event_iter.next() {
match event {
NodeEvent::Enter(node) => {
let mut result = match_definitions(syntax_tree, &mut event_iter, node, url)?;
global_scope.defs.append(&mut result.1);
scopes.append(&mut result.0);
}
NodeEvent::Leave(_) => (),
}
}
global_scope.scopes.append(&mut scopes);
Some(global_scope)
}
pub fn get_scopes_from_vhdl_fast(fast: &FastHdlparam, text: &Rope, url: &Url) -> Option<GenericScope> {
let mut scopes: Vec<Box<dyn Scope>> = Vec::new();
let mut global_scope: GenericScope = GenericScope::new(url);
global_scope.ident = String::from("global");
for module in &fast.content {
let mut scope: GenericScope = GenericScope::new(url);
scope.ident = module.name.clone();
let module_range = module.range.clone();
scope.start = position_to_byte_idx(text, &module_range.start);
scope.end = position_to_byte_idx(text, &module_range.end);
scope.byte_idx = scope.start + 7;
for parameter in &module.params {
let mut def = GenericDec::new(url);
def.ident = parameter.name.clone();
let parameter_range = parameter.range.clone();
def.byte_idx = position_to_byte_idx(text, &parameter_range.start);
def.completion_kind = CompletionItemKind::TYPE_PARAMETER;
def.symbol_kind = SymbolKind::TYPE_PARAMETER;
scope.defs.push(Box::new(def));
}
for port in &module.ports {
let mut port_def = PortDec::new(url);
port_def.ident = port.name.clone();
let port_range = port.range.clone();
port_def.byte_idx = position_to_byte_idx(text, &port_range.start);
port_def.type_str = port.dir_type.clone();
scope.defs.push(Box::new(port_def));
}
for inst in &module.instances {
let mut instance = ModInst::new(url);
instance.ident = inst.name.clone();
let inst_range = inst.range.clone();
instance.byte_idx = position_to_byte_idx(text, &inst_range.start);
instance.type_str = inst.inst_type.clone();
instance.mod_ident = inst.inst_type.clone();
scope.defs.push(Box::new(instance));
}
scopes.push(Box::new(scope));
}
global_scope.scopes.append(&mut scopes);
Some(global_scope)
}
fn position_to_byte_idx(text: &Rope, pos: &hdlparam::Position) -> usize {
let char = text.line_to_char(pos.line as usize) + pos.character as usize;
text.char_to_byte(char)
}

View File

@ -1,3 +1,4 @@
use crate::core::scope_tree::common::{Definition, Scope};
use crate::utils::get_definition_token;
use crate::server::LspServer;
use crate::sources::LSPSupport;
@ -5,8 +6,7 @@ use crate::sources::LSPSupport;
#[allow(unused)]
use log::info;
use tower_lsp::lsp_types::*;
use super::{feature::*, Definition, Scope};
use super::feature::*;
pub fn goto_definition(server: &LspServer, params: &GotoDefinitionParams) -> Option<GotoDefinitionResponse> {
let doc = &params.text_document_position_params.text_document.uri;

View File

@ -5,8 +5,6 @@ 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 super::{Definition, Scope};
pub fn goto_vhdl_definition(server: &LspServer, params: &GotoDefinitionParams) -> Option<GotoDefinitionResponse> {
let doc = &params.text_document_position_params.text_document.uri;
let pos = params.text_document_position_params.position;

View File

@ -65,9 +65,12 @@ pub trait AbstractLinterConfiguration {
/// 获取与该工具匹配的诊断器名字与调用函数名。并检查它们是否有效
///
/// 参考链接https://kirigaya.cn/blog/article?seq=284
fn linter_status(&self) -> LinterStatus {
fn linter_status(
&self,
server: &LspServer
) -> LinterStatus {
let invoke_name = self.get_invoke_name();
let available = is_command_valid(&invoke_name);
let available = is_command_valid(&invoke_name, server);
LinterStatus {
tool_name: self.get_exe_name(),
available,

View File

@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use xml::name;
use crate::{diagnostics::find_non_whitespace_indices, server::LspServer};
use ropey::Rope;
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range, Url};
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, NumberOrString, Position, Range, Url};
use super::AbstractLinterConfiguration;
@ -113,7 +113,7 @@ impl AbstractLinterConfiguration for VivadoConfiguration {
let diagnostic = Diagnostic {
range,
code: None,
code: Some(NumberOrString::String(error_code.to_string())),
severity: Some(DiagnosticSeverity::ERROR),
source: Some("Digital IDE: vivado".to_string()),
message: error_description.to_string(),
@ -167,8 +167,6 @@ fn find_vivado_suitable_range(
let pattern = format!(r"\b(?i){}\b", error_keyword);
let regex = Regex::new(&pattern).unwrap();
info!("find keyword: {:?}", error_keyword);
if let Some(line_text) = rope.line(error_no).as_str() {
// 处理特殊情况: error_keyword 为 ;
if error_keyword == ";" {
@ -177,10 +175,75 @@ fn find_vivado_suitable_range(
}
}
if let Some(mat) = regex.find(line_text) {
info!("mat {} {}", mat.start(), mat.end());
// info!("mat {} {}", mat.start(), mat.end());
return Some((mat.start(), mat.end()));
}
}
find_non_whitespace_indices(rope, error_no)
}
/// 过滤 vivado 给出的一些报错
fn filter_diagnostic_result(
diagnostics: Vec<Diagnostic>,
server: &LspServer,
language_id: &str
) -> Vec<Diagnostic> {
match language_id {
// vhdl
"vhdl" => {
filter_xvhdl_diagnostic_result(diagnostics, server)
}
// vlog & svlog
_ => {
filter_xvlog_diagnostic_result(diagnostics, server)
}
}
}
fn filter_xvhdl_diagnostic_result(
diagnostics: Vec<Diagnostic>,
#[allow(unused)]
server: &LspServer,
) -> Vec<Diagnostic> {
diagnostics
}
/// 判断是否为类似于 xxx ignored 的错误
/// ERROR: [VRFC 10-8530] module 'main' is ignored due to previous errors [/home/dide/project/Digital-Test/Digital-macro/user/src/main.v:1]
fn is_ignore_type(diag: &Diagnostic) -> bool {
// 获取 vrfc 编码
let vrfc_code = if let Some(NumberOrString::String(code)) = &diag.code {
code
} else {
return false;
};
match vrfc_code.as_str() {
"10-8530" => {
true
}
_ => {
false
}
}
}
fn filter_xvlog_diagnostic_result(
diagnostics: Vec<Diagnostic>,
#[allow(unused)]
server: &LspServer,
) -> Vec<Diagnostic> {
// 第一级过滤, 去除所有的 ignore 类型的
let diagnostics = diagnostics.into_iter().filter(|diag| !is_ignore_type(diag)).collect();
// 第二级过滤, 对于 xxx not found, 需要先根据 fast 查看是否存在, 如果存在,还需要把同一行的某些特定错误一并去除
diagnostics
}

View File

@ -3,7 +3,9 @@ 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::{server::LspServer, sources::{LSPSupport, ParseIR, Source}};
use crate::core::scope_tree::parse::get_ident;
use crate::core::scope_tree::common::Scope;
pub fn document_highlight(
server: &LspServer,

View File

@ -2,7 +2,9 @@ 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::{server::LspServer, sources::{LSPSupport, ParseIR, Source}};
use crate::core::scope_tree::parse::get_ident;
use crate::core::scope_tree::common::Scope;
pub fn document_highlight(
server: &LspServer,

View File

@ -1,4 +1,4 @@
use crate::{definition::Scope, server::LspServer};
use crate::{core::scope_tree::common::Scope, server::LspServer};
use tower_lsp::lsp_types::*;
pub fn document_symbol(

View File

@ -4,7 +4,7 @@ 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::{server::LspServer, utils::{to_escape_path, to_lsp_range, to_symbol_kind}};
pub fn document_symbol(server: &LspServer, params: &DocumentSymbolParams) -> Option<DocumentSymbolResponse> {
// info!("enter document symbol");

View File

@ -3,11 +3,11 @@ 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}, scope_tree::common::Scope}, hover::{to_escape_path, BracketMatchResult, BracketMatcher}, server::LspServer, sources::LSPSupport};
use super::feature::*;
use std::{path::PathBuf, str::FromStr, sync::RwLockReadGuard};
use crate::definition::*;
use crate::core::scope_tree::common::*;
use super::{get_definition_token, get_language_id_by_uri};

View File

@ -4,7 +4,8 @@ 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}, hover::{BracketMatchResult, BracketMatcher}, server::LspServer};
use crate::core::scope_tree::common::*;
use super::{from_lsp_pos, get_definition_token, get_language_id_by_uri, to_escape_path};

View File

@ -15,7 +15,7 @@ use crate::core::hdlparam::FastHdlparam;
use crate::core::sv_parser::make_fast_from_syntaxtree;
use crate::core::vhdl_parser::make_fast_from_units;
use crate::definition::VhdlProject;
use crate::core::scope_tree::common::VhdlProject;
use crate::{core, utils::*};
use crate::server::Backend;
use crate::sources::recovery_sv_parse_with_retry;

View File

@ -63,23 +63,23 @@ fn get_linter_status(
// 再根据 linter name 进行分类讨论
match linter_name {
"iverilog" => {
Ok(configuration.iverilog.linter_status())
Ok(configuration.iverilog.linter_status(&backend.server))
}
"vivado" => {
Ok(configuration.vivado.linter_status())
Ok(configuration.vivado.linter_status(&backend.server))
}
"modelsim" => {
Ok(configuration.modelsim.linter_status())
Ok(configuration.modelsim.linter_status(&backend.server))
}
"verible" => {
Ok(configuration.verible.linter_status())
Ok(configuration.verible.linter_status(&backend.server))
}
"verilator" => {
Ok(configuration.verilator.linter_status())
Ok(configuration.verilator.linter_status(&backend.server))
}
_ => {

View File

@ -3,9 +3,9 @@ use crate::core::primitive_parser::PrimitiveText;
use crate::core::sv_parser::make_fast_from_syntaxtree;
use crate::core::vhdl_parser::make_fast_from_units;
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::core::scope_tree::common::*;
use crate::core::scope_tree::get_scopes_from_syntax_tree;
use crate::core::scope_tree::get_scopes_from_vhdl_fast;
use crate::diagnostics::provide_diagnostics;
use crate::server::LspServer;
use crate::server::LspConfiguration;

View File

@ -311,7 +311,9 @@ mod test_svparse {
#[cfg(test)]
mod test_scope_tree {
use std::{fs, path::{Path, PathBuf}};
use crate::{definition::{get_scopes_from_syntax_tree, GenericScope}, sources::{recovery_sv_parse, recovery_sv_parse_with_retry}};
use crate::sources::recovery_sv_parse_with_retry;
use crate::core::scope_tree::get_scopes_from_syntax_tree;
use crate::core::scope_tree::common::GenericScope;
use ropey::Rope;
use tower_lsp::lsp_types::Url;

View File

@ -1,8 +1,27 @@
use std::process::Command;
pub fn is_command_valid(command: &str) -> bool {
use log::info;
use crate::server::LspServer;
pub fn is_command_valid(
command: &str,
server: &LspServer
) -> bool {
let cache_info = server.cache.cache_info.read().unwrap();
let cwd = match &cache_info.linter_cache {
Some(pc) => pc,
None => {
info!("缓存系统尚未完成初始化,获取命令有效性取消");
return false;
}
};
// 尝试执行命令
match Command::new(command).output() {
match Command::new(command)
.current_dir(cwd)
.output() {
Ok(_) => true,
Err(_) => false,
}