Support basic diagnostic reporting

This commit is contained in:
Ayaz Hafiz 2022-08-20 15:14:59 -05:00
parent c50925240d
commit 9d365a8a57
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
11 changed files with 572 additions and 3 deletions

View file

@ -0,0 +1,112 @@
use parking_lot::{Mutex, MutexGuard};
use registry::{DocumentChange, Registry};
use tower_lsp::jsonrpc::Result;
use tower_lsp::lsp_types::*;
use tower_lsp::{Client, LanguageServer, LspService, Server};
mod convert;
mod registry;
#[derive(Debug)]
struct RocLs {
client: Client,
registry: Mutex<Registry>,
}
impl RocLs {
pub fn new(client: Client) -> Self {
Self {
client,
registry: Mutex::new(Registry::default()),
}
}
fn registry(&self) -> MutexGuard<Registry> {
self.registry.lock()
}
pub fn capabilities() -> ServerCapabilities {
let text_document_sync = Some(TextDocumentSyncCapability::Options(
// TODO: later on make this incremental
TextDocumentSyncOptions {
open_close: Some(true),
change: Some(TextDocumentSyncKind::FULL),
..TextDocumentSyncOptions::default()
},
));
let hover_provider = Some(HoverProviderCapability::Simple(true));
ServerCapabilities {
text_document_sync,
hover_provider,
..ServerCapabilities::default()
}
}
/// Records a document content change.
async fn change(&self, fi: Url, text: String, version: i32) {
self.registry()
.apply_change(DocumentChange::Modified(fi.clone(), text));
let diagnostics = self.registry().diagnostics(&fi);
self.client
.publish_diagnostics(fi, diagnostics, Some(version))
.await;
}
async fn close(&self, fi: Url) {
self.registry().apply_change(DocumentChange::Closed(fi));
}
}
#[tower_lsp::async_trait]
impl LanguageServer for RocLs {
async fn initialize(&self, _: InitializeParams) -> Result<InitializeResult> {
Ok(InitializeResult {
capabilities: Self::capabilities(),
..InitializeResult::default()
})
}
async fn initialized(&self, _: InitializedParams) {
self.client
.log_message(MessageType::INFO, "Roc language server initialized.")
.await;
}
async fn did_open(&self, params: DidOpenTextDocumentParams) {
let TextDocumentItem {
uri, text, version, ..
} = params.text_document;
self.change(uri, text, version).await;
}
async fn did_change(&self, params: DidChangeTextDocumentParams) {
let VersionedTextDocumentIdentifier { uri, version, .. } = params.text_document;
// NOTE: We specify that we expect full-content syncs in the server capabilities,
// so here we assume the only change passed is a change of the entire document's content.
let TextDocumentContentChangeEvent { text, .. } =
params.content_changes.into_iter().next().unwrap();
self.change(uri, text, version).await;
}
async fn did_close(&self, params: DidCloseTextDocumentParams) {
let TextDocumentIdentifier { uri } = params.text_document;
self.close(uri).await;
}
async fn shutdown(&self) -> Result<()> {
Ok(())
}
}
#[tokio::main]
async fn main() {
let stdin = tokio::io::stdin();
let stdout = tokio::io::stdout();
let (service, socket) = LspService::new(RocLs::new);
Server::new(stdin, stdout, socket).serve(service).await;
}