xilinx IP 支持 | 增加全局 conf 属性
This commit is contained in:
parent
f055b2bbc3
commit
cbddc07bdc
@ -1,9 +1,10 @@
|
|||||||
use std::{collections::HashMap, fs::{self}, hash::{DefaultHasher, Hash, Hasher}, path::PathBuf, sync::{Arc, RwLock}};
|
use std::{collections::HashMap, fs::{self}, hash::{DefaultHasher, Hash, Hasher}, path::PathBuf, str::FromStr, sync::{Arc, RwLock}};
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tower_lsp::lsp_types::Url;
|
||||||
|
|
||||||
use crate::utils::{file_size_in_kb, get_last_modified_time, k_deserialize, k_serialize};
|
use crate::utils::{file_size_in_kb, get_last_modified_time, k_deserialize, k_serialize, to_escape_path};
|
||||||
|
|
||||||
use super::hdlparam::FastHdlparam;
|
use super::hdlparam::FastHdlparam;
|
||||||
|
|
||||||
@ -59,7 +60,17 @@ impl CacheManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_big_file(&self, path: &PathBuf) -> bool {
|
pub fn is_big_file(path: &PathBuf) -> bool {
|
||||||
|
if let Ok(size) = file_size_in_kb(path.to_str().unwrap()) {
|
||||||
|
return size >= 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uri_is_big_file(uri: &Url) -> bool {
|
||||||
|
let path = PathBuf::from_str(uri.path()).unwrap();
|
||||||
|
let path = to_escape_path(&path);
|
||||||
if let Ok(size) = file_size_in_kb(path.to_str().unwrap()) {
|
if let Ok(size) = file_size_in_kb(path.to_str().unwrap()) {
|
||||||
return size >= 1024;
|
return size >= 1024;
|
||||||
}
|
}
|
||||||
@ -83,7 +94,7 @@ impl CacheManager {
|
|||||||
/// * 如果本来就没有缓存
|
/// * 如果本来就没有缓存
|
||||||
/// * 缓冲的 version 对不上
|
/// * 缓冲的 version 对不上
|
||||||
pub fn try_get_fast_cache(&self, path: &PathBuf) -> CacheResult<FastHdlparam> {
|
pub fn try_get_fast_cache(&self, path: &PathBuf) -> CacheResult<FastHdlparam> {
|
||||||
if !self.is_big_file(path) {
|
if !CacheManager::is_big_file(path) {
|
||||||
return CacheResult::NotNeedCache
|
return CacheResult::NotNeedCache
|
||||||
}
|
}
|
||||||
let path_string = path.to_str().unwrap();
|
let path_string = path.to_str().unwrap();
|
||||||
|
@ -171,6 +171,31 @@ impl Port {
|
|||||||
port_desc_array.push(self.width.to_string());
|
port_desc_array.push(self.width.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
port_desc_array.push(self.name.to_string());
|
||||||
|
let port_desc = port_desc_array.join(" ");
|
||||||
|
port_desc
|
||||||
|
}
|
||||||
|
pub fn vhdl_to_vlog_description(&self) -> String {
|
||||||
|
let mut port_desc_array = Vec::<String>::new();
|
||||||
|
let dir_type = match self.dir_type.as_str() {
|
||||||
|
"in" => "input",
|
||||||
|
"out" => "output",
|
||||||
|
_ => &self.dir_type
|
||||||
|
};
|
||||||
|
|
||||||
|
port_desc_array.push(dir_type.to_string());
|
||||||
|
if self.net_type != "unknown" {
|
||||||
|
port_desc_array.push(self.net_type.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.signed != "unsigned" {
|
||||||
|
port_desc_array.push("signed".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.width != "1" {
|
||||||
|
port_desc_array.push(self.width.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
port_desc_array.push(self.name.to_string());
|
port_desc_array.push(self.name.to_string());
|
||||||
let port_desc = port_desc_array.join(" ");
|
let port_desc = port_desc_array.join(" ");
|
||||||
port_desc
|
port_desc
|
||||||
|
@ -207,6 +207,8 @@ pub fn goto_module_declaration_definition(
|
|||||||
token_name: &str
|
token_name: &str
|
||||||
) -> Option<GotoDefinitionResponse> {
|
) -> Option<GotoDefinitionResponse> {
|
||||||
let hdl_param = server.srcs.hdl_param.clone();
|
let hdl_param = server.srcs.hdl_param.clone();
|
||||||
|
info!("get into goto_module_declaration_definition");
|
||||||
|
|
||||||
if let Some((module, file_type, def_path)) = hdl_param.find_module_context_by_name(token_name) {
|
if let Some((module, file_type, def_path)) = hdl_param.find_module_context_by_name(token_name) {
|
||||||
match file_type.as_str() {
|
match file_type.as_str() {
|
||||||
"common" => {
|
"common" => {
|
||||||
@ -280,6 +282,7 @@ fn goto_ip_module_declaration_definition(
|
|||||||
let target_uri = Url::from_file_path(PathBuf::from_str(&def_path).unwrap()).unwrap();
|
let target_uri = Url::from_file_path(PathBuf::from_str(&def_path).unwrap()).unwrap();
|
||||||
|
|
||||||
let target_range = module.range.clone();
|
let target_range = module.range.clone();
|
||||||
|
info!("target range: {:?}", target_range);
|
||||||
let target_range = target_range.to_lsp_range();
|
let target_range = target_range.to_lsp_range();
|
||||||
|
|
||||||
let link = vec![LocationLink {
|
let link = vec![LocationLink {
|
||||||
|
@ -433,6 +433,8 @@ fn hover_ip_module_declaration(
|
|||||||
|
|
||||||
if def_path_buf.exists() {
|
if def_path_buf.exists() {
|
||||||
// TODO: 当前工具链只支持 Xilinx 下的工具链,所以此处的代码是 vhdl 的代码
|
// TODO: 当前工具链只支持 Xilinx 下的工具链,所以此处的代码是 vhdl 的代码
|
||||||
|
// 如果未来需要支持其他的工具链,则需要从 server 下读取对应的变量
|
||||||
|
|
||||||
let path_uri = Url::from_file_path(def_path.to_string()).unwrap().to_string();
|
let path_uri = Url::from_file_path(def_path.to_string()).unwrap().to_string();
|
||||||
let def_row = module.range.start.line;
|
let def_row = module.range.start.line;
|
||||||
let def_col = module.range.start.character;
|
let def_col = module.range.start.character;
|
||||||
@ -467,7 +469,7 @@ fn hover_ip_module_declaration(
|
|||||||
markdowns.push(MarkedString::String("---".to_string()));
|
markdowns.push(MarkedString::String("---".to_string()));
|
||||||
|
|
||||||
let language_id = get_language_id_by_path_str(def_path);
|
let language_id = get_language_id_by_path_str(def_path);
|
||||||
let module_profile = make_module_profile_code(&module);
|
let module_profile = make_entity_profile_code(&module);
|
||||||
let profile_markdown = LanguageString {
|
let profile_markdown = LanguageString {
|
||||||
language: language_id.to_string(),
|
language: language_id.to_string(),
|
||||||
value: module_profile
|
value: module_profile
|
||||||
@ -596,11 +598,109 @@ pub fn make_module_profile_code(module: &crate::core::hdlparam::Module) -> Strin
|
|||||||
codes.push(format!("\t{port_desc},"));
|
codes.push(format!("\t{port_desc},"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
codes.push(format!(")"));
|
|
||||||
} else {
|
|
||||||
codes.push(format!(")"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
codes.push(format!(");"));
|
||||||
|
|
||||||
|
let profile_string = codes.join("\n");
|
||||||
|
profile_string
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// vhdl 的 entity 的 profile
|
||||||
|
pub fn make_entity_profile_code(module: &crate::core::hdlparam::Module) -> String {
|
||||||
|
let mut codes = Vec::<String>::new();
|
||||||
|
// param 其实就是 generic
|
||||||
|
let param_num = module.params.len();
|
||||||
|
let port_num = module.ports.len();
|
||||||
|
|
||||||
|
codes.push(format!("entity {} is", module.name));
|
||||||
|
// 缩进字符
|
||||||
|
if module.params.len() > 0 {
|
||||||
|
codes.push("\tgeneric (".to_string());
|
||||||
|
let max_param_name_length = module.params.iter().map(|param| param.name.len()).max().unwrap_or(0);
|
||||||
|
let max_param_type_length = module.params.iter().map(|param| param.net_type.len()).max().unwrap_or(0);
|
||||||
|
|
||||||
|
for (i, param) in module.params.iter().enumerate() {
|
||||||
|
let mut param_desc_array = Vec::<String>::new();
|
||||||
|
let param_name_align_spaces = " ".repeat(max_param_name_length - param.name.len() + 1);
|
||||||
|
param_desc_array.push(format!("{}{}:", param.name, param_name_align_spaces));
|
||||||
|
|
||||||
|
let param_type_align_spaces = " ".repeat(max_param_type_length - param.net_type.len() + 1);
|
||||||
|
param_desc_array.push(format!("{}{}", param.net_type, param_type_align_spaces));
|
||||||
|
|
||||||
|
if param.init != "unknown" {
|
||||||
|
param_desc_array.push(format!(":= {}", param.init.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let param_desc = param_desc_array.join(" ");
|
||||||
|
if i == param_num - 1 {
|
||||||
|
codes.push(format!("\t\t{param_desc}"));
|
||||||
|
} else {
|
||||||
|
codes.push(format!("\t\t{param_desc};"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
codes.push("\t);".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if module.ports.len() > 0 {
|
||||||
|
codes.push("\tport (".to_string());
|
||||||
|
|
||||||
|
let net_mapper = |net_type: &str| {
|
||||||
|
if net_type == "unknown" {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
net_type.len()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let width_mapper = |width: &str| {
|
||||||
|
if width == "1" {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
width.len() + 5
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let max_port_length = module.ports.iter().map(|port| port.name.len()).max().unwrap_or(0);
|
||||||
|
let max_net_length = module.ports.iter().map(|port| net_mapper(&port.net_type)).max().unwrap_or(0);
|
||||||
|
// let max_width_length = module.ports.iter().map(|port| width_mapper(&port.width)).max().unwrap_or(0);
|
||||||
|
let max_dir_length = module.ports.iter().map(|port| port.dir_type.len()).max().unwrap_or(0);
|
||||||
|
|
||||||
|
for (i, port) in module.ports.iter().enumerate() {
|
||||||
|
let mut port_desc_array = Vec::<String>::new();
|
||||||
|
|
||||||
|
// port 的名字
|
||||||
|
let port_name_align_spaces = " ".repeat(max_port_length - port.name.len() + 1);
|
||||||
|
port_desc_array.push(format!("{}{}: ", port.name, port_name_align_spaces));
|
||||||
|
|
||||||
|
// in, out, inout
|
||||||
|
let port_dir_align_spaces = " ".repeat(max_dir_length - port.dir_type.len() + 1);
|
||||||
|
port_desc_array.push(format!("{}{}", port.dir_type, port_dir_align_spaces));
|
||||||
|
|
||||||
|
// std_logic, signed, unsigned 等等
|
||||||
|
if port.net_type != "unknown" {
|
||||||
|
port_desc_array.push(port.net_type.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// (57 downto 0)
|
||||||
|
if port.width != "1" {
|
||||||
|
// 内部的 width 统一表示成 [57:0] 这样的格式,需要转换一下
|
||||||
|
let width_string = port.width.replace("[", "(").replace("]", ")").replace(":", " downto ");
|
||||||
|
port_desc_array.push(width_string);
|
||||||
|
}
|
||||||
|
let port_desc = port_desc_array.join("");
|
||||||
|
if i == port_num - 1 {
|
||||||
|
codes.push(format!("\t\t{port_desc}"));
|
||||||
|
} else {
|
||||||
|
codes.push(format!("\t\t{port_desc};"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
codes.push("\t);".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
codes.push(format!("end entity {};", module.name));
|
||||||
|
|
||||||
let profile_string = codes.join("\n");
|
let profile_string = codes.join("\n");
|
||||||
profile_string
|
profile_string
|
||||||
}
|
}
|
@ -6,7 +6,7 @@ use log::info;
|
|||||||
use ropey::Rope;
|
use ropey::Rope;
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp::lsp_types::*;
|
||||||
|
|
||||||
use super::to_escape_path;
|
use super::{get_language_id_by_path_str, to_escape_path};
|
||||||
|
|
||||||
pub fn inlay_hint(server: &LSPServer, params: &InlayHintParams) -> Option<Vec<InlayHint>> {
|
pub fn inlay_hint(server: &LSPServer, params: &InlayHintParams) -> Option<Vec<InlayHint>> {
|
||||||
let uri = ¶ms.text_document.uri;
|
let uri = ¶ms.text_document.uri;
|
||||||
@ -95,7 +95,6 @@ fn find_instport_inlay_hints_position(
|
|||||||
let end_offset = position_to_index(rope, range.end);
|
let end_offset = position_to_index(rope, range.end);
|
||||||
let instport_text = rope.slice(start_offset .. end_offset);
|
let instport_text = rope.slice(start_offset .. end_offset);
|
||||||
let instport_text = instport_text.to_string();
|
let instport_text = instport_text.to_string();
|
||||||
info!("{:?}", instport_text);
|
|
||||||
|
|
||||||
if let Some(offset) = instport_text.find("(") {
|
if let Some(offset) = instport_text.find("(") {
|
||||||
let target_offset = start_offset + offset + 1;
|
let target_offset = start_offset + offset + 1;
|
||||||
@ -112,12 +111,13 @@ fn make_instport_hints(
|
|||||||
instance: &core::hdlparam::Instance,
|
instance: &core::hdlparam::Instance,
|
||||||
rope: &Rope
|
rope: &Rope
|
||||||
) -> Vec<InlayHint> {
|
) -> Vec<InlayHint> {
|
||||||
|
let hdl_param = server.srcs.hdl_param.clone();
|
||||||
let mut hints = Vec::<InlayHint>::new();
|
let mut hints = Vec::<InlayHint>::new();
|
||||||
let define_module = server.srcs.hdl_param.find_module_by_name(&instance.inst_type);
|
let module_context = hdl_param.find_module_context_by_name(&instance.inst_type);
|
||||||
if define_module.is_none() {
|
if module_context.is_none() {
|
||||||
return hints;
|
return hints;
|
||||||
}
|
}
|
||||||
let define_module = define_module.unwrap();
|
let (define_module, file_type, def_path) = module_context.unwrap();
|
||||||
// 制作 port name 到 port 的映射
|
// 制作 port name 到 port 的映射
|
||||||
let mut port_map = HashMap::<String, &core::hdlparam::Port>::new();
|
let mut port_map = HashMap::<String, &core::hdlparam::Port>::new();
|
||||||
for port in &define_module.ports {
|
for port in &define_module.ports {
|
||||||
@ -132,15 +132,18 @@ fn make_instport_hints(
|
|||||||
}
|
}
|
||||||
let port_info = port.unwrap();
|
let port_info = port.unwrap();
|
||||||
let instport_range = port_assigment.range.to_lsp_range();
|
let instport_range = port_assigment.range.to_lsp_range();
|
||||||
info!("inst name: {:?}, range: {:?}", instance.name, instport_range);
|
|
||||||
if let Some(hint_position) = find_instport_inlay_hints_position(rope, &instport_range) {
|
if let Some(hint_position) = find_instport_inlay_hints_position(rope, &instport_range) {
|
||||||
let port_desc = MarkupContent {
|
|
||||||
kind: MarkupKind::Markdown,
|
|
||||||
value: format!("```verilog\n{}\n```", port_info.to_description())
|
|
||||||
};
|
|
||||||
|
|
||||||
let label = {
|
let label = {
|
||||||
let dir_type = port_info.dir_type.to_string();
|
let dir_type = port_info.dir_type.to_string();
|
||||||
|
|
||||||
|
// vhdl 转成 verilog
|
||||||
|
let dir_type = match dir_type.as_str() {
|
||||||
|
"out" => "output",
|
||||||
|
"in" => "input",
|
||||||
|
_ => &dir_type
|
||||||
|
};
|
||||||
|
|
||||||
if dir_type == "output" {
|
if dir_type == "output" {
|
||||||
format!("{}", dir_type)
|
format!("{}", dir_type)
|
||||||
} else {
|
} else {
|
||||||
@ -148,6 +151,28 @@ fn make_instport_hints(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let language_id = get_language_id_by_path_str(&def_path);
|
||||||
|
|
||||||
|
let port_desc_value = match file_type.as_str() {
|
||||||
|
"common" => {
|
||||||
|
format!("```{}\n{}\n```", language_id, port_info.to_description())
|
||||||
|
}
|
||||||
|
"ip" => {
|
||||||
|
// TODO: 支持更多的 IP
|
||||||
|
format!("```verilog\n{}\n```", port_info.vhdl_to_vlog_description())
|
||||||
|
}
|
||||||
|
"primitives" => {
|
||||||
|
format!("```{}\n{}\n```", language_id, port_info.to_description())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
format!("```{}\n{}\n```", language_id, port_info.to_description())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let port_desc = MarkupContent {
|
||||||
|
kind: MarkupKind::Markdown,
|
||||||
|
value: port_desc_value
|
||||||
|
};
|
||||||
|
|
||||||
let hint = InlayHint {
|
let hint = InlayHint {
|
||||||
position: hint_position,
|
position: hint_position,
|
||||||
|
@ -255,6 +255,23 @@ fn do_vhdl_fast(
|
|||||||
};
|
};
|
||||||
hdl_param.update_fast(path.to_string(), ip_fast.clone());
|
hdl_param.update_fast(path.to_string(), ip_fast.clone());
|
||||||
return Ok(ip_fast);
|
return Ok(ip_fast);
|
||||||
|
} else if let Some(design_file) = vhdl_parse(&pathbuf) {
|
||||||
|
if let Some(mut fast) = make_fast_from_design_file(&design_file) {
|
||||||
|
fast.file_type = file_type.to_string();
|
||||||
|
// IP 不需要内部的 instance,其实现是加密的,只需要暴露 module 的接口即可
|
||||||
|
// 所以此处需要清空所有的 module 中的 instance
|
||||||
|
for module in &mut fast.content {
|
||||||
|
module.instances.clear();
|
||||||
|
}
|
||||||
|
hdl_param.update_fast(path.to_string(), fast.clone());
|
||||||
|
return Ok(fast);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(tower_lsp::jsonrpc::Error {
|
||||||
|
code: tower_lsp::jsonrpc::ErrorCode::ParseError,
|
||||||
|
message: Cow::Owned(format!("error happen when parse {path} in [do_vhdl_fast]")),
|
||||||
|
data: None
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -264,9 +281,6 @@ fn do_vhdl_fast(
|
|||||||
// 没有特殊情况,则正常解析并写入
|
// 没有特殊情况,则正常解析并写入
|
||||||
if let Some(design_file) = vhdl_parse(&pathbuf) {
|
if let Some(design_file) = vhdl_parse(&pathbuf) {
|
||||||
if let Some(mut fast) = make_fast_from_design_file(&design_file) {
|
if let Some(mut fast) = make_fast_from_design_file(&design_file) {
|
||||||
if path.contains("ip") {
|
|
||||||
info!("vhdl fast: {:?}", fast);
|
|
||||||
}
|
|
||||||
fast.file_type = file_type.to_string();
|
fast.file_type = file_type.to_string();
|
||||||
hdl_param.update_fast(path.to_string(), fast.clone());
|
hdl_param.update_fast(path.to_string(), fast.clone());
|
||||||
return Ok(fast);
|
return Ok(fast);
|
||||||
|
@ -69,29 +69,15 @@ pub enum LogLevel {
|
|||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct ProjectConfig {
|
pub struct ProjectConfig {
|
||||||
// if true, recursively search the working directory for files to run diagnostics on
|
pub workspace_folder: Option<Url>,
|
||||||
pub auto_search_workdir: bool,
|
pub tool_chain: String
|
||||||
// list of directories with header files
|
|
||||||
pub include_dirs: Vec<String>,
|
|
||||||
// list of directories to recursively search for SystemVerilog/Verilog sources
|
|
||||||
pub source_dirs: Vec<String>,
|
|
||||||
// config options for verible tools
|
|
||||||
pub verible: Verible,
|
|
||||||
// config options for verilator tools
|
|
||||||
pub verilator: Verilator,
|
|
||||||
// log level
|
|
||||||
pub log_level: LogLevel,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ProjectConfig {
|
impl Default for ProjectConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
ProjectConfig {
|
ProjectConfig {
|
||||||
auto_search_workdir: true,
|
workspace_folder: None,
|
||||||
include_dirs: Vec::new(),
|
tool_chain: "xilinx".to_string()
|
||||||
source_dirs: Vec::new(),
|
|
||||||
verible: Verible::default(),
|
|
||||||
verilator: Verilator::default(),
|
|
||||||
log_level: LogLevel::Info,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,15 +156,23 @@ impl Default for VeribleFormat {
|
|||||||
|
|
||||||
#[tower_lsp::async_trait]
|
#[tower_lsp::async_trait]
|
||||||
impl LanguageServer for Backend {
|
impl LanguageServer for Backend {
|
||||||
async fn initialize(&self, _: InitializeParams) -> Result<InitializeResult> {
|
async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
|
||||||
self.server.srcs.init();
|
|
||||||
|
|
||||||
// 申明 LSP 的基本信息和提供的能力
|
// 申明 LSP 的基本信息和提供的能力
|
||||||
let server_info = Some(ServerInfo {
|
let server_info = Some(ServerInfo {
|
||||||
name: "Digital IDE 专用 LSP 后端服务器".to_string(),
|
name: "Digital IDE 专用 LSP 后端服务器".to_string(),
|
||||||
version: Some("0.4.0".to_string())
|
version: Some("0.4.0".to_string())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let root_uri = ¶ms.root_uri;
|
||||||
|
if root_uri.is_none() {
|
||||||
|
self.client.show_message(MessageType::ERROR, "LSP 启动失败,原因: 没有找到启动的 workspaceFolder").await;
|
||||||
|
return Ok(InitializeResult::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut configure = self.server.conf.write().unwrap();
|
||||||
|
configure.workspace_folder = root_uri.clone();
|
||||||
|
info!("当前客户端配置 workspaceFolder: {:?}", params.root_uri);
|
||||||
|
|
||||||
let text_document_sync = TextDocumentSyncCapability::Options(
|
let text_document_sync = TextDocumentSyncCapability::Options(
|
||||||
TextDocumentSyncOptions {
|
TextDocumentSyncOptions {
|
||||||
open_close: Some(true),
|
open_close: Some(true),
|
||||||
@ -239,18 +233,30 @@ impl LanguageServer for Backend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn did_open(&self, params: DidOpenTextDocumentParams) {
|
async fn did_open(&self, params: DidOpenTextDocumentParams) {
|
||||||
let diagnostics = self.server.did_open(params);
|
// // 如果文件太大则显示错误
|
||||||
self.client
|
// if CacheManager::uri_is_big_file(¶ms.text_document.uri) {
|
||||||
.publish_diagnostics(
|
// self.client.show_message(MessageType::WARNING, "考虑到性能问题,对于大于 1MB 的文件不会主动提供语言服务")
|
||||||
diagnostics.uri,
|
// .await;
|
||||||
diagnostics.diagnostics,
|
// } else {
|
||||||
diagnostics.version,
|
let diagnostics = self.server.did_open(params);
|
||||||
)
|
self.client
|
||||||
.await;
|
.publish_diagnostics(
|
||||||
|
diagnostics.uri,
|
||||||
|
diagnostics.diagnostics,
|
||||||
|
diagnostics.version,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn did_change(&self, params: DidChangeTextDocumentParams) {
|
async fn did_change(&self, params: DidChangeTextDocumentParams) {
|
||||||
self.server.did_change(params);
|
// // 如果文件太大则显示错误
|
||||||
|
// if CacheManager::uri_is_big_file(¶ms.text_document.uri) {
|
||||||
|
// // self.client.show_message(MessageType::WARNING, "考虑到性能问题,对于大于 1MB 的文件不会主动提供语言服务")
|
||||||
|
// // .await;
|
||||||
|
// } else {
|
||||||
|
self.server.did_change(params);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn did_delete_files(&self, params: DeleteFilesParams) {
|
async fn did_delete_files(&self, params: DeleteFilesParams) {
|
||||||
@ -258,14 +264,18 @@ impl LanguageServer for Backend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn did_save(&self, params: DidSaveTextDocumentParams) {
|
async fn did_save(&self, params: DidSaveTextDocumentParams) {
|
||||||
let diagnostics = self.server.did_save(params);
|
// if CacheManager::uri_is_big_file(¶ms.text_document.uri) {
|
||||||
self.client
|
|
||||||
.publish_diagnostics(
|
// } else {
|
||||||
diagnostics.uri,
|
let diagnostics = self.server.did_save(params);
|
||||||
diagnostics.diagnostics,
|
self.client
|
||||||
diagnostics.version,
|
.publish_diagnostics(
|
||||||
)
|
diagnostics.uri,
|
||||||
.await;
|
diagnostics.diagnostics,
|
||||||
|
diagnostics.version,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn completion(&self, params: CompletionParams) -> Result<Option<CompletionResponse>> {
|
async fn completion(&self, params: CompletionParams) -> Result<Option<CompletionResponse>> {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::core::cache_storage::CacheManager;
|
||||||
use crate::core::hdlparam::HdlParam;
|
use crate::core::hdlparam::HdlParam;
|
||||||
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_design_file;
|
use crate::core::vhdl_parser::make_fast_from_design_file;
|
||||||
@ -237,35 +238,10 @@ impl Sources {
|
|||||||
fast_sync_controller: Arc::new(RwLock::new(HashMap::<String, Arc<RwLock<bool>>>::new()))
|
fast_sync_controller: Arc::new(RwLock::new(HashMap::<String, Arc<RwLock<bool>>>::new()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn init(&self) {
|
|
||||||
let mut paths: Vec<PathBuf> = Vec::new();
|
|
||||||
for path in &*self.include_dirs.read().unwrap() {
|
|
||||||
paths.push(path.clone());
|
|
||||||
}
|
|
||||||
for path in &*self.source_dirs.read().unwrap() {
|
|
||||||
paths.push(path.clone());
|
|
||||||
}
|
|
||||||
// find and add all source/header files recursively from configured include and source directories
|
|
||||||
let src_paths = find_src_paths(&paths);
|
|
||||||
|
|
||||||
for path in src_paths {
|
|
||||||
let url = unwrap_result!(Url::from_file_path(&path));
|
|
||||||
let text = unwrap_result!(fs::read_to_string(&path));
|
|
||||||
let doc = TextDocumentItem::new(
|
|
||||||
url,
|
|
||||||
"systemverilog".to_string(),
|
|
||||||
-1,
|
|
||||||
text,
|
|
||||||
);
|
|
||||||
self.add(doc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 增加一个 hdl 文件,并为该文件添加单独的解析线程
|
/// 增加一个 hdl 文件,并为该文件添加单独的解析线程
|
||||||
pub fn add(&self, doc: TextDocumentItem) {
|
pub fn add(&self, doc: TextDocumentItem) {
|
||||||
// use a condvar to synchronize the parse thread
|
// 对于当前的文件增加一个解析线程,不断进行解析和同步
|
||||||
// the valid bool decides whether or not the file
|
|
||||||
// needs to be re-parsed
|
|
||||||
#[allow(clippy::mutex_atomic)] // https://github.com/rust-lang/rust-clippy/issues/1516
|
#[allow(clippy::mutex_atomic)] // https://github.com/rust-lang/rust-clippy/issues/1516
|
||||||
let valid_parse = Arc::new((Mutex::new(false), Condvar::new()));
|
let valid_parse = Arc::new((Mutex::new(false), Condvar::new()));
|
||||||
let valid_parse2 = valid_parse.clone();
|
let valid_parse2 = valid_parse.clone();
|
||||||
@ -689,8 +665,10 @@ pub fn vhdl_parser_pipeline(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut file = source_handle.write().unwrap();
|
// TODO: 通过更加精细的方法获取下面的变量
|
||||||
|
|
||||||
|
|
||||||
|
let mut file = source_handle.write().unwrap();
|
||||||
let mut scope_tree = if let Some(design_file) = vhdl_parse(&escape_path) {
|
let mut scope_tree = if let Some(design_file) = vhdl_parse(&escape_path) {
|
||||||
//let mut design_files = design_file_handle.write().unwrap();
|
//let mut design_files = design_file_handle.write().unwrap();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user