1use std::time::UNIX_EPOCH;
9
10use serde_json::json;
11use tonic::{Request, Response, Status};
12use url::Url;
13use CommonLibrary::{
14 Command::CommandExecutor::CommandExecutor,
15 LanguageFeature::{
16 DTO::PositionDTO::PositionDTO,
17 LanguageFeatureProviderRegistry::LanguageFeatureProviderRegistry,
18 },
19};
20use ::Vine::Generated::{GenericRequest as GenericRequestMsg, GenericResponse, RpcError};
21
22use crate::{RPC::CocoonService::CocoonServiceImpl, dev_log};
23
24pub async fn Fn(
25 Service:&CocoonServiceImpl,
26
27 request:Request<GenericRequestMsg>,
28) -> Result<Response<GenericResponse>, Status> {
29 let Req = request.into_inner();
30
31 let RequestId = Req.request_identifier;
32
33 dev_log!(
34 "cocoon",
35 "[CocoonService] generic request: method={} id={}",
36 Req.method,
37 RequestId
38 );
39
40 fn OkResponse(RequestId:u64, Value:&impl serde::Serialize) -> Response<GenericResponse> {
42 let Bytes = serde_json::to_vec(Value).unwrap_or_default();
43
44 Response::new(GenericResponse { request_identifier:RequestId, result:Bytes, error:None })
45 }
46
47 fn ErrResponse(RequestId:u64, Code:i32, Message:String) -> Response<GenericResponse> {
49 Response::new(GenericResponse {
50 request_identifier:RequestId,
51 result:Vec::new(),
52 error:Some(RpcError { code:Code, message:Message, data:Vec::new() }),
53 })
54 }
55
56 let Params:serde_json::Value = if Req.parameter.is_empty() {
58 serde_json::Value::Null
59 } else {
60 serde_json::from_slice(&Req.parameter).unwrap_or(serde_json::Value::Null)
61 };
62
63 match Req.method.as_str() {
64 "fs.readFile" | "file:read" => {
66 let Path = Params
67 .as_str()
68 .or_else(|| Params.get("path").and_then(|V| V.as_str()))
69 .unwrap_or("");
70
71 match tokio::fs::read(Path).await {
72 Ok(Content) => Ok(OkResponse(RequestId, &Content)),
73
74 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("fs.readFile: {}", Error))),
75 }
76 },
77
78 "fs.writeFile" | "file:write" => {
79 let Path = Params.get("path").and_then(|V| V.as_str()).unwrap_or("");
80
81 let Content:Vec<u8> = Params
82 .get("content")
83 .and_then(|V| V.as_array())
84 .map(|A| A.iter().filter_map(|B| B.as_u64().map(|N| N as u8)).collect())
85 .unwrap_or_default();
86
87 match tokio::fs::write(Path, &Content).await {
88 Ok(()) => Ok(OkResponse(RequestId, &serde_json::Value::Null)),
89
90 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("fs.writeFile: {}", Error))),
91 }
92 },
93
94 "fs.stat" | "file:stat" => {
95 let Path = Params
96 .as_str()
97 .or_else(|| Params.get("path").and_then(|V| V.as_str()))
98 .unwrap_or("");
99
100 match tokio::fs::metadata(Path).await {
101 Ok(Meta) => {
102 let Mtime = Meta
103 .modified()
104 .ok()
105 .and_then(|T| T.duration_since(UNIX_EPOCH).ok())
106 .map(|D| D.as_millis() as u64)
107 .unwrap_or(0);
108
109 Ok(OkResponse(
110 RequestId,
111 &json!({
112 "type": if Meta.is_dir() { 2 } else { 1 },
113 "is_file": Meta.is_file(),
114 "is_directory": Meta.is_dir(),
115 "size": Meta.len(),
116 "mtime": Mtime,
117 }),
118 ))
119 },
120
121 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("fs.stat: {}", Error))),
122 }
123 },
124
125 "fs.listDir" | "fs.readdir" | "file:readdir" => {
126 let Path = Params
127 .as_str()
128 .or_else(|| Params.get("path").and_then(|V| V.as_str()))
129 .unwrap_or("");
130
131 match tokio::fs::read_dir(Path).await {
132 Ok(mut Entries) => {
133 let mut Items:Vec<serde_json::Value> = Vec::new();
135
136 while let Ok(Some(Entry)) = Entries.next_entry().await {
137 if let Some(Name) = Entry.file_name().to_str() {
138 let IsDir = Entry.file_type().await.map(|T| T.is_dir()).unwrap_or(false);
139
140 Items.push(json!({ "name": Name, "type": if IsDir { 2u32 } else { 1u32 } }));
141 }
142 }
143
144 Ok(OkResponse(RequestId, &Items))
145 },
146
147 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("fs.listDir: {}", Error))),
148 }
149 },
150
151 "fs.createDir" | "file:mkdir" => {
152 let Path = Params
153 .as_str()
154 .or_else(|| Params.get("path").and_then(|V| V.as_str()))
155 .unwrap_or("");
156
157 match tokio::fs::create_dir_all(Path).await {
158 Ok(()) => Ok(OkResponse(RequestId, &serde_json::Value::Null)),
159
160 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("fs.createDir: {}", Error))),
161 }
162 },
163
164 "fs.delete" | "file:delete" => {
165 let Path = Params
166 .as_str()
167 .or_else(|| Params.get("path").and_then(|V| V.as_str()))
168 .unwrap_or("");
169
170 let Result = if std::path::Path::new(Path).is_dir() {
171 tokio::fs::remove_dir_all(Path).await
172 } else {
173 tokio::fs::remove_file(Path).await
174 };
175
176 match Result {
177 Ok(()) => Ok(OkResponse(RequestId, &serde_json::Value::Null)),
178
179 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("fs.delete: {}", Error))),
180 }
181 },
182
183 "fs.rename" | "file:move" => {
184 let From = Params.get("from").and_then(|V| V.as_str()).unwrap_or("");
185
186 let To = Params.get("to").and_then(|V| V.as_str()).unwrap_or("");
187
188 match tokio::fs::rename(From, To).await {
189 Ok(()) => Ok(OkResponse(RequestId, &serde_json::Value::Null)),
190
191 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("fs.rename: {}", Error))),
192 }
193 },
194
195 "commands.execute" => {
197 let CommandId = Params.get("id").and_then(|V| V.as_str()).unwrap_or("").to_string();
198
199 let Arg = Params.get("arg").cloned().unwrap_or(serde_json::Value::Null);
200
201 match Service.environment.ExecuteCommand(CommandId, Arg).await {
202 Ok(Value) => Ok(OkResponse(RequestId, &Value)),
203
204 Err(Error) => Ok(ErrResponse(RequestId, -32000, Error.to_string())),
205 }
206 },
207
208 "executeCommand" => {
210 let CommandId = Params.get("commandId").and_then(|V| V.as_str()).unwrap_or("").to_string();
211
212 let Arg = Params
213 .get("arguments")
214 .and_then(|A| A.as_array())
215 .and_then(|A| A.first())
216 .cloned()
217 .unwrap_or(serde_json::Value::Null);
218
219 match Service.environment.ExecuteCommand(CommandId, Arg).await {
220 Ok(Value) => Ok(OkResponse(RequestId, &json!({ "result": Value }))),
221
222 Err(Error) => Ok(ErrResponse(RequestId, -32000, Error.to_string())),
223 }
224 },
225
226 "unregisterCommand" => {
227 let ExtensionId = Params.get("extensionId").and_then(|V| V.as_str()).unwrap_or("").to_string();
228
229 let CommandId = Params.get("commandId").and_then(|V| V.as_str()).unwrap_or("").to_string();
230
231 match Service.environment.UnregisterCommand(ExtensionId, CommandId).await {
232 Ok(()) => Ok(OkResponse(RequestId, &json!({ "success": true }))),
233
234 Err(Error) => Ok(ErrResponse(RequestId, -32000, Error.to_string())),
235 }
236 },
237
238 "UserInterface.ShowOpenDialog" => {
240 use CommonLibrary::UserInterface::{
241 DTO::OpenDialogOptionsDTO::OpenDialogOptionsDTO,
242 UserInterfaceProvider::UserInterfaceProvider,
243 };
244
245 let Title = Params
246 .get(0)
247 .and_then(|V| V.get("title"))
248 .and_then(|T| T.as_str())
249 .map(|S| S.to_string());
250
251 let Options = OpenDialogOptionsDTO {
252 Base:CommonLibrary::UserInterface::DTO::DialogOptionsDTO::DialogOptionsDTO {
253 Title,
254 ..Default::default()
255 },
256 ..OpenDialogOptionsDTO::default()
257 };
258
259 match Service.environment.ShowOpenDialog(Some(Options)).await {
260 Ok(Some(Paths)) => {
261 let Uris:Vec<String> = Paths.iter().map(|P| format!("file://{}", P.display())).collect();
262
263 Ok(OkResponse(RequestId, &json!(Uris)))
264 },
265
266 Ok(None) => Ok(OkResponse(RequestId, &json!(serde_json::Value::Array(vec![])))),
267
268 Err(Error) => Ok(ErrResponse(RequestId, -32000, Error.to_string())),
269 }
270 },
271
272 "UserInterface.ShowSaveDialog" => {
273 use CommonLibrary::UserInterface::{
274 DTO::SaveDialogOptionsDTO::SaveDialogOptionsDTO,
275 UserInterfaceProvider::UserInterfaceProvider,
276 };
277
278 let Title = Params
279 .get(0)
280 .and_then(|V| V.get("title"))
281 .and_then(|T| T.as_str())
282 .map(|S| S.to_string());
283
284 let Options = SaveDialogOptionsDTO {
285 Base:CommonLibrary::UserInterface::DTO::DialogOptionsDTO::DialogOptionsDTO {
286 Title,
287 ..Default::default()
288 },
289 ..SaveDialogOptionsDTO::default()
290 };
291
292 match Service.environment.ShowSaveDialog(Some(Options)).await {
293 Ok(Some(Path)) => Ok(OkResponse(RequestId, &json!(format!("file://{}", Path.display())))),
294
295 Ok(None) => Ok(OkResponse(RequestId, &serde_json::Value::Null)),
296
297 Err(Error) => Ok(ErrResponse(RequestId, -32000, Error.to_string())),
298 }
299 },
300
301 "UserInterface.ShowInputBox" => {
302 use CommonLibrary::UserInterface::{
303 DTO::InputBoxOptionsDTO::InputBoxOptionsDTO,
304 UserInterfaceProvider::UserInterfaceProvider,
305 };
306
307 let Opts = Params.get(0);
308
309 let Options = InputBoxOptionsDTO {
310 Prompt:Opts
311 .and_then(|V| V.get("prompt"))
312 .and_then(|P| P.as_str())
313 .map(|S| S.to_string()),
314
315 PlaceHolder:Opts
316 .and_then(|V| V.get("placeHolder"))
317 .and_then(|P| P.as_str())
318 .map(|S| S.to_string()),
319
320 IsPassword:Some(Opts.and_then(|V| V.get("password")).and_then(|B| B.as_bool()).unwrap_or(false)),
321
322 Value:Opts
323 .and_then(|V| V.get("value"))
324 .and_then(|V| V.as_str())
325 .map(|S| S.to_string()),
326
327 Title:None,
328
329 IgnoreFocusOut:None,
330 };
331
332 match Service.environment.ShowInputBox(Some(Options)).await {
333 Ok(Some(Text)) => Ok(OkResponse(RequestId, &json!(Text))),
334
335 Ok(None) => Ok(OkResponse(RequestId, &serde_json::Value::Null)),
336
337 Err(Error) => Ok(ErrResponse(RequestId, -32000, Error.to_string())),
338 }
339 },
340
341 "openExternal" => {
343 use tauri::Emitter;
344
345 let Url = Params
346 .as_str()
347 .or_else(|| Params.get("url").and_then(|V| V.as_str()))
348 .unwrap_or("")
349 .to_string();
350
351 let _ = Service
353 .environment
354 .ApplicationHandle
355 .emit("sky://native/openExternal", json!({ "url": Url }));
356
357 Ok(OkResponse(RequestId, &json!({ "success": true })))
358 },
359
360 "showTextDocument" => {
362 use tauri::Emitter;
363
364 let Uri = Params
365 .get("uri")
366 .and_then(|V| V.get("value").or(Some(V)))
367 .and_then(|V| V.as_str())
368 .unwrap_or("")
369 .to_string();
370
371 let ViewColumn = Params.get("viewColumn").and_then(|V| V.as_i64()).map(|N| N + 2);
372
373 let PreserveFocus = Params.get("preserveFocus").and_then(|V| V.as_bool()).unwrap_or(false);
374
375 let _ = Service.environment.ApplicationHandle.emit(
376 "sky://editor/openDocument",
377 json!({ "uri": Uri, "viewColumn": ViewColumn, "preserveFocus": PreserveFocus }),
378 );
379
380 Ok(OkResponse(RequestId, &json!({ "success": true })))
381 },
382
383 "showInformation" => {
384 use CommonLibrary::UserInterface::{
385 DTO::MessageSeverity::MessageSeverity,
386 UserInterfaceProvider::UserInterfaceProvider,
387 };
388
389 let Message = Params.get("message").and_then(|V| V.as_str()).unwrap_or("").to_string();
390
391 let Items:Option<serde_json::Value> = Params
392 .get("items")
393 .cloned()
394 .filter(|V| V.is_array() && !V.as_array().unwrap().is_empty());
395
396 match Service.environment.ShowMessage(MessageSeverity::Info, Message, Items).await {
397 Ok(Some(Selected)) => Ok(OkResponse(RequestId, &json!({ "selectedItem": Selected }))),
398
399 Ok(None) => Ok(OkResponse(RequestId, &serde_json::Value::Null)),
400
401 Err(Error) => Ok(ErrResponse(RequestId, -32000, Error.to_string())),
402 }
403 },
404
405 "showWarning" => {
406 use CommonLibrary::UserInterface::{
407 DTO::MessageSeverity::MessageSeverity,
408 UserInterfaceProvider::UserInterfaceProvider,
409 };
410
411 let Message = Params.get("message").and_then(|V| V.as_str()).unwrap_or("").to_string();
412
413 let Items:Option<serde_json::Value> = Params
414 .get("items")
415 .cloned()
416 .filter(|V| V.is_array() && !V.as_array().unwrap().is_empty());
417
418 match Service.environment.ShowMessage(MessageSeverity::Warning, Message, Items).await {
419 Ok(Some(Selected)) => Ok(OkResponse(RequestId, &json!({ "selectedItem": Selected }))),
420
421 Ok(None) => Ok(OkResponse(RequestId, &serde_json::Value::Null)),
422
423 Err(Error) => Ok(ErrResponse(RequestId, -32000, Error.to_string())),
424 }
425 },
426
427 "showError" => {
428 use CommonLibrary::UserInterface::{
429 DTO::MessageSeverity::MessageSeverity,
430 UserInterfaceProvider::UserInterfaceProvider,
431 };
432
433 let Message = Params.get("message").and_then(|V| V.as_str()).unwrap_or("").to_string();
434
435 let Items:Option<serde_json::Value> = Params
436 .get("items")
437 .cloned()
438 .filter(|V| V.is_array() && !V.as_array().unwrap().is_empty());
439
440 match Service.environment.ShowMessage(MessageSeverity::Error, Message, Items).await {
441 Ok(Some(Selected)) => Ok(OkResponse(RequestId, &json!({ "selectedItem": Selected }))),
442
443 Ok(None) => Ok(OkResponse(RequestId, &serde_json::Value::Null)),
444
445 Err(Error) => Ok(ErrResponse(RequestId, -32000, Error.to_string())),
446 }
447 },
448
449 "createStatusBarItem" => {
450 use tauri::Emitter;
451
452 let Id = Params.get("id").and_then(|V| V.as_str()).unwrap_or("").to_string();
453
454 let Text = Params.get("text").and_then(|V| V.as_str()).unwrap_or("").to_string();
455
456 let Tooltip = Params.get("tooltip").and_then(|V| V.as_str()).unwrap_or("").to_string();
457
458 let _ = Service.environment.ApplicationHandle.emit(
465 "sky://statusbar/set-entry",
466 json!({ "id": Id, "text": Text, "tooltip": Tooltip }),
467 );
468
469 Ok(OkResponse(RequestId, &json!({ "itemId": Id })))
470 },
471
472 "setStatusBarText" => {
473 use tauri::Emitter;
474
475 let ItemId = Params.get("itemId").and_then(|V| V.as_str()).unwrap_or("").to_string();
476
477 let Text = Params.get("text").and_then(|V| V.as_str()).unwrap_or("").to_string();
478
479 let _ = Service
480 .environment
481 .ApplicationHandle
482 .emit("sky://statusbar/update", json!({ "id": ItemId, "text": Text }));
483
484 Ok(OkResponse(RequestId, &json!({ "success": true })))
485 },
486
487 "createWebviewPanel" => {
488 use tauri::Emitter;
489
490 let ViewType = Params.get("viewType").and_then(|V| V.as_str()).unwrap_or("").to_string();
491
492 let Title = Params.get("title").and_then(|V| V.as_str()).unwrap_or("").to_string();
493
494 let Handle = std::time::SystemTime::now()
495 .duration_since(std::time::UNIX_EPOCH)
496 .map(|D| D.as_millis() as u64)
497 .unwrap_or(0);
498
499 let _ = Service.environment.ApplicationHandle.emit("sky://webview/create", json!({ "handle": Handle, "viewType": ViewType, "title": Title, "viewColumn": Params.get("viewColumn"), "preserveFocus": Params.get("preserveFocus").and_then(|V| V.as_bool()).unwrap_or(false) }));
500
501 Ok(OkResponse(RequestId, &json!({ "handle": Handle })))
502 },
503
504 "setWebviewHtml" => {
505 use tauri::Emitter;
506
507 let Handle = Params.get("handle").and_then(|V| V.as_u64()).unwrap_or(0);
508
509 let Html = Params.get("html").and_then(|V| V.as_str()).unwrap_or("").to_string();
510
511 let _ = Service
513 .environment
514 .ApplicationHandle
515 .emit("sky://webview/set-html", json!({ "handle": Handle, "html": Html }));
516
517 Ok(OkResponse(RequestId, &json!({ "success": true })))
518 },
519
520 "findFiles" => {
532 use CommonLibrary::Workspace::WorkspaceProvider::WorkspaceProvider;
533
534 let Include = Params
535 .get("pattern")
536 .cloned()
537 .or_else(|| Params.get("include").cloned())
538 .unwrap_or(serde_json::Value::String("**".into()));
539
540 let Exclude = Params.get("exclude").cloned().filter(|V| !V.is_null());
541
542 let MaxResults = Params.get("maxResults").and_then(|V| V.as_u64()).map(|N| N as usize);
543
544 let UseIgnoreFiles = Params.get("useIgnoreFiles").and_then(|V| V.as_bool()).unwrap_or(true);
545
546 let FollowSymlinks = Params.get("followSymlinks").and_then(|V| V.as_bool()).unwrap_or(false);
547
548 match Service
549 .environment
550 .FindFilesInWorkspace(Include, Exclude, MaxResults, UseIgnoreFiles, FollowSymlinks)
551 .await
552 {
553 Ok(Urls) => {
554 Ok(OkResponse(
555 RequestId,
556 &json!({ "uris": Urls.into_iter().map(|U| U.to_string()).collect::<Vec<_>>() }),
557 ))
558 },
559
560 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("findFiles: {}", Error))),
561 }
562 },
563
564 "findTextInFiles" => {
565 use CommonLibrary::Search::SearchProvider::SearchProvider;
566
567 let QueryValue = if Params.get("pattern").map(|V| V.is_object()).unwrap_or(false) {
571 Params.get("pattern").cloned().unwrap_or(serde_json::Value::Null)
572 } else if Params.get("pattern").map(|V| V.is_string()).unwrap_or(false) {
573 json!({
574 "pattern": Params.get("pattern").and_then(|V| V.as_str()).unwrap_or(""),
575 "isRegExp": Params.get("isRegExp").and_then(|V| V.as_bool()).unwrap_or(false),
576 "isCaseSensitive": Params.get("isCaseSensitive").and_then(|V| V.as_bool()).unwrap_or(false),
577 "isWordMatch": Params.get("isWordMatch").and_then(|V| V.as_bool()).unwrap_or(false),
578 })
579 } else {
580 Params.clone()
581 };
582
583 let OptionsValue = Params.get("options").cloned().unwrap_or(serde_json::Value::Null);
584
585 match Service.environment.TextSearch(QueryValue, OptionsValue).await {
586 Ok(Matches) => Ok(OkResponse(RequestId, &json!({ "matches": Matches }))),
587
588 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("findTextInFiles: {}", Error))),
589 }
590 },
591
592 "openDocument" => {
593 use tauri::Emitter;
594
595 let Uri = Params
596 .get("uri")
597 .and_then(|V| V.get("value").or(Some(V)))
598 .and_then(|V| V.as_str())
599 .unwrap_or("")
600 .to_string();
601
602 let ViewColumn = Params.get("viewColumn").and_then(|V| V.as_i64());
603
604 let _ = Service
605 .environment
606 .ApplicationHandle
607 .emit("sky://editor/openDocument", json!({ "uri": Uri, "viewColumn": ViewColumn }));
608
609 Ok(OkResponse(RequestId, &json!({ "success": true })))
610 },
611
612 "saveAll" => {
613 use tauri::Emitter;
614
615 let IncludeUntitled = Params.get("includeUntitled").and_then(|V| V.as_bool()).unwrap_or(false);
616
617 let _ = Service
618 .environment
619 .ApplicationHandle
620 .emit("sky://editor/saveAll", json!({ "includeUntitled": IncludeUntitled }));
621
622 Ok(OkResponse(RequestId, &json!({ "success": true })))
623 },
624
625 "applyEdit" => {
626 use tauri::Emitter;
627
628 let Uri = Params
629 .get("uri")
630 .and_then(|V| V.get("value").or(Some(V)))
631 .and_then(|V| V.as_str())
632 .unwrap_or("")
633 .to_string();
634
635 let Edits = Params.get("edits").cloned().unwrap_or(json!([]));
636
637 let _ = Service
638 .environment
639 .ApplicationHandle
640 .emit("sky://editor/applyEdits", json!({ "uri": Uri, "edits": Edits }));
641
642 Ok(OkResponse(RequestId, &json!({ "success": true })))
643 },
644
645 "getSecret" => {
647 use CommonLibrary::Secret::SecretProvider::SecretProvider;
648
649 let ExtensionId = Params.get("extensionId").and_then(|V| V.as_str()).unwrap_or("").to_string();
650
651 let Key = Params.get("key").and_then(|V| V.as_str()).unwrap_or("").to_string();
652
653 match Service.environment.GetSecret(ExtensionId, Key).await {
654 Ok(Some(Value)) => Ok(OkResponse(RequestId, &json!({ "value": Value }))),
655
656 Ok(None) => Ok(OkResponse(RequestId, &serde_json::Value::Null)),
657
658 Err(Error) => Ok(ErrResponse(RequestId, -32000, Error.to_string())),
659 }
660 },
661
662 "storeSecret" => {
663 use CommonLibrary::Secret::SecretProvider::SecretProvider;
664
665 let ExtensionId = Params.get("extensionId").and_then(|V| V.as_str()).unwrap_or("").to_string();
666
667 let Key = Params.get("key").and_then(|V| V.as_str()).unwrap_or("").to_string();
668
669 let Value = Params.get("value").and_then(|V| V.as_str()).unwrap_or("").to_string();
670
671 match Service.environment.StoreSecret(ExtensionId, Key, Value).await {
672 Ok(()) => Ok(OkResponse(RequestId, &json!({ "success": true }))),
673
674 Err(Error) => Ok(ErrResponse(RequestId, -32000, Error.to_string())),
675 }
676 },
677
678 "deleteSecret" => {
679 use CommonLibrary::Secret::SecretProvider::SecretProvider;
680
681 let ExtensionId = Params.get("extensionId").and_then(|V| V.as_str()).unwrap_or("").to_string();
682
683 let Key = Params.get("key").and_then(|V| V.as_str()).unwrap_or("").to_string();
684
685 match Service.environment.DeleteSecret(ExtensionId, Key).await {
686 Ok(()) => Ok(OkResponse(RequestId, &json!({ "success": true }))),
687
688 Err(Error) => Ok(ErrResponse(RequestId, -32000, Error.to_string())),
689 }
690 },
691
692 "readFile" => {
694 let Uri = Params
695 .get("uri")
696 .and_then(|V| V.as_str())
697 .or_else(|| Params.as_str())
698 .unwrap_or("")
699 .replace("file://", "");
700
701 match tokio::fs::read(&Uri).await {
702 Ok(Content) => Ok(OkResponse(RequestId, &Content)),
703
704 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("readFile: {}", Error))),
705 }
706 },
707
708 "writeFile" => {
709 let Uri = Params.get("uri").and_then(|V| V.as_str()).unwrap_or("").replace("file://", "");
710
711 let Content:Vec<u8> = Params
712 .get("content")
713 .and_then(|V| V.as_array())
714 .map(|A| A.iter().filter_map(|B| B.as_u64().map(|N| N as u8)).collect())
715 .unwrap_or_default();
716
717 match tokio::fs::write(&Uri, &Content).await {
718 Ok(()) => Ok(OkResponse(RequestId, &serde_json::Value::Null)),
719
720 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("writeFile: {}", Error))),
721 }
722 },
723
724 "stat" => {
725 let Uri = Params
726 .get("uri")
727 .and_then(|V| V.as_str())
728 .or_else(|| Params.as_str())
729 .unwrap_or("")
730 .replace("file://", "");
731
732 match tokio::fs::metadata(&Uri).await {
733 Ok(Meta) => {
734 let Mtime = Meta
735 .modified()
736 .ok()
737 .and_then(|T| T.duration_since(UNIX_EPOCH).ok())
738 .map(|D| D.as_millis() as u64)
739 .unwrap_or(0);
740
741 Ok(OkResponse(
742 RequestId,
743 &json!({ "type": if Meta.is_dir() { 2 } else { 1 }, "is_file": Meta.is_file(), "is_directory": Meta.is_dir(), "size": Meta.len(), "mtime": Mtime }),
744 ))
745 },
746
747 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("stat: {}", Error))),
748 }
749 },
750
751 "readdir" => {
752 let Uri = Params
753 .get("uri")
754 .and_then(|V| V.as_str())
755 .or_else(|| Params.as_str())
756 .unwrap_or("")
757 .replace("file://", "");
758
759 match tokio::fs::read_dir(&Uri).await {
760 Ok(mut Entries) => {
761 let mut Names:Vec<String> = Vec::new();
762
763 while let Ok(Some(Entry)) = Entries.next_entry().await {
764 if let Some(Name) = Entry.file_name().to_str() {
765 Names.push(Name.to_string());
766 }
767 }
768
769 Ok(OkResponse(RequestId, &Names))
770 },
771
772 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("readdir: {}", Error))),
773 }
774 },
775
776 "$provideCallHierarchyItems" | "prepareCallHierarchy" => {
783 let URI_Raw = Params.get("uri").and_then(|V| V.as_str()).unwrap_or("");
784
785 let Line = Params
786 .get("position")
787 .and_then(|P| P.get("line"))
788 .and_then(|V| V.as_u64())
789 .unwrap_or(0);
790
791 let Char = Params
792 .get("position")
793 .and_then(|P| P.get("character"))
794 .and_then(|V| V.as_u64())
795 .unwrap_or(0);
796
797 match Url::parse(URI_Raw) {
798 Ok(DocURI) => {
799 let Pos = PositionDTO { LineNumber:Line as u32, Column:Char as u32 };
800
801 match Service.environment.PrepareCallHierarchy(DocURI, Pos).await {
802 Ok(Result) => Ok(OkResponse(RequestId, &Result)),
803
804 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("prepareCallHierarchy: {}", Error))),
805 }
806 },
807
808 Err(_) => Ok(OkResponse(RequestId, &serde_json::Value::Array(Vec::new()))),
809 }
810 },
811
812 "$provideTypeHierarchyItems" | "prepareTypeHierarchy" => {
813 let URI_Raw = Params.get("uri").and_then(|V| V.as_str()).unwrap_or("");
814
815 let Line = Params
816 .get("position")
817 .and_then(|P| P.get("line"))
818 .and_then(|V| V.as_u64())
819 .unwrap_or(0);
820
821 let Char = Params
822 .get("position")
823 .and_then(|P| P.get("character"))
824 .and_then(|V| V.as_u64())
825 .unwrap_or(0);
826
827 match Url::parse(URI_Raw) {
828 Ok(DocURI) => {
829 let Pos = PositionDTO { LineNumber:Line as u32, Column:Char as u32 };
830
831 match Service.environment.PrepareTypeHierarchy(DocURI, Pos).await {
832 Ok(Result) => Ok(OkResponse(RequestId, &Result)),
833
834 Err(Error) => Ok(ErrResponse(RequestId, -32000, format!("prepareTypeHierarchy: {}", Error))),
835 }
836 },
837
838 Err(_) => Ok(OkResponse(RequestId, &serde_json::Value::Array(Vec::new()))),
839 }
840 },
841
842 _ => {
844 dev_log!("cocoon", "warn: [CocoonService] Unknown generic method: {}", Req.method);
845
846 Ok(ErrResponse(RequestId, -32601, format!("Method '{}' not found", Req.method)))
847 },
848 }
849}