剥离 scope tree 逻辑到 core 模块中
This commit is contained in:
parent
36ba7a350d
commit
7875a631a8
@ -7,3 +7,5 @@ pub mod vhdl_parser;
|
||||
pub mod cache_storage;
|
||||
|
||||
pub mod primitive_parser;
|
||||
|
||||
pub mod scope_tree;
|
@ -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
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 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)
|
||||
}
|
@ -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, ¶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::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 = ¶ms.text_document_position_params.text_document.uri;
|
||||
|
@ -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 = ¶ms.text_document_position_params.text_document.uri;
|
||||
let pos = params.text_document_position_params.position;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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");
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
_ => {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user