use std::panic::RefUnwindSafe;
use crate::{notification_registry::NotificationRegistry, request_registry::RequestRegistry};
use super::Session;
use anyhow::Error;
use crossbeam_channel::select;
use lsp_server::Message;
#[derive(Debug)]
pub(crate) enum Task {
Response(lsp_server::Response),
NotificationError(Error),
}
impl<Db: salsa::Database + Clone + Send + RefUnwindSafe> Session<Db> {
pub fn main_loop<'a>(
&'a mut self,
req_registry: &'a RequestRegistry<Db>,
not_registry: &'a NotificationRegistry<Db>,
) -> anyhow::Result<()> {
loop {
select! {
recv(self.connection.receiver) -> msg => {
match msg? {
Message::Request(req) => {
if self.connection.handle_shutdown(&req)? {
return Ok(());
};
self.req_queue.incoming.register(req.id.clone(), req.method.clone());
if let Some(method) = req_registry.get(&req) {
RequestRegistry::exec(self, method, req);
} else if let Some(method) = req_registry.get_sync_mut(&req) {
RequestRegistry::exec_sync_mut(self, method, req)?;
} else {
RequestRegistry::complete(self,
RequestRegistry::<Db>::request_mismatch(req.id.clone(), anyhow::format_err!("Unknown request: {}", req.method))
)?
}
}
Message::Notification(not) => {
if let Some(method) = not_registry.get(¬) {
NotificationRegistry::exec(self, method, not);
} else if let Some(method) = not_registry.get_sync_mut(¬) {
NotificationRegistry::exec_sync_mut(self, method, not)?;
} else {
NotificationRegistry::handle_error(self, anyhow::format_err!("Unknown notification: {}", not.method))?
}
}
Message::Response(_) => {}
}
},
recv(self.task_rx) -> task => {
match task? {
Task::Response(resp) => RequestRegistry::complete(self, resp)?,
Task::NotificationError(err) => NotificationRegistry::handle_error(self, err)?,
}
}
}
}
}
pub fn send_notification<N: lsp_types::notification::Notification>(
&self,
params: N::Params,
) -> anyhow::Result<()> {
let params = serde_json::to_value(¶ms)?;
let n = lsp_server::Notification {
method: N::METHOD.into(),
params,
};
self.connection.sender.send(Message::Notification(n))?;
Ok(())
}
}