use super::LanguageServerState;
use crate::{from_lsp, handlers, lsp_utils::apply_document_changes, state::RequestHandler};
use dispatcher::{NotificationDispatcher, RequestDispatcher};
use lsp_types::notification::{
DidChangeTextDocument, DidChangeWatchedFiles, DidCloseTextDocument, DidOpenTextDocument,
};
use std::time::Instant;
pub mod dispatcher;
impl LanguageServerState {
fn on_did_open_text_document(
&mut self,
params: lsp_types::DidOpenTextDocumentParams,
) -> anyhow::Result<()> {
let path = from_lsp::abs_path(¶ms.text_document.uri)?;
self.open_docs.insert(path.clone());
self.vfs
.write()
.set_file_contents(&path, Some(params.text_document.text.into_bytes()));
Ok(())
}
fn on_did_change_text_document(
&mut self,
params: lsp_types::DidChangeTextDocumentParams,
) -> anyhow::Result<()> {
let lsp_types::DidChangeTextDocumentParams {
text_document,
content_changes,
} = params;
let path = from_lsp::abs_path(&text_document.uri)?;
let vfs = &mut *self.vfs.write();
let file_id = vfs
.file_id(&path)
.expect("we already checked that the file_id exists!");
let mut text = vfs
.file_contents(file_id)
.and_then(|contents| String::from_utf8(contents.to_vec()).ok())
.expect("if the file_id exists it must be valid utf8");
apply_document_changes(&mut text, content_changes);
vfs.set_file_contents(&path, Some(text.into_bytes()));
Ok(())
}
fn on_did_close_text_document(
&mut self,
params: lsp_types::DidCloseTextDocumentParams,
) -> anyhow::Result<()> {
let path = from_lsp::abs_path(¶ms.text_document.uri)?;
self.open_docs.remove(&path);
self.vfs_monitor.reload(&path);
Ok(())
}
fn on_did_change_watched_files(
&mut self,
params: lsp_types::DidChangeWatchedFilesParams,
) -> anyhow::Result<()> {
for change in params.changes {
let path = from_lsp::abs_path(&change.uri)?;
self.vfs_monitor.reload(&path);
}
Ok(())
}
pub(super) fn on_request(
&mut self,
request: lsp_server::Request,
request_received: Instant,
) -> anyhow::Result<()> {
self.register_request(&request, request_received);
if self.shutdown_requested {
self.respond(lsp_server::Response::new_err(
request.id,
lsp_server::ErrorCode::InvalidRequest as i32,
"shutdown was requested".to_owned(),
));
return Ok(());
}
RequestDispatcher::new(self, request)
.on_sync::<lsp_types::request::Shutdown>(|state, _request| {
state.shutdown_requested = true;
Ok(())
})?
.on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)?
.on::<lsp_types::request::Completion>(handlers::handle_completion)?
.finish();
Ok(())
}
pub(super) fn on_notification(
&mut self,
notification: lsp_server::Notification,
) -> anyhow::Result<()> {
NotificationDispatcher::new(self, notification)
.on::<DidOpenTextDocument>(LanguageServerState::on_did_open_text_document)?
.on::<DidChangeTextDocument>(LanguageServerState::on_did_change_text_document)?
.on::<DidCloseTextDocument>(LanguageServerState::on_did_close_text_document)?
.on::<DidChangeWatchedFiles>(LanguageServerState::on_did_change_watched_files)?
.finish();
Ok(())
}
fn register_request(&mut self, request: &lsp_server::Request, request_received: Instant) {
self.request_queue.incoming.register(
request.id.clone(),
(request.method.clone(), request_received),
)
}
pub(crate) fn send_request<R: lsp_types::request::Request>(
&mut self,
params: R::Params,
handler: RequestHandler,
) {
let request = self
.request_queue
.outgoing
.register(R::METHOD.to_string(), params, handler);
self.send(request.into());
}
pub(crate) fn send_notification<N: lsp_types::notification::Notification>(
&mut self,
params: N::Params,
) {
let not = lsp_server::Notification::new(N::METHOD.to_string(), params);
self.send(not.into());
}
pub(super) fn complete_request(&mut self, response: lsp_server::Response) {
let handler = self
.request_queue
.outgoing
.complete(response.id.clone())
.expect("received response for unknown request");
handler(self, response)
}
pub(super) fn respond(&mut self, response: lsp_server::Response) {
if let Some((_method, start)) = self.request_queue.incoming.complete(response.id.clone()) {
let duration = start.elapsed();
log::info!("handled req#{} in {:?}", response.id, duration);
self.send(response.into());
}
}
pub(crate) fn send(&mut self, message: lsp_server::Message) {
self.sender
.send(message)
.expect("error sending lsp message to the outgoing channel")
}
}