Files
leaf/lsp/src/main.rs
T

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(&params.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(&params.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(&params.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(&params.text_document.uri).await {
w.file_changed(params).await;
}
}
async fn did_save(&self, params: DidSaveTextDocumentParams) {
if let Some(w) = self.find_workspace(&params.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(&params.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;
}