lsp_client/
lib.rs

1pub mod transport;
2
3use jsonrpsee::{
4    async_client::{Client, ClientBuilder},
5    core::{
6        client::{
7            ClientT, Subscription, SubscriptionClientT, TransportReceiverT, TransportSenderT,
8        },
9        traits::ToRpcParams,
10    },
11};
12use lsp_types::{notification::*, request::*, *};
13use serde::Serialize;
14use serde_json::value::RawValue;
15
16struct SerdeParam<T>(T)
17where
18    T: Serialize;
19
20impl<T> ToRpcParams for SerdeParam<T>
21where
22    T: Serialize,
23{
24    fn to_rpc_params(self) -> Result<Option<Box<RawValue>>, serde_json::Error> {
25        let json = serde_json::to_string(&self.0)?;
26        RawValue::from_string(json).map(Some)
27    }
28}
29
30#[derive(thiserror::Error, Debug)]
31pub enum LspError {
32    #[error("jsonrpsee error: {0}")]
33    Jsonrpsee(#[from] jsonrpsee::core::client::Error),
34}
35
36/// A client for the Language Server Protocol.
37#[derive(Debug)]
38pub struct LspClient {
39    client: Client,
40}
41
42impl LspClient {
43    pub fn new<S, R>(sender: S, receiver: R) -> Self
44    where
45        S: TransportSenderT + Send,
46        R: TransportReceiverT + Send,
47    {
48        let client = ClientBuilder::default().build_with_tokio(sender, receiver);
49        Self { client }
50    }
51
52    /// Request the server to initialize the client.
53    ///
54    /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize
55    pub async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult, LspError> {
56        self.send_request::<Initialize>(params).await
57    }
58
59    /// Notify the server that the client received the result of the `initialize` request.
60    ///
61    /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialized
62    pub async fn initialized(&self) -> Result<(), LspError> {
63        let params = InitializedParams {};
64        self.send_notification::<Initialized>(params).await
65    }
66
67    /// Request the server to shutdown the client.
68    ///
69    /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#shutdown
70    pub async fn shutdown(&self) -> Result<(), LspError> {
71        self.send_request::<Shutdown>(()).await
72    }
73
74    /// Notify the server to exit the process.
75    ///
76    /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#exit
77    pub async fn exit(&self) -> Result<(), LspError> {
78        self.send_notification::<Exit>(()).await
79    }
80
81    /// Send an LSP request to the server.
82    pub async fn send_request<R>(&self, params: R::Params) -> Result<R::Result, LspError>
83    where
84        R: Request,
85    {
86        let result = self.client.request(R::METHOD, SerdeParam(params)).await?;
87        Ok(result)
88    }
89
90    /// Send an LSP notification to the server.
91    pub async fn send_notification<N>(&self, params: N::Params) -> Result<(), LspError>
92    where
93        N: Notification,
94    {
95        self.client
96            .notification(N::METHOD, SerdeParam(params))
97            .await?;
98        Ok(())
99    }
100
101    /// Create a subscription to an LSP notification.
102    pub async fn subscribe_to_method<N>(&self) -> Result<Subscription<N::Params>, LspError>
103    where
104        N: Notification,
105    {
106        let subscription = self.client.subscribe_to_method(N::METHOD).await?;
107        Ok(subscription)
108    }
109}