use crate::core::cache_storage::CacheManager; use crate::diagnostics::{DigitalLinterConfiguration, DigitalLinterMode, ModelsimConfiguration, VeribleConfiguration, VerilatorConfiguration, VivadoConfiguration}; use crate::sources::*; use crate::completion::{keyword::*, provide_vlog_sys_tasks_completions}; use flexi_logger::LoggerHandle; #[allow(unused)] use log::{debug, info, warn}; use serde::{Deserialize, Serialize}; use std::string::ToString; use std::sync::{Arc, Mutex, RwLock}; use tower_lsp::jsonrpc::Result; use tower_lsp::lsp_types::*; use tower_lsp::{Client, LanguageServer}; pub struct LspServer { /// 文件和 ast 相关的 pub srcs: Sources, /// 缓存 pub cache: CacheManager, /// verilog 关键词的自动补全 pub vlog_keyword_completion_items: Vec, /// verilog 的系统调用的自动补全 pub vlog_sys_tasks_completion_items: Vec, /// verilog 的所有宏的自动补全 pub vlog_directives: Vec, /// vhdl 关键词的自动补全 pub vhdl_keyword_completiom_items: Vec, /// 相关的配置项目 pub configuration: Arc>, #[allow(unused)] pub log_handle: Mutex>, } 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), vlog_keyword_completion_items: keyword_completions(VLOG_KEYWORDS), vhdl_keyword_completiom_items: keyword_completions(VHDL_KEYWORDS), vlog_sys_tasks_completion_items: provide_vlog_sys_tasks_completions(), vlog_directives: other_completions(DIRECTIVES), configuration: Arc::new(RwLock::new(LspConfiguration::default())), log_handle: Mutex::new(log_handle), } } } pub struct Backend { pub client: Client, pub server: LspServer } impl Backend { pub fn new(client: Client, log_handle: LoggerHandle) -> Backend { Backend { client, server: LspServer::new(Some(log_handle)), } } } #[derive(strum_macros::Display, Debug, Serialize, Deserialize)] pub enum LogLevel { #[strum(serialize = "error")] Error, #[strum(serialize = "warn")] Warn, #[strum(serialize = "info")] Info, #[strum(serialize = "debug")] Debug, #[strum(serialize = "trace")] Trace, } #[derive(Debug, Serialize, Deserialize)] #[serde(default)] pub struct LspConfiguration { // 用户工作目录的路径 pub workspace_folder: Option, // 插件安装的根路径 pub extension_path: String, // 当前工具链 pub tool_chain: String, // if true, recursively search the working directory for files to run diagnostics on pub auto_search_workdir: bool, // list of directories with header files pub include_dirs: Vec, // list of directories to recursively search for SystemVerilog/Verilog sources pub source_dirs: Vec, // 下方是和 linter 相关的配置 // 诊断模式 pub linter_mode: DigitalLinterMode, // vlog 的诊断配置 pub vlog_linter_configuration: DigitalLinterConfiguration, // vhdl 的诊断配置 pub vhdl_linter_configuration: DigitalLinterConfiguration, // svlog 的诊断配置 pub svlog_linter_configuration: DigitalLinterConfiguration, // log level pub log_level: LogLevel } impl Default for LspConfiguration { fn default() -> Self { LspConfiguration { workspace_folder: None, extension_path: "".to_string(), tool_chain: "xilinx".to_string(), auto_search_workdir: true, include_dirs: Vec::new(), source_dirs: Vec::new(), linter_mode: DigitalLinterMode::FULL, vlog_linter_configuration: DigitalLinterConfiguration::new("verilog"), vhdl_linter_configuration: DigitalLinterConfiguration::new("vhdl"), svlog_linter_configuration: DigitalLinterConfiguration::new("systemverilog"), log_level: LogLevel::Info, } } } #[tower_lsp::async_trait] impl LanguageServer for Backend { async fn initialize(&self, params: InitializeParams) -> Result { // 申明 LSP 的基本信息和提供的能力 let mut version = "0.4.0".to_string(); let root_uri = ¶ms.root_uri; let mut configure = self.server.configuration.write().unwrap(); configure.workspace_folder = root_uri.clone(); if let Some(serde_json::Value::Object(options)) = params.initialization_options { let extension_path = options.get("extensionPath").unwrap().as_str().unwrap(); let tool_chain = options.get("toolChain").unwrap().as_str().unwrap(); version = options.get("version").unwrap().as_str().unwrap().to_string(); configure.tool_chain = tool_chain.to_string(); configure.extension_path = extension_path.to_string(); } let server_info = Some(ServerInfo { name: "Digital IDE 专用 LSP 后端服务器".to_string(), version: Some(version.to_string()) }); info!("当前客户端初始化结果"); info!("workspaceFolder: {:?}", configure.workspace_folder); info!("extensionPath: {:?}", configure.extension_path); info!("toolChain: {:?}", configure.tool_chain); // 初始化原语系统 self.server.srcs.init_primitive( &configure.tool_chain, &configure.extension_path ); self.server.srcs.init_vhdl_project(&configure.extension_path); // 初始化系统缓存路径 self.server.cache.start(&version); let text_document_sync = TextDocumentSyncCapability::Options( TextDocumentSyncOptions { open_close: Some(true), change: Some(TextDocumentSyncKind::INCREMENTAL), will_save: None, will_save_wait_until: None, save: Some(TextDocumentSyncSaveOptions::SaveOptions(SaveOptions { include_text: None, })), } ); let completion_provider = CompletionOptions { resolve_provider: Some(false), trigger_characters: Some(vec![ ".".to_string(), "$".to_string(), "`".to_string(), "\"".to_string(), "/".to_string() ]), work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None, }, all_commit_characters: None, // TODO: 检查这里的选项 completion_item: None, }; let workspace = WorkspaceServerCapabilities { workspace_folders: Some(WorkspaceFoldersServerCapabilities { supported: Some(true), change_notifications: Some(OneOf::Left(true)), }), ..Default::default() }; let capabilities = ServerCapabilities { text_document_sync: Some(text_document_sync), completion_provider: Some(completion_provider), definition_provider: Some(OneOf::Left(true)), hover_provider: Some(HoverProviderCapability::Simple(true)), inlay_hint_provider: Some(OneOf::Left(true)), document_symbol_provider: Some(OneOf::Left(true)), document_highlight_provider: Some(OneOf::Left(true)), workspace: Some(workspace), code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), ..ServerCapabilities::default() }; Ok(InitializeResult { server_info, capabilities, offset_encoding: None }) } async fn initialized(&self, _: InitializedParams) { self.client .log_message(MessageType::INFO, "Digital LSP initialized!") .await; } async fn shutdown(&self) -> Result<()> { Ok(()) } async fn did_open(&self, params: DidOpenTextDocumentParams) { // // 如果文件太大则显示错误 // if CacheManager::uri_is_big_file(¶ms.text_document.uri) { // self.client.show_message(MessageType::WARNING, "考虑到性能问题,对于大于 1MB 的文件不会主动提供语言服务") // .await; // } else { let diagnostics = self.server.did_open(params); self.client.publish_diagnostics( diagnostics.uri, diagnostics.diagnostics, diagnostics.version, ) .await; // } } async fn did_change(&self, params: DidChangeTextDocumentParams) { // // 如果文件太大则显示错误 // 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) { self.server.did_delete_files(params); } async fn did_save(&self, params: DidSaveTextDocumentParams) { // if CacheManager::uri_is_big_file(¶ms.text_document.uri) { // } else { let diagnostics = self.server.did_save(params); self.client .publish_diagnostics( diagnostics.uri, diagnostics.diagnostics, diagnostics.version, ) .await; // } } async fn completion(&self, params: CompletionParams) -> Result> { Ok(self.server.completion(params)) } async fn goto_definition( &self, params: GotoDefinitionParams, ) -> Result> { Ok(self.server.goto_definition(params)) } async fn hover(&self, params: HoverParams) -> Result> { Ok(self.server.hover(params)) } async fn formatting(&self, params: DocumentFormattingParams) -> Result>> { Ok(self.server.formatting(params)) } async fn range_formatting( &self, params: DocumentRangeFormattingParams, ) -> Result>> { Ok(self.server.range_formatting(params)) } async fn document_symbol( &self, params: DocumentSymbolParams, ) -> Result> { Ok(self.server.document_symbol(params)) } async fn document_highlight( &self, params: DocumentHighlightParams, ) -> Result>> { Ok(self.server.document_highlight(params)) } async fn inlay_hint( &self, params: InlayHintParams ) -> Result>> { Ok(self.server.inlay_hint(params)) } async fn code_lens( &self, params: CodeLensParams ) -> Result>> { Ok(self.server.code_lens(params)) } }