use std::backtrace::Backtrace; use std::fmt::{Debug, Display}; use std::marker::PhantomData; 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 crate::lsp::Void; #[derive(Serialize, Deserialize)] pub enum RequestError { Rx(PhantomData), Failure(Re, #[serde(skip)] Option), Cancelled(Re, DiagnosticServerCancellationData), Send(Message), // Unsupported, } pub type AQErr = RequestError; impl Request for LSPError { type Params = (); type Result = (); const METHOD: &'static str = ""; } #[derive(Debug)] pub struct LSPError {} pub trait Anonymize { fn anonymize(self) -> Result>; } impl Anonymize for Result> { fn anonymize(self) -> Result> { 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), // RequestError::Unsupported => RequestError::Unsupported, }) } } // impl Debug for RequestError {} impl From for RequestError { fn from(_: oneshot::error::RecvError) -> Self { Self::Rx(PhantomData) } } impl std::error::Error for RequestError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None } } impl From> for RequestError { fn from(x: SendError) -> Self { Self::Send(x.into_inner()) } } impl std::fmt::Display for RequestError { 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), // RequestError::Unsupported => // write!(f, "{} failed; detected as unsupported", 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 Debug for RequestError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self, f) } } pub trait Require { fn require(&self) -> Requiring; } impl Require for Option { fn require(&self) -> Requiring { self.void().ok_or(Unsupported) } } pub struct Unsupported; pub type Requiring = Result>; impl Display for Unsupported { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "request {} isnt supported by this LSP", R) } } pub trait Peel { fn peel(self) -> Result<(), E>; } impl Peel for Result, N> { fn peel(self) -> Result<(), E> { match self { Ok(Err(e)) => Err(e), Ok(Ok(_)) | Err(_) => Ok(()), } } } // impl Debug for Unsupported { // fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // std::fmt::Display::fmt(&self, f) // } // } // impl std::error::Error for Unsupported { // fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { // None // } // } fn none() -> Option { None } impl Clone for Rq { fn clone(&self) -> Self { Self { result: self.result.clone(), request: None } } } #[derive(serde_derive::Serialize, serde_derive::Deserialize)] pub struct Rq> { #[serde(skip_serializing_if = "Option::is_none", default = "none")] pub result: Option, #[serde(skip, default = "none")] pub request: Option<(AbortOnDropHandle>, D)>, } impl Debug for Rq { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(&format!("Rq<{}>", std::any::type_name::())) .field("result", &self.result) .field("request", &self.request) .finish() } } pub type RqS = Rq>; impl Default for Rq { fn default() -> Self { Self { result: None, request: None } } } impl Rq { pub fn new(f: task::JoinHandle>) -> Self { Self { request: Some((AbortOnDropHandle::new(f), ())), result: None, } } pub fn request(&mut self, f: task::JoinHandle>) { self.request_d(f, ()); } } impl Rq { pub fn request_d(&mut self, f: task::JoinHandle>, d: D) { self.request = Some((AbortOnDropHandle::new(f), d)); } } impl Rq { pub fn running(&self) -> bool { matches!( self, Self { result: Some(_), .. } | Self { request: Some(_), .. }, ) } pub fn poll( &mut self, f: impl FnOnce(Result, (D, Option)) -> Option, ) -> 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.inspect_err(|x| { dbg!(&x); }), Err(e) => { log::error!( "unexpected join error from request poll: {e}" ); return false; } }, (d, self.result.take()), ); true } else { false } } }