160 lines
4.2 KiB
Rust
160 lines
4.2 KiB
Rust
use crate::syntax_tokens::semantic_tokens;
|
|
use crate::utils::UriUtils;
|
|
use crate::workspace::{Workspace, start_workspace_thread};
|
|
use std::sync::Arc;
|
|
use tokio::sync::RwLock;
|
|
use tower_lsp_server::jsonrpc::Result;
|
|
use tower_lsp_server::ls_types::request::{GotoDeclarationParams, GotoDeclarationResponse};
|
|
use tower_lsp_server::{Client, LspService, Server};
|
|
use tower_lsp_server::{LanguageServer, ls_types::*};
|
|
|
|
mod syntax_tokens;
|
|
mod utils;
|
|
mod workspace;
|
|
|
|
struct Backend {
|
|
client: Client,
|
|
workspaces: RwLock<Vec<Arc<Workspace>>>,
|
|
}
|
|
|
|
impl LanguageServer for Backend {
|
|
async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
|
|
let mut workspaces = self.workspaces.write().await;
|
|
for workspace in workspaces.drain(..) {
|
|
workspace.close().await;
|
|
}
|
|
|
|
for folder in params.workspace_folders.iter().flatten() {
|
|
workspaces
|
|
.push(start_workspace_thread(folder.uri.clone(), self.client.clone()).unwrap());
|
|
}
|
|
|
|
Ok(InitializeResult {
|
|
capabilities: ServerCapabilities {
|
|
hover_provider: Some(HoverProviderCapability::Simple(true)),
|
|
definition_provider: Some(OneOf::Left(true)),
|
|
declaration_provider: Some(DeclarationCapability::Simple(true)),
|
|
text_document_sync: Some(TextDocumentSyncCapability::Options(
|
|
TextDocumentSyncOptions {
|
|
save: Some(TextDocumentSyncSaveOptions::SaveOptions(SaveOptions {
|
|
include_text: Some(false),
|
|
})),
|
|
change: Some(TextDocumentSyncKind::INCREMENTAL),
|
|
..Default::default()
|
|
},
|
|
)),
|
|
semantic_tokens_provider: Some(
|
|
SemanticTokensServerCapabilities::SemanticTokensOptions(
|
|
SemanticTokensOptions {
|
|
legend: SemanticTokensLegend {
|
|
token_types: semantic_tokens::TOKENS.to_vec(),
|
|
token_modifiers: vec![],
|
|
},
|
|
full: Some(SemanticTokensFullOptions::Bool(true)),
|
|
range: Some(false),
|
|
..Default::default()
|
|
},
|
|
),
|
|
),
|
|
..Default::default()
|
|
},
|
|
..Default::default()
|
|
})
|
|
}
|
|
|
|
async fn initialized(&self, _: InitializedParams) {
|
|
self.client
|
|
.log_message(MessageType::INFO, "server initialized!")
|
|
.await;
|
|
}
|
|
|
|
async fn hover(&self, params: HoverParams) -> Result<Option<Hover>> {
|
|
if let Some(w) = self
|
|
.find_workspace(¶ms.text_document_position_params.text_document.uri)
|
|
.await
|
|
{
|
|
return Ok(w.hover(params).await);
|
|
}
|
|
Ok(None)
|
|
}
|
|
|
|
async fn goto_declaration(
|
|
&self,
|
|
params: GotoDeclarationParams,
|
|
) -> Result<Option<GotoDeclarationResponse>> {
|
|
if let Some(w) = self
|
|
.find_workspace(¶ms.text_document_position_params.text_document.uri)
|
|
.await
|
|
{
|
|
return Ok(w.go_to_declaration(params).await);
|
|
}
|
|
Ok(None)
|
|
}
|
|
|
|
async fn goto_definition(
|
|
&self,
|
|
params: GotoDeclarationParams,
|
|
) -> Result<Option<GotoDeclarationResponse>> {
|
|
if let Some(w) = self
|
|
.find_workspace(¶ms.text_document_position_params.text_document.uri)
|
|
.await
|
|
{
|
|
return Ok(w.go_to_declaration(params).await);
|
|
}
|
|
Ok(None)
|
|
}
|
|
|
|
async fn did_change(&self, params: DidChangeTextDocumentParams) {
|
|
if let Some(w) = self.find_workspace(¶ms.text_document.uri).await {
|
|
w.file_changed(params).await;
|
|
}
|
|
}
|
|
|
|
async fn did_save(&self, params: DidSaveTextDocumentParams) {
|
|
if let Some(w) = self.find_workspace(¶ms.text_document.uri).await {
|
|
w.reload().await;
|
|
}
|
|
}
|
|
|
|
async fn semantic_tokens_full(
|
|
&self,
|
|
params: SemanticTokensParams,
|
|
) -> Result<Option<SemanticTokensResult>> {
|
|
if let Some(w) = self.find_workspace(¶ms.text_document.uri).await {
|
|
return Ok(w.semantic_tokens(params).await);
|
|
}
|
|
Ok(None)
|
|
}
|
|
|
|
async fn shutdown(&self) -> Result<()> {
|
|
let mut workspaces = self.workspaces.write().await;
|
|
for workspace in workspaces.drain(..) {
|
|
workspace.close().await;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Backend {
|
|
pub async fn find_workspace(&self, file: &Uri) -> Option<Arc<Workspace>> {
|
|
let workspaces = self.workspaces.read().await;
|
|
let path = file.strip_header();
|
|
workspaces
|
|
.iter()
|
|
.find(|w| path.starts_with(&w.base))
|
|
.cloned()
|
|
}
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
let stdin = tokio::io::stdin();
|
|
let stdout = tokio::io::stdout();
|
|
|
|
let (service, socket) = LspService::new(|client| Backend {
|
|
client,
|
|
workspaces: RwLock::default(),
|
|
});
|
|
Server::new(stdin, stdout, socket).serve(service).await;
|
|
}
|