A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/lsp/rq.rs')
-rw-r--r--src/lsp/rq.rs171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/lsp/rq.rs b/src/lsp/rq.rs
new file mode 100644
index 0000000..18c6616
--- /dev/null
+++ b/src/lsp/rq.rs
@@ -0,0 +1,171 @@
+use std::backtrace::Backtrace;
+use std::fmt::Debug;
+use std::marker::PhantomData;
+use std::sync::Arc;
+
+use crossbeam::channel::SendError;
+use lsp_server::{Message, Response as Re};
+use lsp_types::DiagnosticServerCancellationData;
+use lsp_types::request::Request;
+use serde::{Deserialize, Serialize};
+use tokio::sync::oneshot;
+use tokio::task;
+use tokio_util::task::AbortOnDropHandle;
+use winit::window::Window;
+
+#[derive(Serialize, Deserialize)]
+pub enum RequestError<X> {
+ Rx(PhantomData<X>),
+ Failure(Re, #[serde(skip)] Option<Backtrace>),
+ Cancelled(Re, DiagnosticServerCancellationData),
+ Send(Message),
+}
+pub type AQErr = RequestError<LSPError>;
+impl Request for LSPError {
+ type Params = ();
+ type Result = ();
+ const METHOD: &'static str = "<unknown method>";
+}
+#[derive(Debug)]
+pub struct LSPError {}
+pub trait Anonymize<T> {
+ fn anonymize(self) -> Result<T, RequestError<LSPError>>;
+}
+impl<T, E> Anonymize<T> for Result<T, RequestError<E>> {
+ fn anonymize(self) -> Result<T, RequestError<LSPError>> {
+ self.map_err(|e| match e {
+ RequestError::Send(x) => RequestError::Send(x),
+ RequestError::Rx(_) => RequestError::Rx(PhantomData),
+ RequestError::Failure(r, b) => RequestError::Failure(r, b),
+ RequestError::Cancelled(r, d) => RequestError::Cancelled(r, d),
+ })
+ }
+}
+
+// impl<X> Debug for RequestError<X> {}
+impl<X> From<oneshot::error::RecvError> for RequestError<X> {
+ fn from(_: oneshot::error::RecvError) -> Self {
+ Self::Rx(PhantomData)
+ }
+}
+impl<X: Request + Debug> std::error::Error for RequestError<X> {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ None
+ }
+}
+impl<X> From<SendError<Message>> for RequestError<X> {
+ fn from(x: SendError<Message>) -> Self {
+ Self::Send(x.into_inner())
+ }
+}
+impl<X: Request> std::fmt::Display for RequestError<X> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Self::Send(x) =>
+ write!(f, "{} failed; couldnt send {x:?}", X::METHOD),
+ Self::Rx(_) =>
+ write!(f, "{} failed; couldnt get from thingy", X::METHOD),
+ Self::Failure(x, bt) => write!(
+ f,
+ "{} failed; returned badge :( {x:?} ({bt:?})",
+ X::METHOD
+ ),
+ Self::Cancelled(x, y) =>
+ write!(f, "server cancelled {}. {x:?} {y:?}", X::METHOD),
+ }
+ }
+}
+impl<R: Request> Debug for RequestError<R> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(&self, f)
+ }
+}
+
+fn none<T>() -> Option<T> {
+ None
+}
+impl<T: Clone, R, D, E> Clone for Rq<T, R, D, E> {
+ fn clone(&self) -> Self {
+ Self { result: self.result.clone(), request: None }
+ }
+}
+#[derive(serde_derive::Serialize, serde_derive::Deserialize)]
+pub struct Rq<T, R, D = (), E = RequestError<R>> {
+ #[serde(skip_serializing_if = "Option::is_none", default = "none")]
+ pub result: Option<T>,
+ #[serde(skip, default = "none")]
+ pub request: Option<(AbortOnDropHandle<Result<R, E>>, D)>,
+}
+impl<T: Debug, R, D: Debug, E> Debug for Rq<T, R, D, E> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct(&format!("Rq<{}>", std::any::type_name::<R>()))
+ .field("result", &self.result)
+ .field("request", &self.request)
+ .finish()
+ }
+}
+
+pub type RqS<T, R: Request, D = ()> = Rq<T, R::Result, D, RequestError<R>>;
+impl<T, R, D, E> Default for Rq<T, R, D, E> {
+ fn default() -> Self {
+ Self { result: None, request: None }
+ }
+}
+impl<T, R, E> Rq<T, R, (), E> {
+ pub fn new(f: task::JoinHandle<Result<R, E>>) -> Self {
+ Self {
+ request: Some((AbortOnDropHandle::new(f), ())),
+ result: None,
+ }
+ }
+ pub fn request(&mut self, f: task::JoinHandle<Result<R, E>>) {
+ self.request = Some((AbortOnDropHandle::new(f), ()));
+ }
+}
+impl<T, R, D, E> Rq<T, R, D, E> {
+ pub fn running(&self) -> bool {
+ matches!(
+ self,
+ Self { result: Some(_), .. } | Self { request: Some(_), .. },
+ )
+ }
+ pub fn poll(
+ &mut self,
+ f: impl FnOnce(Result<R, E>, (D, Option<T>)) -> Option<T>,
+ ) -> bool {
+ if self.request.as_mut().is_some_and(|(x, _)| x.is_finished())
+ && let Some((task, _)) = self.request.as_mut()
+ && let Some(x) = futures::FutureExt::now_or_never(task)
+ {
+ let (_, d) = self.request.take().unwrap();
+ self.result = f(
+ match x {
+ Ok(x) => x,
+ Err(e) => {
+ log::error!(
+ "unexpected join error from request poll: {e}"
+ );
+ return false;
+ }
+ },
+ (d, self.result.take()),
+ );
+ true
+ } else {
+ false
+ }
+ }
+
+ pub fn poll_r(
+ &mut self,
+ f: impl FnOnce(Result<R, E>, (D, Option<T>)) -> Option<T>,
+ _runtime: &tokio::runtime::Runtime,
+ _w: Option<&Arc<dyn Window>>,
+ ) -> bool {
+ self.poll(|x, y| {
+ f(x, y).inspect(|_| {
+ // w.map(|x| x.request_redraw());
+ })
+ })
+ }
+}