1use std::{
2 collections::HashMap,
3 path::PathBuf,
4 sync::{
5 atomic::{AtomicU64, Ordering},
6 Arc,
7 },
8};
9
10use crossbeam_channel::{Receiver, Sender};
11use lsp_types::{
12 CompletionResponse, LogMessageParams, ProgressParams, PublishDiagnosticsParams,
13 ShowMessageParams,
14};
15use parking_lot::Mutex;
16use serde::{Deserialize, Serialize};
17
18use crate::{
19 file::FileNodeItem,
20 plugin::{PluginId, VoltInfo, VoltMetadata},
21 source_control::DiffInfo,
22 terminal::TermId,
23 RequestId, RpcError, RpcMessage,
24};
25
26pub enum CoreRpc {
27 Request(RequestId, CoreRequest),
28 Notification(Box<CoreNotification>), Shutdown,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
33#[serde(rename_all = "snake_case")]
34#[serde(tag = "method", content = "params")]
35pub enum CoreNotification {
36 ProxyConnected {},
37 OpenFileChanged {
38 path: PathBuf,
39 content: String,
40 },
41 CompletionResponse {
42 request_id: usize,
43 input: String,
44 resp: CompletionResponse,
45 plugin_id: PluginId,
46 },
47 ReloadBuffer {
48 path: PathBuf,
49 content: String,
50 rev: u64,
51 },
52 OpenPaths {
53 window_tab_id: Option<(usize, usize)>,
54 folders: Vec<PathBuf>,
55 files: Vec<PathBuf>,
56 },
57 WorkspaceFileChange {},
58 PublishDiagnostics {
59 diagnostics: PublishDiagnosticsParams,
60 },
61 WorkDoneProgress {
62 progress: ProgressParams,
63 },
64 ShowMessage {
65 title: String,
66 message: ShowMessageParams,
67 },
68 LogMessage {
69 message: LogMessageParams,
70 },
71 HomeDir {
72 path: PathBuf,
73 },
74 VoltInstalled {
75 volt: VoltMetadata,
76 only_installing: bool,
77 },
78 VoltInstalling {
79 volt: VoltMetadata,
80 error: String,
81 },
82 VoltRemoving {
83 volt: VoltMetadata,
84 error: String,
85 },
86 VoltRemoved {
87 volt: VoltInfo,
88 only_installing: bool,
89 },
90 ListDir {
91 items: Vec<FileNodeItem>,
92 },
93 DiffFiles {
94 files: Vec<PathBuf>,
95 },
96 DiffInfo {
97 diff: DiffInfo,
98 },
99 UpdateTerminal {
100 term_id: TermId,
101 content: String,
102 },
103 CloseTerminal {
104 term_id: TermId,
105 },
106 Log {
107 level: String,
108 message: String,
109 },
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
113pub enum CoreRequest {}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
116#[serde(rename_all = "snake_case")]
117#[serde(tag = "method", content = "params")]
118pub enum CoreResponse {}
119
120pub type CoreMessage = RpcMessage<CoreRequest, CoreNotification, CoreResponse>;
121
122pub trait CoreHandler {
123 fn handle_notification(&mut self, rpc: CoreNotification);
124 fn handle_request(&mut self, id: RequestId, rpc: CoreRequest);
125}
126
127#[derive(Clone)]
128pub struct CoreRpcHandler {
129 tx: Sender<CoreRpc>,
130 rx: Receiver<CoreRpc>,
131 id: Arc<AtomicU64>,
132 #[allow(clippy::type_complexity)]
133 pending: Arc<Mutex<HashMap<u64, Sender<Result<CoreResponse, RpcError>>>>>,
134}
135
136impl CoreRpcHandler {
137 pub fn new() -> Self {
138 let (tx, rx) = crossbeam_channel::unbounded();
139 Self {
140 tx,
141 rx,
142 id: Arc::new(AtomicU64::new(0)),
143 pending: Arc::new(Mutex::new(HashMap::new())),
144 }
145 }
146
147 pub fn mainloop<H>(&self, handler: &mut H)
148 where
149 H: CoreHandler,
150 {
151 for msg in &self.rx {
152 match msg {
153 CoreRpc::Request(id, rpc) => {
154 handler.handle_request(id, rpc);
155 }
156 CoreRpc::Notification(rpc) => {
157 handler.handle_notification(*rpc);
158 }
159 CoreRpc::Shutdown => {
160 return;
161 }
162 }
163 }
164 }
165
166 pub fn rx(&self) -> &Receiver<CoreRpc> {
167 &self.rx
168 }
169
170 pub fn handle_response(
171 &self,
172 id: RequestId,
173 response: Result<CoreResponse, RpcError>,
174 ) {
175 let tx = { self.pending.lock().remove(&id) };
176 if let Some(tx) = tx {
177 let _ = tx.send(response);
178 }
179 }
180
181 pub fn request(&self, request: CoreRequest) -> Result<CoreResponse, RpcError> {
182 let (tx, rx) = crossbeam_channel::bounded(1);
183 let id = self.id.fetch_add(1, Ordering::Relaxed);
184 {
185 let mut pending = self.pending.lock();
186 pending.insert(id, tx);
187 }
188 let _ = self.tx.send(CoreRpc::Request(id, request));
189 rx.recv().unwrap_or_else(|_| {
190 Err(RpcError {
191 code: 0,
192 message: "io error".to_string(),
193 })
194 })
195 }
196
197 pub fn shutdown(&self) {
198 let _ = self.tx.send(CoreRpc::Shutdown);
199 }
200
201 pub fn notification(&self, notification: CoreNotification) {
202 let _ = self.tx.send(CoreRpc::Notification(Box::new(notification)));
203 }
204
205 pub fn proxy_connected(&self) {
206 self.notification(CoreNotification::ProxyConnected {});
207 }
208
209 pub fn workspace_file_change(&self) {
210 self.notification(CoreNotification::WorkspaceFileChange {});
211 }
212
213 pub fn diff_info(&self, diff: DiffInfo) {
214 self.notification(CoreNotification::DiffInfo { diff });
215 }
216
217 pub fn open_file_changed(&self, path: PathBuf, content: String) {
218 self.notification(CoreNotification::OpenFileChanged { path, content });
219 }
220
221 pub fn completion_response(
222 &self,
223 request_id: usize,
224 input: String,
225 resp: CompletionResponse,
226 plugin_id: PluginId,
227 ) {
228 self.notification(CoreNotification::CompletionResponse {
229 request_id,
230 input,
231 resp,
232 plugin_id,
233 });
234 }
235
236 pub fn volt_installed(&self, volt: VoltMetadata, only_installing: bool) {
237 self.notification(CoreNotification::VoltInstalled {
238 volt,
239 only_installing,
240 });
241 }
242
243 pub fn volt_installing(&self, volt: VoltMetadata, error: String) {
244 self.notification(CoreNotification::VoltInstalling { volt, error });
245 }
246
247 pub fn volt_removing(&self, volt: VoltMetadata, error: String) {
248 self.notification(CoreNotification::VoltRemoving { volt, error });
249 }
250
251 pub fn volt_removed(&self, volt: VoltInfo, only_installing: bool) {
252 self.notification(CoreNotification::VoltRemoved {
253 volt,
254 only_installing,
255 });
256 }
257
258 pub fn log(&self, level: log::Level, message: String) {
259 self.notification(CoreNotification::Log {
260 level: level.as_str().to_string(),
261 message,
262 });
263 }
264
265 pub fn publish_diagnostics(&self, diagnostics: PublishDiagnosticsParams) {
266 self.notification(CoreNotification::PublishDiagnostics { diagnostics });
267 }
268
269 pub fn work_done_progress(&self, progress: ProgressParams) {
270 self.notification(CoreNotification::WorkDoneProgress { progress });
271 }
272
273 pub fn show_message(&self, title: String, message: ShowMessageParams) {
274 self.notification(CoreNotification::ShowMessage { title, message });
275 }
276
277 pub fn log_message(&self, message: LogMessageParams) {
278 self.notification(CoreNotification::LogMessage { message });
279 }
280
281 pub fn close_terminal(&self, term_id: TermId) {
282 self.notification(CoreNotification::CloseTerminal { term_id });
283 }
284
285 pub fn update_terminal(&self, term_id: TermId, content: String) {
286 self.notification(CoreNotification::UpdateTerminal { term_id, content });
287 }
288}
289
290impl Default for CoreRpcHandler {
291 fn default() -> Self {
292 Self::new()
293 }
294}