Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'src/lsp/communication.rs')
-rw-r--r--src/lsp/communication.rs74
1 files changed, 61 insertions, 13 deletions
diff --git a/src/lsp/communication.rs b/src/lsp/communication.rs
index 4c4f49d..efc44ee 100644
--- a/src/lsp/communication.rs
+++ b/src/lsp/communication.rs
@@ -7,22 +7,29 @@ use std::time::Instant;
use crossbeam::channel::{Receiver, RecvError, SendError, Sender};
use log::{debug, error, trace};
use lsp_server::{
- ErrorCode, Message, Notification as N, Request as LRq, Response as Re,
- ResponseError,
+ ErrorCode, ExtractError, Message, Notification as N, Request as LRq,
+ RequestId, Response as Re, ResponseError,
};
-use lsp_types::notification::*;
-use lsp_types::request::*;
use lsp_types::*;
+use serde::{Deserialize, Serialize};
use tokio::sync::oneshot;
use tokio::time::error::Elapsed;
+use url::Url;
use winit::window::Window;
+#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
+#[serde(untagged)]
+pub enum WorkDoneProgress {
+ Begin(WorkDoneProgressBegin),
+ Report(WorkDoneProgressReport),
+ End(WorkDoneProgressEnd),
+}
use crate::lsp::BehaviourAfter::{self, *};
use crate::lsp::{RequestError, RqSendError};
pub fn handler(
window_rx: oneshot::Receiver<Arc<dyn Window + 'static>>,
progress: &papaya::HashMap<
- NumberOrString,
+ ProgressToken,
Option<(WorkDoneProgress, WorkDoneProgressBegin)>,
>,
_req_tx: Sender<LRq>,
@@ -40,13 +47,13 @@ pub fn handler(
Ok((.., BehaviourAfter::RedrawNow)) => w.request_redraw(),
Ok((x, y, and)) => {
debug!("received request {x}");
- assert!(map.insert(x, (y, Instant::now(), and)).is_none());
+ assert!(map.insert(RequestId::from(x), (y, Instant::now(), and)).is_none());
}
Err(RecvError) => return,
},
recv(rx) -> x => match x {
Ok(Message::Request(rq @ LRq { method: "window/workDoneProgress/create", .. })) => {
- match rq.load::<WorkDoneProgressCreate>() {
+ match load_rq::<lsp_request!("window/workDoneProgress/create")>(rq) {
Ok((_, x)) => {
let g = progress.guard();
progress.insert(x.token, None, &g);
@@ -67,13 +74,13 @@ pub fn handler(
if let Some(e) = &x.error {
if e.code == ErrorCode::RequestCanceled as i32 {}
else if e.code == ErrorCode::ServerCancelled as i32 {
- if let Some((s, _, t)) = map.remove(&x.id.i32()) {
+ if let Some((s, _, t)) = map.remove(&x.id) {
log::info!("request {} cancelled", x.id);
_ = s.send(x);
if t == Redraw { w.request_redraw() }
}
} else {
- if let Some((s, _, t)) = map.remove(&x.id.i32()) {
+ if let Some((s, _, t)) = map.remove(&x.id) {
_ = s.send(x.clone());
if t == Redraw { w.request_redraw() }
trace!("received error from lsp for response {x:?}");
@@ -82,7 +89,7 @@ pub fn handler(
}
}
}
- else if let Some((s, took, t)) = map.remove(&x.id.i32()) {
+ else if let Some((s, took, t)) = map.remove(&x.id) {
log::debug!("request {} took {:?}", x.id, took.elapsed());
match s.send(x) {
Ok(()) => {}
@@ -100,7 +107,7 @@ pub fn handler(
}
Ok(Message::Notification(rq @ N { method: "textDocument/publishDiagnostics", .. })) => {
debug!("got diagnostics");
- match rq.load::<PublishDiagnostics>() {
+ match load_n::<lsp_notification!("textDocument/publishDiagnostics")>(rq) {
Ok(x) => {
d.insert(x.uri, x.diagnostics, &d.guard());
w.request_redraw();
@@ -109,7 +116,8 @@ pub fn handler(
}
},
Ok(Message::Notification(x @ N { method: "$/progress", .. })) => {
- let ProgressParams {token,value:ProgressParamsValue::WorkDone(x) } = x.load::<Progress>().unwrap();
+ let ProgressParams {token,value:x } = load_n::<lsp_notification!("$/progress")>(x).unwrap();
+ let Ok(x) = serde_json::from_value::<WorkDoneProgress>(x.clone()) else { error!("{x:?}"); continue };
match x.clone() {
WorkDoneProgress::Begin(y) => {
progress.update(token, move |_| Some((x.clone(), y.clone())), &progress.guard());
@@ -131,6 +139,34 @@ pub fn handler(
}
}
}
+#[derive(Debug)]
+#[allow(dead_code)]
+pub enum ExtractErr<T> {
+ /// The extracted message was of a different method than expected.
+ MethodMismatch(T),
+ /// Failed to deserialize the message.
+ JsonError { method: String, error: serde_json::Error },
+}
+fn load_n<T: lsp_types::Notification>(
+ me: lsp_server::Notification,
+) -> Result<T::Params, ExtractErr<lsp_server::Notification>> {
+ (T::METHOD.as_str() == me.method)
+ .ok_or(ExtractErr::MethodMismatch(me.clone()))?;
+ serde_json::from_value(me.params)
+ .map_err(|e| ExtractErr::JsonError { method: me.method, error: e })
+}
+pub fn load_rq<P: lsp_types::Request>(
+ me: LRq,
+) -> Result<(RequestId, P::Params), ExtractError<LRq>> {
+ if me.method != P::METHOD.to_string() {
+ return Err(ExtractError::MethodMismatch(me));
+ }
+ match serde_json::from_value(me.params) {
+ Ok(params) => Ok((me.id, params)),
+ Err(error) =>
+ Err(ExtractError::JsonError { method: me.method, error }),
+ }
+}
impl super::Tx {
pub fn notify<X: Notification>(
&self,
@@ -142,7 +178,9 @@ impl super::Tx {
}))
}
pub fn cancel(&self, rid: i32) {
- _ = self.notify::<Cancel>(&CancelParams { id: rid.into() });
+ _ = self.notify::<CancelNotification>(&CancelParams {
+ id: rid.into(),
+ });
}
}
impl super::Client {
@@ -266,3 +304,13 @@ impl super::Client {
self.send_to.send((0, tx, BehaviourAfter::RedrawNow))
}
}
+macro_rules! send
+ {
+ ($c:ident.$call:ident$(::<$($arg:block),*>)?, $request:tt, _ { $($field:ident: $expr:expr),* $(,)? $(,..$base:expr)? } $(,)?) => {{
+ type R = lsp_request!($request);
+ type P = <R as Request>::Params;
+ $c.$call::<R $($(,$arg)*)?>(&P { $($field: $expr),* })
+ }};
+}
+
+pub(crate) use send;