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