2024-12-10 00:08:46 +08:00

335 lines
11 KiB
Rust

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<CompletionItem>,
/// verilog 的系统调用的自动补全
pub vlog_sys_tasks_completion_items: Vec<CompletionItem>,
/// verilog 的所有宏的自动补全
pub vlog_directives: Vec<CompletionItem>,
/// vhdl 关键词的自动补全
pub vhdl_keyword_completiom_items: Vec<CompletionItem>,
/// 相关的配置项目
pub configuration: Arc<RwLock<LspConfiguration>>,
#[allow(unused)]
pub log_handle: Mutex<Option<LoggerHandle>>,
}
impl LspServer {
pub fn new(log_handle: Option<LoggerHandle>) -> 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<Url>,
// 插件安装的根路径
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<String>,
// list of directories to recursively search for SystemVerilog/Verilog sources
pub source_dirs: Vec<String>,
// 下方是和 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<InitializeResult> {
// 申明 LSP 的基本信息和提供的能力
let mut version = "0.4.0".to_string();
let root_uri = &params.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(&params.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(&params.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(&params.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<Option<CompletionResponse>> {
Ok(self.server.completion(params))
}
async fn goto_definition(
&self,
params: GotoDefinitionParams,
) -> Result<Option<GotoDefinitionResponse>> {
Ok(self.server.goto_definition(params))
}
async fn hover(&self, params: HoverParams) -> Result<Option<Hover>> {
Ok(self.server.hover(params))
}
async fn formatting(&self, params: DocumentFormattingParams) -> Result<Option<Vec<TextEdit>>> {
Ok(self.server.formatting(params))
}
async fn range_formatting(
&self,
params: DocumentRangeFormattingParams,
) -> Result<Option<Vec<TextEdit>>> {
Ok(self.server.range_formatting(params))
}
async fn document_symbol(
&self,
params: DocumentSymbolParams,
) -> Result<Option<DocumentSymbolResponse>> {
Ok(self.server.document_symbol(params))
}
async fn document_highlight(
&self,
params: DocumentHighlightParams,
) -> Result<Option<Vec<DocumentHighlight>>> {
Ok(self.server.document_highlight(params))
}
async fn inlay_hint(
&self,
params: InlayHintParams
) -> Result<Option<Vec<InlayHint>>> {
Ok(self.server.inlay_hint(params))
}
async fn code_lens(
&self,
params: CodeLensParams
) -> Result<Option<Vec<CodeLens>>> {
Ok(self.server.code_lens(params))
}
}