Skip to main content

lsp_max/service/client/
mod.rs

1//! Types for sending data to and from the language client.
2
3pub use self::socket::{ClientSocket, RequestStream, ResponseSink};
4
5use std::fmt::{self, Debug, Formatter};
6use std::sync::atomic::{AtomicU32, Ordering};
7use std::sync::Arc;
8use std::task::{Context, Poll};
9
10use futures::channel::mpsc::{self, Sender};
11use futures::future::BoxFuture;
12use futures::sink::SinkExt;
13use tower::Service;
14use tracing::{error, trace};
15
16use self::pending::Pending;
17pub use self::progress::Progress;
18use super::state::{ServerState, State};
19use super::ExitedError;
20use crate::jsonrpc::{self, Error, ErrorCode, Id, Request, Response};
21
22mod lsp_methods;
23mod pending;
24pub mod progress;
25pub mod progress_ext;
26mod socket;
27
28#[cfg(test)]
29mod tests;
30
31struct ClientInner {
32    tx: Sender<Request>,
33    request_id: AtomicU32,
34    pending: Arc<Pending>,
35    state: Arc<ServerState>,
36}
37
38/// Handle for communicating with the language client.
39#[derive(Clone)]
40pub struct Client {
41    inner: Arc<ClientInner>,
42}
43
44impl Client {
45    pub(super) fn new(state: Arc<ServerState>) -> (Self, ClientSocket) {
46        let (tx, rx) = mpsc::channel(1);
47        let pending = Arc::new(Pending::new());
48
49        let client = Client {
50            inner: Arc::new(ClientInner {
51                tx,
52                request_id: AtomicU32::new(0),
53                pending: pending.clone(),
54                state: state.clone(),
55            }),
56        };
57
58        (client, ClientSocket { rx, pending, state })
59    }
60
61    /// Disconnects the `Client` from its corresponding `LspService`.
62    pub(crate) fn close(&self) {
63        self.inner.tx.clone().close_channel();
64    }
65}
66
67impl Client {
68    /// Sends a custom notification to the client.
69    pub async fn send_notification<N>(&self, params: N::Params)
70    where
71        N: lsp_types_max::notification::Notification,
72    {
73        if let State::Initialized | State::ShutDown = self.inner.state.get() {
74            self.send_notification_unchecked::<N>(params).await;
75        } else {
76            let msg = Request::from_notification::<N>(params);
77            trace!("server not initialized, supressing message: {}", msg);
78        }
79    }
80
81    async fn send_notification_unchecked<N>(&self, params: N::Params)
82    where
83        N: lsp_types_max::notification::Notification,
84    {
85        let request = Request::from_notification::<N>(params);
86        if self.clone().call(request).await.is_err() {
87            error!("failed to send notification");
88        }
89    }
90
91    /// Sends a custom request to the client.
92    pub async fn send_request<R>(&self, params: R::Params) -> jsonrpc::Result<R::Result>
93    where
94        R: lsp_types_max::request::Request,
95    {
96        if let State::Initialized | State::ShutDown = self.inner.state.get() {
97            self.send_request_unchecked::<R>(params).await
98        } else {
99            let id = self.inner.request_id.load(Ordering::SeqCst) as i64 + 1;
100            let msg = Request::from_request::<R>(id.into(), params);
101            trace!("server not initialized, supressing message: {}", msg);
102            Err(jsonrpc::not_initialized_error())
103        }
104    }
105
106    async fn send_request_unchecked<R>(&self, params: R::Params) -> jsonrpc::Result<R::Result>
107    where
108        R: lsp_types_max::request::Request,
109    {
110        let id = self.next_request_id();
111        let request = Request::from_request::<R>(id, params);
112
113        let response = match self.clone().call(request).await {
114            Ok(Some(response)) => response,
115            Ok(None) | Err(_) => return Err(Error::internal_error()),
116        };
117
118        let (_, result) = response.into_parts();
119        result.and_then(|v| {
120            serde_json::from_value(v).map_err(|e| Error {
121                code: ErrorCode::ParseError,
122                message: e.to_string().into(),
123                data: None,
124            })
125        })
126    }
127}
128
129impl Client {
130    /// Increments the internal request ID counter and returns the previous value.
131    pub fn next_request_id(&self) -> Id {
132        let num = self.inner.request_id.fetch_add(1, Ordering::Relaxed);
133        Id::Number(num as i64)
134    }
135}
136
137impl Debug for Client {
138    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
139        f.debug_struct("Client")
140            .field("tx", &self.inner.tx)
141            .field("pending", &self.inner.pending)
142            .field("request_id", &self.inner.request_id)
143            .field("state", &self.inner.state)
144            .finish()
145    }
146}
147
148impl Service<Request> for Client {
149    type Response = Option<Response>;
150    type Error = ExitedError;
151    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
152
153    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
154        let state = self.inner.state.clone();
155        self.inner.tx.clone().poll_ready(cx).map_err(move |_| {
156            let code = if state.get() == State::Exited {
157                state.get_exit_code()
158            } else {
159                1
160            };
161            ExitedError(code)
162        })
163    }
164
165    fn call(&mut self, req: Request) -> Self::Future {
166        let mut tx = self.inner.tx.clone();
167        let response_waiter = req.id().cloned().map(|id| self.inner.pending.wait(id));
168        let state = self.inner.state.clone();
169
170        Box::pin(async move {
171            if tx.send(req).await.is_err() {
172                let code = if state.get() == State::Exited {
173                    state.get_exit_code()
174                } else {
175                    1
176                };
177                return Err(ExitedError(code));
178            }
179
180            match response_waiter {
181                Some(fut) => Ok(Some(fut.await)),
182                None => Ok(None),
183            }
184        })
185    }
186}
187
188#[derive(Debug)]
189struct FoldingRangeRefresh;
190
191impl lsp_types_max::request::Request for FoldingRangeRefresh {
192    type Params = ();
193    type Result = ();
194    const METHOD: &'static str = "workspace/foldingRange/refresh";
195}