-
Notifications
You must be signed in to change notification settings - Fork 98
/
Copy pathclient.rs
133 lines (111 loc) · 3.85 KB
/
client.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use crate::workspace::ServerInfo;
use crate::{TransportError, Workspace, WorkspaceError};
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use serde_json::json;
use std::{
panic::RefUnwindSafe,
sync::atomic::{AtomicU64, Ordering},
};
use super::{CloseFileParams, GetFileContentParams, IsPathIgnoredParams, OpenFileParams};
pub struct WorkspaceClient<T> {
transport: T,
request_id: AtomicU64,
server_info: Option<ServerInfo>,
}
pub trait WorkspaceTransport {
fn request<P, R>(&self, request: TransportRequest<P>) -> Result<R, TransportError>
where
P: Serialize,
R: DeserializeOwned;
}
#[derive(Debug)]
pub struct TransportRequest<P> {
pub id: u64,
pub method: &'static str,
pub params: P,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
pub struct InitializeResult {
/// Information about the server.
#[serde(skip_serializing_if = "Option::is_none")]
pub server_info: Option<ServerInfo>,
}
impl<T> WorkspaceClient<T>
where
T: WorkspaceTransport + RefUnwindSafe + Send + Sync,
{
pub fn new(transport: T) -> Result<Self, WorkspaceError> {
let mut client = Self {
transport,
request_id: AtomicU64::new(0),
server_info: None,
};
// TODO: The current implementation of the JSON-RPC protocol in
// tower_lsp doesn't allow any request to be sent before a call to
// initialize, this is something we could be able to lift by using our
// own RPC protocol implementation
let value: InitializeResult = client.request(
"initialize",
json!({
"capabilities": {},
"clientInfo": {
"name": env!("CARGO_PKG_NAME"),
"version": pgt_configuration::VERSION
},
}),
)?;
client.server_info = value.server_info;
Ok(client)
}
fn request<P, R>(&self, method: &'static str, params: P) -> Result<R, WorkspaceError>
where
P: Serialize,
R: DeserializeOwned,
{
let id = self.request_id.fetch_add(1, Ordering::Relaxed);
let request = TransportRequest { id, method, params };
let response = self.transport.request(request)?;
Ok(response)
}
pub fn shutdown(self) -> Result<(), WorkspaceError> {
self.request("pgt/shutdown", ())
}
}
impl<T> Workspace for WorkspaceClient<T>
where
T: WorkspaceTransport + RefUnwindSafe + Send + Sync,
{
fn open_file(&self, params: OpenFileParams) -> Result<(), WorkspaceError> {
self.request("pgt/open_file", params)
}
fn close_file(&self, params: CloseFileParams) -> Result<(), WorkspaceError> {
self.request("pgt/close_file", params)
}
fn change_file(&self, params: super::ChangeFileParams) -> Result<(), WorkspaceError> {
self.request("pgt/change_file", params)
}
fn update_settings(&self, params: super::UpdateSettingsParams) -> Result<(), WorkspaceError> {
self.request("pgt/update_settings", params)
}
fn is_path_ignored(&self, params: IsPathIgnoredParams) -> Result<bool, WorkspaceError> {
self.request("pgt/is_path_ignored", params)
}
fn server_info(&self) -> Option<&ServerInfo> {
self.server_info.as_ref()
}
fn get_file_content(&self, params: GetFileContentParams) -> Result<String, WorkspaceError> {
self.request("pgt/get_file_content", params)
}
fn pull_diagnostics(
&self,
params: super::PullDiagnosticsParams,
) -> Result<super::PullDiagnosticsResult, WorkspaceError> {
self.request("pgt/pull_diagnostics", params)
}
fn get_completions(
&self,
params: super::GetCompletionsParams,
) -> Result<super::CompletionResult, WorkspaceError> {
self.request("pgt/get_completions", params)
}
}