diff --git a/Cargo.lock b/Cargo.lock index 0ea5b44..8ac993a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,6 +206,7 @@ dependencies = [ "anyhow", "flexi_logger", "log", + "once_cell", "path-clean", "pathdiff", "regex", diff --git a/Cargo.toml b/Cargo.toml index b55a2b6..f02bb9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] sv-parser = { version = "0.13.3", path = "sv-parser/sv-parser"} +once_cell = "1.8" log = "0.4.19" tower-lsp = "0.20.0" flexi_logger = "0.29.0" diff --git a/src/completion.rs b/src/completion.rs index 7426abe..e1d8aeb 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -239,7 +239,7 @@ endmodule text: text.to_owned(), }, }; - server.did_open(open_params); + server.did_open(open_params, None); let fid = server.srcs.get_id(&uri); server.srcs.wait_parse_ready(fid, true); @@ -357,7 +357,7 @@ endmodule text: text.to_owned(), }, }; - server.did_open(open_params); + server.did_open(open_params, None); let fid = server.srcs.get_id(&uri); server.srcs.wait_parse_ready(fid, true); @@ -477,7 +477,7 @@ endmodule text: text.to_owned(), }, }; - server.did_open(open_params); + server.did_open(open_params, None); let fid = server.srcs.get_id(&uri); server.srcs.wait_parse_ready(fid, true); let file = server.srcs.get_file(fid).unwrap(); @@ -566,7 +566,7 @@ endmodule text: text.to_owned(), }, }; - server.did_open(open_params); + server.did_open(open_params, None); let fid = server.srcs.get_id(&uri); server.srcs.wait_parse_ready(fid, true); let file = server.srcs.get_file(fid).unwrap(); @@ -738,8 +738,8 @@ endinterface"#; text: text2.to_owned(), }, }; - server.did_open(open_params); - server.did_open(open_params2); + server.did_open(open_params, None); + server.did_open(open_params2, None); let fid = server.srcs.get_id(&uri); let fid2 = server.srcs.get_id(&uri2); server.srcs.wait_parse_ready(fid, true); diff --git a/src/core/fast_hdlparam.rs b/src/core/fast_hdlparam.rs index 7be3c17..e87be35 100644 --- a/src/core/fast_hdlparam.rs +++ b/src/core/fast_hdlparam.rs @@ -1,20 +1,21 @@ -use serde::Serialize; +use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, Serialize, PartialEq)] +#[derive(Debug, Clone, Serialize, PartialEq, Deserialize)] pub struct Position { pub line: u32, pub character: u32 } -#[derive(Debug, Clone, Serialize, PartialEq)] +#[derive(Debug, Clone, Serialize, PartialEq, Deserialize)] pub struct Range { pub start: Position, pub end: Position } -#[derive(Debug, Serialize, PartialEq)] +#[derive(Debug, Serialize, PartialEq, Deserialize)] pub struct Port { pub name: String, + #[serde(rename = "type")] pub dir_type: String, pub net_type: String, pub width: String, @@ -22,7 +23,7 @@ pub struct Port { pub range: Range } -#[derive(Debug, Serialize, PartialEq)] +#[derive(Debug, Serialize, PartialEq, Deserialize)] pub struct Parameter { pub name: String, pub net_type: String, @@ -43,16 +44,17 @@ pub struct Parameter { // pub range: Range // } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct Instance { pub name: String, + #[serde(rename = "type")] pub inst_type: String, pub instparams: Option, pub instports: Option, pub range: Range } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct Module { pub name: String, pub params: Vec, @@ -61,13 +63,13 @@ pub struct Module { pub range: Range } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct DefineParam { pub name: String, pub value: String } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct Define { name: String, replacement: String, @@ -75,13 +77,13 @@ pub struct Define { params: Vec } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct Include { pub path: String, pub range: Range } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct Error { severity: String, message: String, @@ -91,7 +93,7 @@ pub struct Error { running_phase: Option, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct Macro { pub defines: Vec, pub includes: Vec, @@ -99,9 +101,10 @@ pub struct Macro { pub invalid: Vec } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct FastHdlparam { + #[serde(rename = "macro")] pub fast_macro: Macro, pub content: Vec } @@ -227,61 +230,62 @@ impl FastHdlparam { last_module.instances.push(instance); } - pub fn print_fast(&self) { - if self.content.is_empty() { - println!("none module"); - } else { - for module in &self.content { - println!("module {}", module.name); - if !module.params.is_empty() { - println!(" params:"); - for param in &module.params { - println!(" parameter {} {} {}", param.net_type, param.name, param.init); - println!(" range start {} {}", param.range.start.line, param.range.start.character); - println!(" range end {} {}", param.range.end.line, param.range.end.character); - } - } - if !module.ports.is_empty() { - println!(" ports:"); - for port in &module.ports { - if port.width == "1" { - println!(" {} {} {}", port.dir_type, port.net_type, port.name); - } else { - println!(" {} {} {} {}", port.dir_type, port.net_type, port.width, port.name); - } - println!(" range start {} {}", port.range.start.line, port.range.start.character); - println!(" range end {} {}", port.range.end.line, port.range.end.character); - } - } - if !module.instances.is_empty() { - println!(" instances:"); - for instance in &module.instances { - println!(" {} {}", instance.inst_type, instance.name); - if instance.instparams.is_none() { - println!(" params: {:?}", instance.instparams); - } else { - println!(" params:"); - println!(" range start {} {}", instance.instparams.clone().unwrap().start.line, - instance.instparams.clone().unwrap().start.character); - println!(" range end {} {}", instance.instparams.clone().unwrap().end.line, - instance.instparams.clone().unwrap().end.character); - } - if instance.instports.is_none() { - println!(" ports: {:?}", instance.instports); - } else { - println!(" ports:"); - println!(" range start {} {}", instance.instports.clone().unwrap().start.line, - instance.instports.clone().unwrap().start.character); - println!(" range end {} {}", instance.instports.clone().unwrap().end.line, - instance.instports.clone().unwrap().end.character); - } - println!(" range start {} {}", instance.range.start.line, instance.range.start.character); - println!(" range end {} {}", instance.range.end.line, instance.range.end.character); - } - } - println!(" range start {} {}", module.range.start.line, module.range.start.character); - println!(" range end {} {}", module.range.end.line, module.range.end.character); - } - } - } + // pub fn print_fast(&self) { + // if self.content.is_empty() { + // println!("none module"); + // } else { + // for module in &self.content { + // println!("module {}", module.name); + // if !module.params.is_empty() { + // println!(" params:"); + // for param in &module.params { + // println!(" parameter {} {} {}", param.net_type, param.name, param.init); + // println!(" range start {} {}", param.range.start.line, param.range.start.character); + // println!(" range end {} {}", param.range.end.line, param.range.end.character); + // } + // } + // if !module.ports.is_empty() { + // println!(" ports:"); + // for port in &module.ports { + // if port.width == "1" { + // println!(" {} {} {}", port.dir_type, port.net_type, port.name); + // } else { + // println!(" {} {} {} {}", port.dir_type, port.net_type, port.width, port.name); + // } + // println!(" range start {} {}", port.range.start.line, port.range.start.character); + // println!(" range end {} {}", port.range.end.line, port.range.end.character); + // } + // } + // if !module.instances.is_empty() { + // println!(" instances:"); + // for instance in &module.instances { + // println!(" {} {}", instance.inst_type, instance.name); + // if instance.instparams.is_none() { + // println!(" params: {:?}", instance.instparams); + // } else { + // println!(" params:"); + // println!(" range start {} {}", instance.instparams.clone().unwrap().start.line, + // instance.instparams.clone().unwrap().start.character); + // println!(" range end {} {}", instance.instparams.clone().unwrap().end.line, + // instance.instparams.clone().unwrap().end.character); + // } + // if instance.instports.is_none() { + // println!(" ports: {:?}", instance.instports); + // } else { + // println!(" ports:"); + // println!(" range start {} {}", instance.instports.clone().unwrap().start.line, + // instance.instports.clone().unwrap().start.character); + // println!(" range end {} {}", instance.instports.clone().unwrap().end.line, + // instance.instports.clone().unwrap().end.character); + // } + // println!(" range start {} {}", instance.range.start.line, instance.range.start.character); + // println!(" range end {} {}", instance.range.end.line, instance.range.end.character); + // } + // } + // println!(" range start {} {}", module.range.start.line, module.range.start.character); + // println!(" range end {} {}", module.range.end.line, module.range.end.character); + // } + // } + // } + } diff --git a/src/core/sv_parser.rs b/src/core/sv_parser.rs index 89fc381..4038b77 100644 --- a/src/core/sv_parser.rs +++ b/src/core/sv_parser.rs @@ -16,14 +16,14 @@ pub fn sv_parser(path: &str) -> Option { let result = parse_sv(&path, &defines, &includes, false, true); if let Ok((syntax_tree, _)) = result { - let hdlparam = make_fast_from_syntaxtree(syntax_tree, path); + let hdlparam = make_fast_from_syntaxtree(&syntax_tree, &path); return Some(hdlparam); } None } -pub fn make_fast_from_syntaxtree(syntax_tree: SyntaxTree, path: PathBuf) -> FastHdlparam { +pub fn make_fast_from_syntaxtree(syntax_tree: &SyntaxTree, path: &PathBuf) -> FastHdlparam { let mut hdlparam = FastHdlparam { fast_macro: Macro { defines: Vec::new(), @@ -39,7 +39,7 @@ pub fn make_fast_from_syntaxtree(syntax_tree: SyntaxTree, path: PathBuf) -> Fast .map(|s| s.to_string()) .collect::>(); // &SyntaxTree is iterable - for node in &syntax_tree { + for node in syntax_tree { match node { RefNode::TextMacroDefinition(x) => { let start = unwrap_node!(x, TextMacroDefinition).unwrap(); @@ -533,7 +533,7 @@ fn get_identifier(node: RefNode) -> Option { } } -fn get_includes(path: PathBuf) -> Vec { +fn get_includes(path: &PathBuf) -> Vec { let mut includes = Vec::new(); let file = File::open(path).unwrap(); diff --git a/src/custom_request.rs b/src/custom_request.rs index 08d17c0..0b11294 100644 --- a/src/custom_request.rs +++ b/src/custom_request.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; use std::sync::Arc; use log::info; +use notification::Notification; use ropey::Rope; use serde::{Deserialize, Serialize}; use tower_lsp::jsonrpc::Result; @@ -113,7 +114,7 @@ pub fn do_fast(path: String) -> Result { ); if let Some(syntax_tree) = parse_result { - let hdlparam = make_fast_from_syntaxtree(syntax_tree, path_buf); + let hdlparam = make_fast_from_syntaxtree(&syntax_tree, &path_buf); return Ok(hdlparam); } @@ -124,4 +125,23 @@ pub fn do_fast(path: String) -> Result { }; Err(api_error) +} + + + +// 下面是服务端发送给客户端的 +#[derive(Serialize, Deserialize)] +pub struct UpdateFastNotification { + pub fast: FastHdlparam +} + +impl Notification for UpdateFastNotification { + const METHOD: &'static str = "update/fast"; + type Params = Self; +} + +pub fn update_fast_to_client(backend: Arc>, fast: FastHdlparam) { + let backend = backend.unwrap(); + let params = UpdateFastNotification { fast }; + backend.client.send_notification::(params); } \ No newline at end of file diff --git a/src/definition.rs b/src/definition.rs index 49baaba..fc31e74 100644 --- a/src/definition.rs +++ b/src/definition.rs @@ -1,5 +1,3 @@ -use std::path::PathBuf; - use crate::definition::extract_defs::get_ident; use crate::server::LSPServer; use crate::sources::LSPSupport; @@ -164,20 +162,6 @@ pub fn get_language_id_by_uri(uri: &Url) -> String { } } -pub fn get_language_id_by_path(path: &PathBuf) -> String { - let path = path.as_path(); - let ext_name = std::path::Path::new(path) - .extension() - .and_then(std::ffi::OsStr::to_str) - .unwrap_or(""); - - match ext_name { - "vhd" | "vhdl" | "vho" | "vht" => "vhdl".to_string(), - "v" | "V" | "vh" | "vl" => "verilog".to_string(), - "sv" | "svh" => "systemverilog".to_string(), - _ => "plaintext".to_string() - } -} type ScopesAndDefs = Option<(Vec>, Vec>)>; diff --git a/src/definition/def_types.rs b/src/definition/def_types.rs index 0b0b0cf..c8f1352 100644 --- a/src/definition/def_types.rs +++ b/src/definition/def_types.rs @@ -885,7 +885,6 @@ pub struct ClassDec { pub extends: (Vec, Option), // class, package pub implements: Vec<(String, Option)>, - pub interface: bool, } impl ClassDec { @@ -904,7 +903,6 @@ impl ClassDec { scopes: Vec::new(), extends: (Vec::new(), None), implements: Vec::new(), - interface: false, } } } diff --git a/src/server.rs b/src/server.rs index 0ae76aa..a9c9eb5 100644 --- a/src/server.rs +++ b/src/server.rs @@ -9,7 +9,7 @@ use std::fs::File; use std::io::Read; use std::path::PathBuf; use std::string::ToString; -use std::sync::{Mutex, RwLock}; +use std::sync::{Arc, Mutex, RwLock}; use tower_lsp::jsonrpc::{Error, ErrorCode, Result}; use tower_lsp::lsp_types::*; use tower_lsp::{Client, LanguageServer}; @@ -38,10 +38,11 @@ impl LSPServer { } pub struct Backend { - client: Client, - server: LSPServer + pub client: Client, + pub server: LSPServer } + impl Backend { pub fn new(client: Client, log_handle: LoggerHandle) -> Backend { Backend { @@ -215,9 +216,7 @@ impl LanguageServer for Backend { match read_config(params.root_uri) { Ok(conf) => { inc_dirs.extend(conf.include_dirs.iter().filter_map(|x| absolute_path(x))); - debug!("{:#?}", inc_dirs); src_dirs.extend(conf.source_dirs.iter().filter_map(|x| absolute_path(x))); - debug!("{:#?}", src_dirs); let mut log_handle = self.server.log_handle.lock().unwrap(); let log_handle = log_handle.as_mut(); if let Some(handle) = log_handle { @@ -252,7 +251,7 @@ impl LanguageServer for Backend { drop(inc_dirs); drop(src_dirs); // parse all source files found from walking source dirs and include dirs - self.server.srcs.init(); + self.server.srcs.init(Some(&self)); Ok(InitializeResult { server_info: None, capabilities: ServerCapabilities { @@ -278,7 +277,7 @@ impl LanguageServer for Backend { work_done_progress: None, }, all_commit_characters: None, - //TODO: check if corect + // TODO: check if corect completion_item: None, }), definition_provider: Some(OneOf::Left(true)), @@ -296,6 +295,7 @@ impl LanguageServer for Backend { self.client .log_message(MessageType::INFO, "digital lsp initialized!") .await; + } async fn shutdown(&self) -> Result<()> { @@ -303,7 +303,7 @@ impl LanguageServer for Backend { } async fn did_open(&self, params: DidOpenTextDocumentParams) { - let diagnostics = self.server.did_open(params); + let diagnostics = self.server.did_open(params, Some(&self)); self.client .publish_diagnostics( diagnostics.uri, diff --git a/src/sources.rs b/src/sources.rs index d159c7a..584f678 100644 --- a/src/sources.rs +++ b/src/sources.rs @@ -1,6 +1,10 @@ +use crate::core::sv_parser::make_fast_from_syntaxtree; +use crate::custom_request::update_fast_to_client; +use crate::custom_request::UpdateFastNotification; use crate::definition::def_types::*; use crate::definition::get_scopes; use crate::diagnostics::{get_diagnostics, is_hidden}; +use crate::server::Backend; use crate::server::LSPServer; use log::{debug, error}; use pathdiff::diff_paths; @@ -18,11 +22,20 @@ use thread::JoinHandle; use tower_lsp::lsp_types::*; use walkdir::WalkDir; +macro_rules! unwrap_result { + ($expr:expr) => { + match $expr { + Ok(e) => e, + Err(_) => return + } + }; +} + impl LSPServer { - pub fn did_open(&self, params: DidOpenTextDocumentParams) -> PublishDiagnosticsParams { + pub fn did_open(&self, params: DidOpenTextDocumentParams, backend: Option<&Backend>) -> PublishDiagnosticsParams { let document: TextDocumentItem = params.text_document; let uri = document.uri.clone(); - debug!("did_open: {}", &uri); + // check if doc is already added if self.srcs.names.read().unwrap().contains_key(&document.uri) { // convert to a did_change that replace the entire text @@ -35,7 +48,7 @@ impl LSPServer { }], }); } else { - self.srcs.add(document); + self.srcs.add(document, backend); } // diagnostics let urls = self.srcs.names.read().unwrap().keys().cloned().collect(); @@ -160,7 +173,7 @@ impl Sources { source_dirs: Arc::new(RwLock::new(Vec::new())), } } - pub fn init(&self) { + pub fn init(&self, backend: Option<&Backend>) { let mut paths: Vec = Vec::new(); for path in &*self.include_dirs.read().unwrap() { paths.push(path.clone()); @@ -172,21 +185,20 @@ impl Sources { let src_paths = find_src_paths(&paths); for path in src_paths { - if let Ok(url) = Url::from_file_path(&path) { - if let Ok(text) = fs::read_to_string(&path) { - self.add(TextDocumentItem::new( - url, - "systemverilog".to_string(), - -1, - text, - )); - } - } + 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, backend); } } - /// add a source file, creating a parse thread for that file - pub fn add(&self, doc: TextDocumentItem) { + /// 增加一个 hdl 文件,并为该文件添加单独的解析线程 + pub fn add(&self, doc: TextDocumentItem, backend: Option<&Backend>) { // use a condvar to synchronize the parse thread // the valid bool decides whether or not the file // needs to be re-parsed @@ -206,6 +218,8 @@ impl Sources { let scope_handle = self.scope_tree.clone(); let inc_dirs = self.include_dirs.clone(); + let backend = Arc::new(backend); + // spawn parse thread let parse_handle = thread::spawn(move || { let (lock, cvar) = &*valid_parse2; @@ -222,6 +236,13 @@ impl Sources { None => None, }; + // 计算 fast + if let Some(syntax_tree) = &syntax_tree { + let path = PathBuf::from(uri.path().to_string()); + let fast = make_fast_from_syntaxtree(&syntax_tree, &path); + update_fast_to_client(backend.clone(), fast); + } + let mut file = source_handle.write().unwrap(); file.syntax_tree = syntax_tree; @@ -544,7 +565,7 @@ endmodule"#; text: text.to_owned(), }, }; - server.did_open(open_params); + server.did_open(open_params, None); let fid = server.srcs.get_id(&uri); let file = server.srcs.get_file(fid).unwrap(); let file = file.read().unwrap(); @@ -597,7 +618,7 @@ endmodule"#; text: text.to_owned(), }, }; - server.did_open(open_params); + server.did_open(open_params, None); let fid = server.srcs.get_id(&uri); server.srcs.wait_parse_ready(fid, true);