剥离 scope tree 逻辑到 core 模块中
This commit is contained in:
parent
36ba7a350d
commit
7875a631a8
@ -373,7 +373,7 @@ fn make_module_completions(
|
|||||||
insert_text_mode: Some(InsertTextMode::ADJUST_INDENTATION),
|
insert_text_mode: Some(InsertTextMode::ADJUST_INDENTATION),
|
||||||
..CompletionItem::default()
|
..CompletionItem::default()
|
||||||
};
|
};
|
||||||
module_completioms.push(item);
|
module_completioms.push(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,3 +7,5 @@ pub mod vhdl_parser;
|
|||||||
pub mod cache_storage;
|
pub mod cache_storage;
|
||||||
|
|
||||||
pub mod primitive_parser;
|
pub mod primitive_parser;
|
||||||
|
|
||||||
|
pub mod scope_tree;
|
@ -1,5 +1,3 @@
|
|||||||
use std::ffi::OsStr;
|
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
use ropey::Rope;
|
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
|
// first we need to go down the scope tree, to the scope the user is invoking a completion
|
||||||
// in
|
// in
|
||||||
for scope in self.scopes() {
|
for scope in self.scopes() {
|
||||||
|
// 如果当前的 token 在这个 scope 中,那么需要递归获取这个 scope 中的所有补全项目
|
||||||
if &scope.url() == url && scope.start() <= byte_idx && byte_idx <= scope.end() {
|
if &scope.url() == url && scope.start() <= byte_idx && byte_idx <= scope.end() {
|
||||||
completions = scope.get_completion(token, byte_idx, url);
|
completions = scope.get_completion(token, byte_idx, url);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 自动补全时,忽略大小写
|
||||||
let lower_case_token = token.to_lowercase();
|
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();
|
let completion_idents: Vec<String> = completions.iter().map(|x| x.label.clone()).collect();
|
||||||
|
|
||||||
|
// 寻找前缀相同的 symbol
|
||||||
for def in self.defs() {
|
for def in self.defs() {
|
||||||
|
|
||||||
if !completion_idents.contains(&def.ident()) && def.ident().to_lowercase().starts_with(&lower_case_token) {
|
if !completion_idents.contains(&def.ident()) && def.ident().to_lowercase().starts_with(&lower_case_token) {
|
||||||
completions.push(def.completion());
|
completions.push(def.completion());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 寻找前缀相同的 scope
|
||||||
for scope in self.scopes() {
|
for scope in self.scopes() {
|
||||||
if scope.starts_with(token) {
|
if scope.starts_with(token) {
|
||||||
completions.push(scope.completion());
|
completions.push(scope.completion());
|
||||||
@ -155,7 +154,6 @@ pub trait Scope: std::fmt::Debug + Definition + Sync + Send {
|
|||||||
// in
|
// in
|
||||||
for scope in self.scopes() {
|
for scope in self.scopes() {
|
||||||
if &scope.url() == url && scope.start() <= byte_idx && byte_idx <= scope.end() {
|
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);
|
let result = scope.get_dot_completion(token, byte_idx, url, scope_tree);
|
||||||
if !result.is_empty() {
|
if !result.is_empty() {
|
||||||
return result;
|
return result;
|
226
src/core/scope_tree/mod.rs
Normal file
226
src/core/scope_tree/mod.rs
Normal 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, ¶meter_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)
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
use crate::definition::def_types::*;
|
use super::common::*;
|
||||||
use crate::definition::match_definitions;
|
use super::match_definitions;
|
||||||
|
|
||||||
use sv_parser::*;
|
use sv_parser::*;
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
|
|
||||||
/// 找到 node 的 名字,开始的位置和结束的位置
|
/// 找到 node 的 名字,开始的位置和结束的位置
|
||||||
pub fn get_ident(tree: &SyntaxTree, node: RefNode) -> (String, usize) {
|
pub fn get_ident(tree: &SyntaxTree, node: RefNode) -> (String, usize) {
|
||||||
let loc = unwrap_locate!(node).unwrap();
|
let loc = unwrap_locate!(node).unwrap();
|
||||||
@ -2340,7 +2342,8 @@ pub fn text_macro_def(
|
|||||||
let ident = get_ident(tree, RefNode::TextMacroIdentifier(&node.nodes.2.nodes.0));
|
let ident = get_ident(tree, RefNode::TextMacroIdentifier(&node.nodes.2.nodes.0));
|
||||||
text_macro.ident = ident.0;
|
text_macro.ident = ident.0;
|
||||||
text_macro.byte_idx = ident.1;
|
text_macro.byte_idx = ident.1;
|
||||||
let type_str = &mut text_macro.type_str;
|
let type_str = &mut text_macro.type_str;
|
||||||
|
|
||||||
advance_until_enter!(
|
advance_until_enter!(
|
||||||
type_str,
|
type_str,
|
||||||
tree,
|
tree,
|
||||||
@ -2349,8 +2352,11 @@ pub fn text_macro_def(
|
|||||||
&TextMacroIdentifier
|
&TextMacroIdentifier
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 自动补全用的
|
||||||
text_macro.completion_kind = CompletionItemKind::CONSTANT;
|
text_macro.completion_kind = CompletionItemKind::CONSTANT;
|
||||||
|
// document 用的
|
||||||
text_macro.symbol_kind = SymbolKind::FUNCTION;
|
text_macro.symbol_kind = SymbolKind::FUNCTION;
|
||||||
|
// 内部用于标定当前类型的
|
||||||
text_macro.def_type = DefinitionType::Macro;
|
text_macro.def_type = DefinitionType::Macro;
|
||||||
Some(text_macro)
|
Some(text_macro)
|
||||||
}
|
}
|
@ -1,21 +1,12 @@
|
|||||||
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;
|
||||||
use ropey::Rope;
|
|
||||||
use sv_parser::*;
|
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
pub mod def_types;
|
|
||||||
pub use def_types::*;
|
|
||||||
|
|
||||||
pub mod feature;
|
pub mod feature;
|
||||||
|
|
||||||
pub mod extract_defs;
|
|
||||||
pub use extract_defs::*;
|
|
||||||
|
|
||||||
mod sv;
|
mod sv;
|
||||||
mod vhdl;
|
mod vhdl;
|
||||||
|
|
||||||
@ -36,219 +27,4 @@ impl LspServer {
|
|||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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, ¶meter_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)
|
|
||||||
}
|
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::core::scope_tree::common::{Definition, Scope};
|
||||||
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;
|
||||||
@ -5,8 +6,7 @@ use crate::sources::LSPSupport;
|
|||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use log::info;
|
use log::info;
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
use super::feature::*;
|
||||||
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;
|
||||||
|
@ -5,8 +5,6 @@ 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};
|
|
||||||
|
|
||||||
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;
|
||||||
|
@ -65,9 +65,12 @@ pub trait AbstractLinterConfiguration {
|
|||||||
/// 获取与该工具匹配的诊断器名字与调用函数名。并检查它们是否有效
|
/// 获取与该工具匹配的诊断器名字与调用函数名。并检查它们是否有效
|
||||||
///
|
///
|
||||||
/// 参考链接:https://kirigaya.cn/blog/article?seq=284
|
/// 参考链接: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 invoke_name = self.get_invoke_name();
|
||||||
let available = is_command_valid(&invoke_name);
|
let available = is_command_valid(&invoke_name, server);
|
||||||
LinterStatus {
|
LinterStatus {
|
||||||
tool_name: self.get_exe_name(),
|
tool_name: self.get_exe_name(),
|
||||||
available,
|
available,
|
||||||
|
@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use xml::name;
|
use xml::name;
|
||||||
use crate::{diagnostics::find_non_whitespace_indices, server::LspServer};
|
use crate::{diagnostics::find_non_whitespace_indices, server::LspServer};
|
||||||
use ropey::Rope;
|
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;
|
use super::AbstractLinterConfiguration;
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ impl AbstractLinterConfiguration for VivadoConfiguration {
|
|||||||
|
|
||||||
let diagnostic = Diagnostic {
|
let diagnostic = Diagnostic {
|
||||||
range,
|
range,
|
||||||
code: None,
|
code: Some(NumberOrString::String(error_code.to_string())),
|
||||||
severity: Some(DiagnosticSeverity::ERROR),
|
severity: Some(DiagnosticSeverity::ERROR),
|
||||||
source: Some("Digital IDE: vivado".to_string()),
|
source: Some("Digital IDE: vivado".to_string()),
|
||||||
message: error_description.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 pattern = format!(r"\b(?i){}\b", error_keyword);
|
||||||
let regex = Regex::new(&pattern).unwrap();
|
let regex = Regex::new(&pattern).unwrap();
|
||||||
|
|
||||||
info!("find keyword: {:?}", error_keyword);
|
|
||||||
|
|
||||||
if let Some(line_text) = rope.line(error_no).as_str() {
|
if let Some(line_text) = rope.line(error_no).as_str() {
|
||||||
// 处理特殊情况: error_keyword 为 ;
|
// 处理特殊情况: error_keyword 为 ;
|
||||||
if error_keyword == ";" {
|
if error_keyword == ";" {
|
||||||
@ -177,10 +175,75 @@ fn find_vivado_suitable_range(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(mat) = regex.find(line_text) {
|
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()));
|
return Some((mat.start(), mat.end()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
find_non_whitespace_indices(rope, error_no)
|
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
|
||||||
}
|
}
|
@ -3,7 +3,9 @@ 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::{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(
|
pub fn document_highlight(
|
||||||
server: &LspServer,
|
server: &LspServer,
|
||||||
|
@ -2,7 +2,9 @@ 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::{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(
|
pub fn document_highlight(
|
||||||
server: &LspServer,
|
server: &LspServer,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{definition::Scope, server::LspServer};
|
use crate::{core::scope_tree::common::Scope, server::LspServer};
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
pub fn document_symbol(
|
pub fn document_symbol(
|
||||||
|
@ -4,7 +4,7 @@ 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::{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");
|
||||||
|
@ -3,11 +3,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}, 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 super::feature::*;
|
||||||
use std::{path::PathBuf, str::FromStr, sync::RwLockReadGuard};
|
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};
|
use super::{get_definition_token, get_language_id_by_uri};
|
||||||
|
|
||||||
|
@ -4,7 +4,8 @@ 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}, 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};
|
use super::{from_lsp_pos, get_definition_token, get_language_id_by_uri, to_escape_path};
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ use crate::core::hdlparam::FastHdlparam;
|
|||||||
use crate::core::sv_parser::make_fast_from_syntaxtree;
|
use crate::core::sv_parser::make_fast_from_syntaxtree;
|
||||||
|
|
||||||
use crate::core::vhdl_parser::make_fast_from_units;
|
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::{core, utils::*};
|
||||||
use crate::server::Backend;
|
use crate::server::Backend;
|
||||||
use crate::sources::recovery_sv_parse_with_retry;
|
use crate::sources::recovery_sv_parse_with_retry;
|
||||||
|
@ -63,23 +63,23 @@ fn get_linter_status(
|
|||||||
// 再根据 linter name 进行分类讨论
|
// 再根据 linter name 进行分类讨论
|
||||||
match linter_name {
|
match linter_name {
|
||||||
"iverilog" => {
|
"iverilog" => {
|
||||||
Ok(configuration.iverilog.linter_status())
|
Ok(configuration.iverilog.linter_status(&backend.server))
|
||||||
}
|
}
|
||||||
|
|
||||||
"vivado" => {
|
"vivado" => {
|
||||||
Ok(configuration.vivado.linter_status())
|
Ok(configuration.vivado.linter_status(&backend.server))
|
||||||
}
|
}
|
||||||
|
|
||||||
"modelsim" => {
|
"modelsim" => {
|
||||||
Ok(configuration.modelsim.linter_status())
|
Ok(configuration.modelsim.linter_status(&backend.server))
|
||||||
}
|
}
|
||||||
|
|
||||||
"verible" => {
|
"verible" => {
|
||||||
Ok(configuration.verible.linter_status())
|
Ok(configuration.verible.linter_status(&backend.server))
|
||||||
}
|
}
|
||||||
|
|
||||||
"verilator" => {
|
"verilator" => {
|
||||||
Ok(configuration.verilator.linter_status())
|
Ok(configuration.verilator.linter_status(&backend.server))
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -3,9 +3,9 @@ use crate::core::primitive_parser::PrimitiveText;
|
|||||||
use crate::core::sv_parser::make_fast_from_syntaxtree;
|
use crate::core::sv_parser::make_fast_from_syntaxtree;
|
||||||
use crate::core::vhdl_parser::make_fast_from_units;
|
use crate::core::vhdl_parser::make_fast_from_units;
|
||||||
use crate::core::vhdl_parser::vhdl_parse_str;
|
use crate::core::vhdl_parser::vhdl_parse_str;
|
||||||
use crate::definition::def_types::*;
|
use crate::core::scope_tree::common::*;
|
||||||
use crate::definition::get_scopes_from_syntax_tree;
|
use crate::core::scope_tree::get_scopes_from_syntax_tree;
|
||||||
use crate::definition::get_scopes_from_vhdl_fast;
|
use crate::core::scope_tree::get_scopes_from_vhdl_fast;
|
||||||
use crate::diagnostics::provide_diagnostics;
|
use crate::diagnostics::provide_diagnostics;
|
||||||
use crate::server::LspServer;
|
use crate::server::LspServer;
|
||||||
use crate::server::LspConfiguration;
|
use crate::server::LspConfiguration;
|
||||||
|
@ -311,7 +311,9 @@ mod test_svparse {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_scope_tree {
|
mod test_scope_tree {
|
||||||
use std::{fs, path::{Path, PathBuf}};
|
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 ropey::Rope;
|
||||||
use tower_lsp::lsp_types::Url;
|
use tower_lsp::lsp_types::Url;
|
||||||
|
|
||||||
|
@ -1,8 +1,27 @@
|
|||||||
use std::process::Command;
|
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,
|
Ok(_) => true,
|
||||||
Err(_) => false,
|
Err(_) => false,
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user