use async_tungstenite::tokio::accept_async;
use lspower::{jsonrpc::Result, lsp::*, Client, LanguageServer, LspService, Server};
use serde_json::Value;
use tokio::net::TcpListener;
use ws_stream_tungstenite::*;
#[derive(Debug)]
struct Backend {
client: Client,
}
#[lspower::async_trait]
impl LanguageServer for Backend {
async fn initialize(&self, _: InitializeParams) -> Result<InitializeResult> {
Ok(InitializeResult {
server_info: None,
capabilities: ServerCapabilities {
text_document_sync: Some(TextDocumentSyncCapability::Kind(TextDocumentSyncKind::INCREMENTAL)),
completion_provider: Some(CompletionOptions {
resolve_provider: Some(false),
trigger_characters: Some(vec![".".to_string()]),
..Default::default()
}),
execute_command_provider: Some(ExecuteCommandOptions {
commands: vec!["dummy.do_something".to_string()],
..Default::default()
}),
workspace: Some(WorkspaceServerCapabilities {
workspace_folders: Some(WorkspaceFoldersServerCapabilities {
supported: Some(true),
change_notifications: Some(OneOf::Left(true)),
}),
..Default::default()
}),
..ServerCapabilities::default()
},
})
}
async fn initialized(&self, _: InitializedParams) {
self.client.log_message(MessageType::INFO, "initialized!").await;
}
async fn shutdown(&self) -> Result<()> {
Ok(())
}
async fn did_change_workspace_folders(&self, _: DidChangeWorkspaceFoldersParams) {
self.client
.log_message(MessageType::INFO, "workspace folders changed!")
.await;
}
async fn did_change_configuration(&self, _: DidChangeConfigurationParams) {
self.client
.log_message(MessageType::INFO, "configuration changed!")
.await;
}
async fn did_change_watched_files(&self, _: DidChangeWatchedFilesParams) {
self.client
.log_message(MessageType::INFO, "watched files have changed!")
.await;
}
async fn execute_command(&self, _: ExecuteCommandParams) -> Result<Option<Value>> {
self.client.log_message(MessageType::INFO, "command executed!").await;
match self
.client
.apply_edit(WorkspaceEdit::default(), Default::default())
.await
{
Ok(res) if res.applied => self.client.log_message(MessageType::INFO, "applied").await,
Ok(_) => self.client.log_message(MessageType::INFO, "rejected").await,
Err(err) => self.client.log_message(MessageType::ERROR, err).await,
}
Ok(None)
}
async fn did_open(&self, _: DidOpenTextDocumentParams) {
self.client.log_message(MessageType::INFO, "file opened!").await;
}
async fn did_change(&self, _: DidChangeTextDocumentParams) {
self.client.log_message(MessageType::INFO, "file changed!").await;
}
async fn did_save(&self, _: DidSaveTextDocumentParams) {
self.client.log_message(MessageType::INFO, "file saved!").await;
}
async fn did_close(&self, _: DidCloseTextDocumentParams) {
self.client.log_message(MessageType::INFO, "file closed!").await;
}
async fn completion(&self, _: CompletionParams) -> Result<Option<CompletionResponse>> {
Ok(Some(CompletionResponse::Array(vec![
CompletionItem::new_simple("Hello".to_string(), "Some detail".to_string()),
CompletionItem::new_simple("Bye".to_string(), "More detail".to_string()),
])))
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
env_logger::init();
let listener = TcpListener::bind("127.0.0.1:9257").await?;
while let Ok((socket, _)) = listener.accept().await {
tokio::spawn(async move {
let stream = WsStream::new(accept_async(socket).await?);
let (read, write) = tokio::io::split(stream);
let (service, messages) = LspService::new(|client| Backend { client });
Server::new(read, write).interleave(messages).serve(service).await;
Ok::<_, anyhow::Error>(())
});
}
Ok(())
}