diff --git a/Cargo.lock b/Cargo.lock index d6f3413..83c98a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,12 +99,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "anyhow" -version = "1.0.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" - [[package]] name = "async-trait" version = "0.1.72" @@ -332,8 +326,8 @@ dependencies = [ name = "digital-lsp" version = "0.0.1" dependencies = [ - "anyhow", "bincode", + "dirs-next", "flexi_logger", "log", "path-clean", @@ -351,10 +345,8 @@ dependencies = [ "tempdir", "tokio", "tower-lsp", - "uuid", "vhdl_lang", "walkdir", - "which", ] [[package]] @@ -366,6 +358,16 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + [[package]] name = "dirs-sys" version = "0.4.1" @@ -378,6 +380,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dunce" version = "1.0.5" @@ -416,16 +429,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "flexi_logger" version = "0.29.0" @@ -603,15 +606,6 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "httparse" version = "1.8.0" @@ -713,12 +707,6 @@ dependencies = [ "libc", ] -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - [[package]] name = "lock_api" version = "0.4.10" @@ -1171,19 +1159,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustix" -version = "0.38.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" -dependencies = [ - "bitflags 2.4.2", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - [[package]] name = "rustversion" version = "1.0.14" @@ -1729,15 +1704,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" -dependencies = [ - "getrandom", -] - [[package]] name = "vec_map" version = "0.8.2" @@ -1849,19 +1815,6 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" -[[package]] -name = "which" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fa5e0c10bf77f44aac573e498d1a82d5fbd5e91f6fc0a99e7be4b38e85e101c" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", - "windows-sys 0.52.0", -] - [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index e204fc3..06f1401 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] sv-parser = { version = "0.13.3", path = "sv-parser/sv-parser"} vhdl_lang = { version = "^0.83.0", path = "rust_hdl/vhdl_lang" } -uuid = { version = "1.0", features = ["v4"] } +dirs-next = "2.0" bincode = "1.3" percent-encoding = "2.1.0" log = "0.4.19" @@ -21,8 +21,6 @@ walkdir = "2.3.3" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_yaml = "0.9.25" -anyhow = "1.0.72" -which = "6.0.0" regex = "1.9.1" structopt = "0.3.26" strum = "0.26.1" diff --git a/src/core/cache_storage.rs b/src/core/cache_storage.rs index 0cf70f8..4636c70 100644 --- a/src/core/cache_storage.rs +++ b/src/core/cache_storage.rs @@ -1,9 +1,10 @@ -use std::{collections::HashMap, fs::{self, File}, io::Read, path::PathBuf, str::FromStr, sync::{Arc, RwLock}}; +use core::hash; +use std::{borrow::{Borrow, Cow}, collections::HashMap, fs::{self}, hash::{DefaultHasher, Hash, Hasher}, os::unix::thread, path::PathBuf, sync::{Arc, RwLock}}; use log::info; use serde::{Deserialize, Serialize}; -use crate::utils::{file_size_in_kb, get_last_modified_time, k_deserialize}; +use crate::utils::{file_size_in_kb, get_last_modified_time, k_deserialize, k_serialize}; use super::hdlparam::FastHdlparam; @@ -16,7 +17,7 @@ pub enum CacheResult { Error(String) } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct CacheItem { /// 文件名字 pub file_name: String, @@ -40,11 +41,9 @@ pub struct CacheManager { } - impl CacheManager { - pub fn new(root_dir: &str) -> Self { + pub fn new(root_dir: PathBuf) -> Self { // 读入 meta 文件 - let root_dir = PathBuf::from_str(root_dir).unwrap(); let meta_name = "index.cache"; let meta_path = root_dir.join(meta_name); let meta = get_or_init_meta(&meta_path); @@ -106,8 +105,45 @@ impl CacheManager { CacheResult::CacheNotFound } - pub fn update_cache() { + pub fn get_uuid_cache_name(&self, path_string: String) -> String { + // 采用 sip 哈希算法计算哈希 + let mut hasher = DefaultHasher::new(); + path_string.hash(&mut hasher); + let hash_value = hasher.finish(); + let hash_string = format!("{:x}", hash_value); + let mut hash_string: String = hash_string.chars().take(32).collect(); + hash_string.push_str(".cache"); + hash_string + } + pub fn update_cache(&self, path: &PathBuf, fast: FastHdlparam) { + let path_string = path.to_str().unwrap(); + let version = self.get_version(path); + let size = file_size_in_kb(path_string).unwrap(); + let file_name = path.file_name().unwrap().to_str().unwrap().to_string(); + let cache_name = self.get_uuid_cache_name(path_string.to_string()); + let cache_item = CacheItem { + file_name, + version, + size, + cache_name: cache_name.clone() + }; + + let mut meta_handle = self.meta.write().unwrap(); + meta_handle.insert(path_string.to_string(), cache_item); + + // 准备必要的独立数据塞入线程进行调度 + let meta = (&*meta_handle).clone(); + let meta_save_path = self.root_dir.join(self.meta_name.clone()); + let cache_save_path = self.root_dir.join(cache_name); + + std::thread::spawn(move || { + info!("save meta to {meta_save_path:?}"); + k_serialize(&meta_save_path, meta); + + info!("save index to {cache_save_path:?}"); + k_serialize(&cache_save_path, fast); + }); } } diff --git a/src/core/sv_parser.rs b/src/core/sv_parser.rs index c79e931..f1d4e30 100644 --- a/src/core/sv_parser.rs +++ b/src/core/sv_parser.rs @@ -2,7 +2,6 @@ use std::fs::{self, File}; use std::io::BufRead; use std::io::BufReader; use std::path::PathBuf; -use anyhow::Error; use regex::Regex; use ropey::Rope; use tower_lsp::lsp_types::Url; @@ -38,7 +37,7 @@ pub fn sv_parser(path: &str) -> Option { None } -pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Result { +pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> Result { // 对不同操作系统文件路径的支持 let path = to_escape_path(path); diff --git a/src/hover/feature.rs b/src/hover/feature.rs index 1e9ed94..58573b7 100644 --- a/src/hover/feature.rs +++ b/src/hover/feature.rs @@ -346,7 +346,7 @@ pub fn hover_module_declaration( let port_num = module.ports.len(); let param_num = module.params.len(); let instance_num = module.instances.len(); - let port_desc = format!("`$(instance-param) ` {port_num}, `param` {param_num}, `instantiation` {instance_num}"); + let port_desc = format!("`port` {port_num}, `param` {param_num}, `instantiation` {instance_num}"); // 统计 dir let mut input_count = 0 as u32; diff --git a/src/request/mod.rs b/src/request/mod.rs index 9a365ae..bf4a1ff 100644 --- a/src/request/mod.rs +++ b/src/request/mod.rs @@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize}; use tower_lsp::jsonrpc::Result; use tower_lsp::lsp_types::*; +use crate::core::cache_storage::CacheResult; use crate::core::hdlparam::FastHdlparam; use crate::core::sv_parser::make_fast_from_syntaxtree; @@ -92,18 +93,50 @@ pub fn do_fast<'a>(path: String, backend: &Arc) -> Result info!("parse fast \"{}\"", path); let language_id = get_language_id_by_path_str(&path); - let res = match language_id.as_str() { - "vhdl" => do_vhdl_fast(&path, backend), - "verilog" | "systemverilog" => do_sv_fast(&path, backend), - _ => Err(tower_lsp::jsonrpc::Error { - code: tower_lsp::jsonrpc::ErrorCode::InvalidRequest, - message: Cow::Owned(format!("invalid file: {path}, expect vhdl, verilog or system verilog!")), - data: None - }) + + let parse_fast_by_language_id = |language_id: &str| { + match language_id { + "vhdl" => { + do_vhdl_fast(&path, backend) + } + + "verilog" | "systemverilog" => { + do_sv_fast(&path, backend) + } + + _ => Err(tower_lsp::jsonrpc::Error { + code: tower_lsp::jsonrpc::ErrorCode::InvalidRequest, + message: Cow::Owned(format!("invalid file: {path}, expect vhdl, verilog or system verilog!")), + data: None + }) + } }; - info!("finish parse"); - res + let path_buf = PathBuf::from_str(&path).unwrap(); + // 做缓存优化 + let cache = &backend.server.cache; + match cache.try_get_fast_cache(&path_buf) { + // 找到缓存,直接返回 + CacheResult::Ok(fast) => { + return Ok(fast); + } + + // cache 没找到,那么就需要计算并存入 + CacheResult::CacheNotFound => { + match parse_fast_by_language_id(&language_id) { + Ok(fast) => { + cache.update_cache(&path_buf, fast.clone()); + return Ok(fast); + }, + Err(err) => Err(err) + } + } + + // 不需要缓存的文件正常进行 fast 计算即可 + _ => { + parse_fast_by_language_id(&language_id) + } + } } fn do_sv_fast(path: &str, backend: &Arc) -> Result { diff --git a/src/server.rs b/src/server.rs index 3bdf3f6..94eb0e2 100644 --- a/src/server.rs +++ b/src/server.rs @@ -6,12 +6,13 @@ use flexi_logger::LoggerHandle; use log::{debug, info, warn}; use serde::{Deserialize, Serialize}; use std::string::ToString; -use std::sync::{Arc, Mutex, RwLock}; +use std::sync::{Mutex, RwLock}; use tower_lsp::jsonrpc::Result; use tower_lsp::lsp_types::*; use tower_lsp::{Client, LanguageServer}; pub struct LSPServer { pub srcs: Sources, + pub cache: CacheManager, pub key_comps: Vec, pub sys_tasks: Vec, pub directives: Vec, @@ -22,8 +23,11 @@ pub struct LSPServer { impl LSPServer { pub fn new(log_handle: Option) -> LSPServer { + let user_home = dirs_next::home_dir().unwrap(); + let dide_home = user_home.join(".digital-ide"); LSPServer { srcs: Sources::new(), + cache: CacheManager::new(dide_home), key_comps: keyword_completions(KEYWORDS), sys_tasks: other_completions(SYS_TASKS), directives: other_completions(DIRECTIVES), @@ -166,9 +170,8 @@ impl Default for VeribleFormat { #[tower_lsp::async_trait] impl LanguageServer for Backend { - async fn initialize(&self, params: InitializeParams) -> Result { + async fn initialize(&self, _: InitializeParams) -> Result { self.server.srcs.init(); - // params.client_info.unwrap().name // 申明 LSP 的基本信息和提供的能力 let server_info = Some(ServerInfo { diff --git a/src/sources.rs b/src/sources.rs index afad191..6fa3865 100644 --- a/src/sources.rs +++ b/src/sources.rs @@ -448,7 +448,7 @@ pub fn recovery_sv_parse( return Some(syntax_tree); } Err(err) => { - println!("err: {err:?}"); + // println!("err: {err:?}"); match err { // 语法错误 sv_parser::Error::Parse(trace) => match trace {