1#![allow(unused_imports)]
2
3use std::{future::Future, pin::Pin, sync::Arc};
106
107use base64::{Engine as _, engine::general_purpose::STANDARD};
108use CommonLibrary::{
109 Command::CommandExecutor::CommandExecutor,
110 Configuration::{
111 ConfigurationInspector::ConfigurationInspector,
112 ConfigurationProvider::ConfigurationProvider,
113 DTO::ConfigurationTarget::ConfigurationTarget,
114 },
115 CustomEditor::CustomEditorProvider::CustomEditorProvider,
116 Debug::DebugService::DebugService,
117 Diagnostic::DiagnosticManager::DiagnosticManager,
118 Document::DocumentProvider::DocumentProvider,
119 Environment::Requires::Requires,
120 FileSystem::{FileSystemReader::FileSystemReader, FileSystemWriter::FileSystemWriter},
121 Keybinding::KeybindingProvider::KeybindingProvider,
122 LanguageFeature::{
123 DTO::ProviderType::ProviderType,
124 LanguageFeatureProviderRegistry::LanguageFeatureProviderRegistry,
125 },
126 Search::SearchProvider::SearchProvider,
127 SourceControlManagement::SourceControlManagementProvider::SourceControlManagementProvider,
128 StatusBar::{DTO::StatusBarEntryDTO::StatusBarEntryDTO, StatusBarProvider::StatusBarProvider},
129 Storage::StorageProvider::StorageProvider,
130 Terminal::TerminalProvider::TerminalProvider,
131 TreeView::TreeViewProvider::TreeViewProvider,
132 UserInterface::{DTO::MessageSeverity::MessageSeverity, UserInterfaceProvider::UserInterfaceProvider},
133 Webview::WebviewProvider,
134};
135use serde_json::{Value, json};
136use tauri::{AppHandle, Runtime};
137use url::Url;
138
139use crate::{RunTime::ApplicationRunTime::ApplicationRunTime, Track::Effect::MappedEffectType::MappedEffect};
140use crate::dev_log;
141
142pub fn CreateEffectForRequest<R:Runtime>(
155 _ApplicationHandle:&AppHandle<R>,
156 MethodName:&str,
157 Parameters:Value,
158) -> Result<MappedEffect, String> {
159 match MethodName {
160 "Configuration.Inspect" => {
162 let effect =
163 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
164 Box::pin(async move {
165 let provider:Arc<dyn ConfigurationInspector> = run_time.Environment.Require();
166 let section = Parameters.get(0).and_then(Value::as_str).unwrap_or("").to_string();
167 let result = provider.InspectConfigurationValue(section, Default::default()).await;
168 result.map(|_opt_dto| json!(null)).map_err(|e| e.to_string())
169 })
170 };
171 Ok(Box::new(effect))
172 },
173
174 "Configuration.Update" => {
175 let effect =
176 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
177 Box::pin(async move {
178 let provider:Arc<dyn ConfigurationProvider> = run_time.Environment.Require();
179 let key = Parameters.get(0).and_then(Value::as_str).unwrap_or("").to_string();
180 let value = Parameters.get(1).cloned().unwrap_or_default();
181 let target = match Parameters.get(2).and_then(Value::as_u64) {
182 Some(0) => ConfigurationTarget::User,
183 Some(1) => ConfigurationTarget::Workspace,
184 _ => ConfigurationTarget::User,
185 };
186 let result = provider
187 .UpdateConfigurationValue(key, value, target, Default::default(), None)
188 .await;
189 result.map(|_| json!(null)).map_err(|e| e.to_string())
190 })
191 };
192 Ok(Box::new(effect))
193 },
194
195 "Diagnostic.Set" => {
197 let effect =
198 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
199 Box::pin(async move {
200 let provider:Arc<dyn DiagnosticManager> = run_time.Environment.Require();
201 let owner = Parameters.get(0).and_then(Value::as_str).unwrap_or("").to_string();
202 let entries = Parameters.get(1).cloned().unwrap_or_default();
203 provider
204 .SetDiagnostics(owner, entries)
205 .await
206 .map(|_| json!(null))
207 .map_err(|e| e.to_string())
208 })
209 };
210 Ok(Box::new(effect))
211 },
212
213 "Diagnostic.Clear" => {
214 let effect =
215 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
216 Box::pin(async move {
217 let provider:Arc<dyn DiagnosticManager> = run_time.Environment.Require();
218 let owner = Parameters.get(0).and_then(Value::as_str).unwrap_or("").to_string();
219 provider
220 .ClearDiagnostics(owner)
221 .await
222 .map(|_| json!(null))
223 .map_err(|e| e.to_string())
224 })
225 };
226 Ok(Box::new(effect))
227 },
228
229 "$languageFeatures:registerProvider" => {
231 let effect =
232 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
233 Box::pin(async move {
234 let provider:Arc<dyn LanguageFeatureProviderRegistry> = run_time.Environment.Require();
235 let id = Parameters.get(0).and_then(Value::as_str).unwrap_or("").to_string();
236 let selector = Parameters.get(1).cloned().unwrap_or_default();
237 let extension_id = Parameters.get(2).cloned().unwrap_or_default();
238 let options = Parameters.get(3).cloned();
239 provider
240 .RegisterProvider(id, ProviderType::Hover, selector, extension_id, options)
241 .await
242 .map(|handle| json!(handle))
243 .map_err(|e| e.to_string())
244 })
245 };
246 Ok(Box::new(effect))
247 },
248
249 "Document.Save" => {
251 let effect =
252 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
253 Box::pin(async move {
254 let document_provider:Arc<dyn DocumentProvider> = run_time.Environment.Require();
255 let uri_str = Parameters.get(0).and_then(Value::as_str).unwrap_or("");
256 let uri = Url::parse(uri_str).unwrap_or_else(|_| Url::parse("file:///tmp/test.txt").unwrap());
257 document_provider
258 .SaveDocument(uri)
259 .await
260 .map(|success| json!(success))
261 .map_err(|e| e.to_string())
262 })
263 };
264 Ok(Box::new(effect))
265 },
266
267 "Document.SaveAs" => {
268 let effect =
269 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
270 Box::pin(async move {
271 let document_provider:Arc<dyn DocumentProvider> = run_time.Environment.Require();
272 let original_uri_str = Parameters.get(0).and_then(Value::as_str).unwrap_or("");
273 let original_uri = Url::parse(original_uri_str)
274 .unwrap_or_else(|_| Url::parse("file:///tmp/test.txt").unwrap());
275 let target_uri = Parameters
276 .get(1)
277 .and_then(Value::as_str)
278 .map(Url::parse)
279 .transpose()
280 .unwrap_or(None);
281 document_provider
282 .SaveDocumentAs(original_uri, target_uri)
283 .await
284 .map(|uri_option| json!(uri_option))
285 .map_err(|e| e.to_string())
286 })
287 };
288 Ok(Box::new(effect))
289 },
290
291 "FileSystem.ReadFile" => {
293 let effect =
294 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
295 Box::pin(async move {
296 let fs_reader:Arc<dyn FileSystemReader> = run_time.Environment.Require();
297 let path_str = Parameters.get(0).and_then(Value::as_str).unwrap_or("");
298 let path = std::path::PathBuf::from(path_str);
299 fs_reader
300 .ReadFile(&path)
301 .await
302 .map(|bytes| json!(bytes))
303 .map_err(|e| e.to_string())
304 })
305 };
306 Ok(Box::new(effect))
307 },
308
309 "FileSystem.WriteFile" => {
310 let effect =
311 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
312 Box::pin(async move {
313 let fs_writer:Arc<dyn FileSystemWriter> = run_time.Environment.Require();
314 let path_str = Parameters.get(0).and_then(Value::as_str).unwrap_or("");
315 let path = std::path::PathBuf::from(path_str);
316 let content = Parameters.get(1).cloned();
317 let content_bytes = match content {
318 Some(Value::Array(arr)) => {
319 arr.into_iter().filter_map(|v| v.as_u64().map(|n| n as u8)).collect()
320 },
321 Some(Value::String(s)) => STANDARD.decode(&s).unwrap_or_default(),
322 _ => vec![],
323 };
324 fs_writer
325 .WriteFile(&path, content_bytes, true, true)
326 .await
327 .map(|_| json!(null))
328 .map_err(|e| e.to_string())
329 })
330 };
331 Ok(Box::new(effect))
332 },
333
334 "FileSystem.ReadDirectory" => {
335 let effect =
336 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
337 Box::pin(async move {
338 let fs_reader:Arc<dyn FileSystemReader> = run_time.Environment.Require();
339 let path_str = Parameters.get(0).and_then(Value::as_str).unwrap_or("");
340 let path = std::path::PathBuf::from(path_str);
341 fs_reader
342 .ReadDirectory(&path)
343 .await
344 .map(|entries| json!(entries))
345 .map_err(|e| e.to_string())
346 })
347 };
348 Ok(Box::new(effect))
349 },
350
351 "FileSystem.Stat" => {
352 let effect =
353 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
354 Box::pin(async move {
355 let fs_reader:Arc<dyn FileSystemReader> = run_time.Environment.Require();
356 let path_str = Parameters.get(0).and_then(Value::as_str).unwrap_or("");
357 let path = std::path::PathBuf::from(path_str);
358 fs_reader
359 .StatFile(&path)
360 .await
361 .map(|stat| json!(stat))
362 .map_err(|e| e.to_string())
363 })
364 };
365 Ok(Box::new(effect))
366 },
367
368 "FileSystem.CreateDirectory" => {
369 let effect =
370 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
371 Box::pin(async move {
372 let fs_writer:Arc<dyn FileSystemWriter> = run_time.Environment.Require();
373 let path_str = Parameters.get(0).and_then(Value::as_str).unwrap_or("");
374 let path = std::path::PathBuf::from(path_str);
375 fs_writer
376 .CreateDirectory(&path, true)
377 .await
378 .map(|_| json!(null))
379 .map_err(|e| e.to_string())
380 })
381 };
382 Ok(Box::new(effect))
383 },
384
385 "FileSystem.Delete" => {
386 let effect =
387 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
388 Box::pin(async move {
389 let fs_writer:Arc<dyn FileSystemWriter> = run_time.Environment.Require();
390 let path_str = Parameters.get(0).and_then(Value::as_str).unwrap_or("");
391 let path = std::path::PathBuf::from(path_str);
392 let recursive = Parameters.get(1).and_then(Value::as_bool).unwrap_or(false);
393 fs_writer
394 .Delete(&path, recursive, false)
395 .await
396 .map(|_| json!(null))
397 .map_err(|e| e.to_string())
398 })
399 };
400 Ok(Box::new(effect))
401 },
402
403 "FileSystem.Rename" => {
404 let effect =
405 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
406 Box::pin(async move {
407 let fs_writer:Arc<dyn FileSystemWriter> = run_time.Environment.Require();
408 let source = Parameters.get(0).and_then(Value::as_str).unwrap_or("");
409 let target = Parameters.get(1).and_then(Value::as_str).unwrap_or("");
410 fs_writer
411 .Rename(
412 &std::path::PathBuf::from(source),
413 &std::path::PathBuf::from(target),
414 true,
415 )
416 .await
417 .map(|_| json!(null))
418 .map_err(|e| e.to_string())
419 })
420 };
421 Ok(Box::new(effect))
422 },
423
424 "FileSystem.Copy" => {
425 let effect =
426 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
427 Box::pin(async move {
428 let fs_writer:Arc<dyn FileSystemWriter> = run_time.Environment.Require();
429 let source = Parameters.get(0).and_then(Value::as_str).unwrap_or("");
430 let target = Parameters.get(1).and_then(Value::as_str).unwrap_or("");
431 fs_writer
432 .Copy(
433 &std::path::PathBuf::from(source),
434 &std::path::PathBuf::from(target),
435 true,
436 )
437 .await
438 .map(|_| json!(null))
439 .map_err(|e| e.to_string())
440 })
441 };
442 Ok(Box::new(effect))
443 },
444
445 "Keybinding.GetResolved" => {
447 let effect =
448 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
449 Box::pin(async move {
450 let provider:Arc<dyn KeybindingProvider> = run_time.Environment.Require();
451 provider.GetResolvedKeybinding().await.map_err(|e| e.to_string())
452 })
453 };
454 Ok(Box::new(effect))
455 },
456
457 "Search.TextSearch" => {
459 let effect =
460 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
461 Box::pin(async move {
462 let provider:Arc<dyn SearchProvider> = run_time.Environment.Require();
463 let query = Parameters.get(0).cloned().unwrap_or_default();
464 let options = Parameters.get(1).cloned().unwrap_or_default();
465 provider.TextSearch(query, options).await.map_err(|e| e.to_string())
466 })
467 };
468 Ok(Box::new(effect))
469 },
470
471 "Storage.Get" => {
473 let effect =
474 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
475 Box::pin(async move {
476 let provider:Arc<dyn StorageProvider> = run_time.Environment.Require();
477 let key = Parameters.get(0).and_then(Value::as_str).unwrap_or("").to_string();
478 provider
479 .GetStorageValue(false, &key)
480 .await
481 .map(|opt_val| json!(opt_val))
482 .map_err(|e| e.to_string())
483 })
484 };
485 Ok(Box::new(effect))
486 },
487
488 "Storage.Set" => {
489 let effect =
490 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
491 Box::pin(async move {
492 let provider:Arc<dyn StorageProvider> = run_time.Environment.Require();
493 let key = Parameters.get(0).and_then(Value::as_str).unwrap_or("").to_string();
494 let value = Parameters.get(1).cloned();
495 provider
496 .UpdateStorageValue(false, key, value)
497 .await
498 .map(|_| json!(null))
499 .map_err(|e| e.to_string())
500 })
501 };
502 Ok(Box::new(effect))
503 },
504
505 "Command.Execute" => {
507 let effect =
508 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
509 Box::pin(async move {
510 let command_executor:Arc<dyn CommandExecutor> = run_time.Environment.Require();
511 let command_id = Parameters.get(0).and_then(Value::as_str).unwrap_or("").to_string();
512 let args = Parameters.get(1).cloned().unwrap_or_default();
513 command_executor
514 .ExecuteCommand(command_id, args)
515 .await
516 .map_err(|e| e.to_string())
517 })
518 };
519 Ok(Box::new(effect))
520 },
521
522 "Command.GetAll" => {
523 let effect =
524 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
525 Box::pin(async move {
526 let provider:Arc<dyn CommandExecutor> = run_time.Environment.Require();
527 provider
528 .GetAllCommands()
529 .await
530 .map(|cmds| json!(cmds))
531 .map_err(|e| e.to_string())
532 })
533 };
534 Ok(Box::new(effect))
535 },
536
537 "$statusBar:set" => {
539 let effect =
540 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
541 Box::pin(async move {
542 let provider:Arc<dyn StatusBarProvider> = run_time.Environment.Require();
543 let text = Parameters.get(0).and_then(Value::as_str).unwrap_or("status").to_string();
545 let entry = StatusBarEntryDTO {
546 EntryIdentifier:"id".to_string(),
547 ItemIdentifier:"item".to_string(),
548 ExtensionIdentifier:"ext".to_string(),
549 Name:None,
550 Text:text,
551 Tooltip:None,
552 HasTooltipProvider:false,
553 Command:None,
554 Color:None,
555 BackgroundColor:None,
556 IsAlignedLeft:false,
557 Priority:None,
558 AccessibilityInformation:None,
559 };
560 provider
561 .SetStatusBarEntry(entry)
562 .await
563 .map(|_| json!(null))
564 .map_err(|e| e.to_string())
565 })
566 };
567 Ok(Box::new(effect))
568 },
569
570 "$statusBar:dispose" => {
571 let effect =
572 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
573 Box::pin(async move {
574 let provider:Arc<dyn StatusBarProvider> = run_time.Environment.Require();
575 let id = Parameters.get(0).and_then(Value::as_str).unwrap_or("id").to_string();
576 provider
577 .DisposeStatusBarEntry(id)
578 .await
579 .map(|_| json!(null))
580 .map_err(|e| e.to_string())
581 })
582 };
583 Ok(Box::new(effect))
584 },
585
586 "$setStatusBarMessage" => {
587 let effect =
588 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
589 Box::pin(async move {
590 let provider:Arc<dyn StatusBarProvider> = run_time.Environment.Require();
591 let message_id = Parameters.get(0).and_then(Value::as_str).unwrap_or("msg_id").to_string();
592 let text = Parameters.get(1).and_then(Value::as_str).unwrap_or("message").to_string();
593 provider
594 .SetStatusBarMessage(message_id, text)
595 .await
596 .map(|_| json!(null))
597 .map_err(|e| e.to_string())
598 })
599 };
600 Ok(Box::new(effect))
601 },
602
603 "$disposeStatusBarMessage" => {
604 let effect =
605 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
606 Box::pin(async move {
607 let provider:Arc<dyn StatusBarProvider> = run_time.Environment.Require();
608 let message_id = Parameters.get(0).and_then(Value::as_str).unwrap_or("msg_id").to_string();
609 provider
610 .DisposeStatusBarMessage(message_id)
611 .await
612 .map(|_| json!(null))
613 .map_err(|e| e.to_string())
614 })
615 };
616 Ok(Box::new(effect))
617 },
618
619 "UserInterface.ShowMessage" => {
621 let effect =
622 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
623 Box::pin(async move {
624 let provider:Arc<dyn UserInterfaceProvider> = run_time.Environment.Require();
625 let severity_str = Parameters.get(0).and_then(Value::as_str).unwrap_or("info");
626 let message = Parameters.get(1).and_then(Value::as_str).unwrap_or("").to_string();
627 let options = Parameters.get(2).cloned();
628 let severity = match severity_str {
629 "warning" => MessageSeverity::Warning,
630 "error" => MessageSeverity::Error,
631 _ => MessageSeverity::Info,
632 };
633 provider
634 .ShowMessage(severity, message, options)
635 .await
636 .map(|_| json!(null))
637 .map_err(|e| e.to_string())
638 })
639 };
640 Ok(Box::new(effect))
641 },
642
643 "UserInterface.ShowQuickPick" => {
644 let effect =
645 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
646 Box::pin(async move {
647 let provider:Arc<dyn UserInterfaceProvider> = run_time.Environment.Require();
648 let (items, options) = (
650 vec![],
651 None as Option<CommonLibrary::UserInterface::DTO::QuickPickOptionsDTO::QuickPickOptionsDTO>,
652 );
653 provider
654 .ShowQuickPick(items, options)
655 .await
656 .map(|selected_items| json!(selected_items))
657 .map_err(|e| e.to_string())
658 })
659 };
660 Ok(Box::new(effect))
661 },
662
663 "UserInterface.ShowInputBox" => {
664 let effect =
665 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
666 Box::pin(async move {
667 let provider:Arc<dyn UserInterfaceProvider> = run_time.Environment.Require();
668 let options = if let Some(Value::Object(obj)) = Parameters.get(0) {
669 match serde_json::from_value::<
671 CommonLibrary::UserInterface::DTO::InputBoxOptionsDTO::InputBoxOptionsDTO,
672 >(Value::Object(obj.clone()))
673 {
674 Ok(dto) => Some(dto),
675 Err(e) => {
676 dev_log!("ipc", "warn: Failed to deserialize InputBoxOptionsDTO: {}", e);
677 Some(CommonLibrary::UserInterface::DTO::InputBoxOptionsDTO::InputBoxOptionsDTO::default())
678 },
679 }
680 } else {
681 None
682 };
683 provider
684 .ShowInputBox(options)
685 .await
686 .map(|input_opt| json!(input_opt))
687 .map_err(|e| e.to_string())
688 })
689 };
690 Ok(Box::new(effect))
691 },
692
693 "UserInterface.ShowOpenDialog" => {
694 let effect =
695 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
696 Box::pin(async move {
697 let provider:Arc<dyn UserInterfaceProvider> = run_time.Environment.Require();
698 let options = if let Some(Value::Object(obj)) = Parameters.get(0) {
699 match serde_json::from_value::<
701 CommonLibrary::UserInterface::DTO::OpenDialogOptionsDTO::OpenDialogOptionsDTO,
702 >(Value::Object(obj.clone()))
703 {
704 Ok(dto) => Some(dto),
705 Err(e) => {
706 dev_log!("ipc", "warn: Failed to deserialize OpenDialogOptionsDTO: {}", e);
707 Some(Default::default())
708 },
709 }
710 } else {
711 None
712 };
713 provider
714 .ShowOpenDialog(options)
715 .await
716 .map(|path_buf_opt| json!(path_buf_opt))
717 .map_err(|e| e.to_string())
718 })
719 };
720 Ok(Box::new(effect))
721 },
722
723 "UserInterface.ShowSaveDialog" => {
724 let effect =
725 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
726 Box::pin(async move {
727 let provider:Arc<dyn UserInterfaceProvider> = run_time.Environment.Require();
728 let options = if let Some(Value::Object(obj)) = Parameters.get(0) {
729 match serde_json::from_value::<
731 CommonLibrary::UserInterface::DTO::SaveDialogOptionsDTO::SaveDialogOptionsDTO,
732 >(Value::Object(obj.clone()))
733 {
734 Ok(dto) => Some(dto),
735 Err(e) => {
736 dev_log!("ipc", "warn: Failed to deserialize SaveDialogOptionsDTO: {}", e);
737 Some(Default::default())
738 },
739 }
740 } else {
741 None
742 };
743 provider
744 .ShowSaveDialog(options)
745 .await
746 .map(|path_buf_opt| json!(path_buf_opt))
747 .map_err(|e| e.to_string())
748 })
749 };
750 Ok(Box::new(effect))
751 },
752
753 "$terminal:create" => {
755 let effect =
756 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
757 Box::pin(async move {
758 let provider:Arc<dyn TerminalProvider> = run_time.Environment.Require();
759 let options = Parameters.get(0).cloned().unwrap_or_default();
760 provider.CreateTerminal(options).await.map_err(|e| e.to_string())
761 })
762 };
763 Ok(Box::new(effect))
764 },
765
766 "$terminal:sendText" => {
767 let effect =
768 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
769 Box::pin(async move {
770 let provider:Arc<dyn TerminalProvider> = run_time.Environment.Require();
771 let terminal_id = Parameters.get(0).and_then(Value::as_i64).map(|n| n as u64).unwrap_or(0);
772 let text = Parameters.get(1).and_then(Value::as_str).unwrap_or("").to_string();
773 provider
774 .SendTextToTerminal(terminal_id, text)
775 .await
776 .map(|_| json!(null))
777 .map_err(|e| e.to_string())
778 })
779 };
780 Ok(Box::new(effect))
781 },
782
783 "$terminal:dispose" => {
784 let effect =
785 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
786 Box::pin(async move {
787 let provider:Arc<dyn TerminalProvider> = run_time.Environment.Require();
788 let terminal_id = Parameters.get(0).and_then(Value::as_i64).map(|n| n as u64).unwrap_or(0);
789 provider
790 .DisposeTerminal(terminal_id)
791 .await
792 .map(|_| json!(null))
793 .map_err(|e| e.to_string())
794 })
795 };
796 Ok(Box::new(effect))
797 },
798
799 "$webview:create" => {
801 let effect =
802 move |_run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
803 Box::pin(async move {
804 dev_log!("ipc", "warn: $webview:create not fully implemented");
805 Ok(json!({"handle": "webview-123"}))
806 })
807 };
808 Ok(Box::new(effect))
809 },
810
811 "$resolveCustomEditor" => {
812 let effect =
813 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
814 Box::pin(async move {
815 let provider:Arc<dyn CustomEditorProvider> = run_time.Environment.Require();
816 let view_type = Parameters.get(0).and_then(Value::as_str).unwrap_or("").to_string();
817 let resource_uri_str = Parameters.get(1).and_then(Value::as_str).unwrap_or("");
818 let resource_uri = Url::parse(resource_uri_str)
819 .unwrap_or_else(|_| Url::parse("file:///tmp/test.txt").unwrap());
820 let webview_handle =
821 Parameters.get(2).and_then(Value::as_str).unwrap_or("webview-123").to_string();
822 provider
823 .ResolveCustomEditor(view_type, resource_uri, webview_handle)
824 .await
825 .map(|_| json!(null))
826 .map_err(|e| e.to_string())
827 })
828 };
829 Ok(Box::new(effect))
830 },
831
832 "Debug.Start" => {
834 let effect =
835 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
836 Box::pin(async move {
837 let provider:Arc<dyn DebugService> = run_time.Environment.Require();
838 let folder_uri_str = Parameters.get(0).and_then(Value::as_str).unwrap_or("");
839 let folder_uri = if folder_uri_str.is_empty() { None } else { Url::parse(folder_uri_str).ok() };
840 let configuration = Parameters.get(1).cloned().unwrap_or_else(|| json!({ "type": "node" }));
841 provider
842 .StartDebugging(folder_uri, configuration)
843 .await
844 .map(|session_id| json!(session_id))
845 .map_err(|e| e.to_string())
846 })
847 };
848 Ok(Box::new(effect))
849 },
850
851 "Debug.RegisterConfigurationProvider" => {
852 let effect =
853 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
854 Box::pin(async move {
855 let provider:Arc<dyn DebugService> = run_time.Environment.Require();
856 let debug_type = Parameters.get(0).and_then(Value::as_str).unwrap_or("node").to_string();
857 let provider_handle = Parameters.get(1).and_then(Value::as_i64).map(|n| n as u32).unwrap_or(1);
858 let sidecar_id = Parameters.get(2).and_then(Value::as_str).unwrap_or("cocoon-main").to_string();
859 provider
860 .RegisterDebugConfigurationProvider(debug_type, provider_handle, sidecar_id)
861 .await
862 .map(|_| json!(null))
863 .map_err(|e| e.to_string())
864 })
865 };
866 Ok(Box::new(effect))
867 },
868
869 "$tree:register" => {
871 let effect =
872 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
873 Box::pin(async move {
874 let provider:Arc<dyn TreeViewProvider> = run_time.Environment.Require();
875 let view_id = Parameters.get(0).and_then(Value::as_str).unwrap_or("viewId").to_string();
876 let options = Parameters.get(1).cloned().unwrap_or_default();
877 provider
878 .RegisterTreeDataProvider(view_id, options)
879 .await
880 .map(|_| json!(null))
881 .map_err(|e| e.to_string())
882 })
883 };
884 Ok(Box::new(effect))
885 },
886
887 "$scm:createSourceControl" => {
889 let effect =
890 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
891 Box::pin(async move {
892 let provider:Arc<dyn SourceControlManagementProvider> = run_time.Environment.Require();
893 let resource = Parameters.get(0).cloned().unwrap_or_default();
894 provider
895 .CreateSourceControl(resource)
896 .await
897 .map(|handle| json!(handle))
898 .map_err(|e| e.to_string())
899 })
900 };
901 Ok(Box::new(effect))
902 },
903
904 "$scm:updateSourceControl" => {
905 let effect =
906 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
907 Box::pin(async move {
908 let provider:Arc<dyn SourceControlManagementProvider> = run_time.Environment.Require();
909 let handle = Parameters.get(0).and_then(Value::as_i64).map(|n| n as u32).unwrap_or(0);
910 let update = Parameters.get(1).cloned().unwrap_or_default();
911 provider
912 .UpdateSourceControl(handle, update)
913 .await
914 .map(|_| json!(null))
915 .map_err(|e| e.to_string())
916 })
917 };
918 Ok(Box::new(effect))
919 },
920
921 "$scm:updateGroup" => {
922 let effect =
923 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
924 Box::pin(async move {
925 let provider:Arc<dyn SourceControlManagementProvider> = run_time.Environment.Require();
926 let handle = Parameters.get(0).and_then(Value::as_i64).map(|n| n as u32).unwrap_or(0);
927 let group_data = Parameters.get(1).cloned().unwrap_or_default();
928 provider
929 .UpdateSourceControlGroup(handle, group_data)
930 .await
931 .map(|_| json!(null))
932 .map_err(|e| e.to_string())
933 })
934 };
935 Ok(Box::new(effect))
936 },
937
938 "$scm:registerInputBox" => {
939 let effect =
940 move |run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
941 Box::pin(async move {
942 let provider:Arc<dyn SourceControlManagementProvider> = run_time.Environment.Require();
943 let handle = Parameters.get(0).and_then(Value::as_i64).map(|n| n as u32).unwrap_or(0);
944 let options = Parameters.get(1).cloned().unwrap_or_default();
945 provider
946 .RegisterInputBox(handle, options)
947 .await
948 .map(|_| json!(null))
949 .map_err(|e| e.to_string())
950 })
951 };
952 Ok(Box::new(effect))
953 },
954
955 "Debug.Stop" => {
958 let effect =
959 move |_run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
960 Box::pin(async move {
961 let session_id = Parameters.get(0).and_then(Value::as_str).unwrap_or("").to_string();
962 dev_log!("ipc", "[Debug.Stop] stub — session={} (TODO: DebugService::StopDebugging)", session_id);
963 Ok(json!(null))
964 })
965 };
966 Ok(Box::new(effect))
967 },
968
969 "Task.Fetch" => {
973 let effect =
974 move |_run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
975 Box::pin(async move {
976 dev_log!("ipc", "[Task.Fetch] stub — returning [] (TODO: TaskProvider trait)");
977 Ok(json!([]))
978 })
979 };
980 Ok(Box::new(effect))
981 },
982
983 "Task.Execute" => {
984 let effect =
985 move |_run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
986 Box::pin(async move {
987 dev_log!("ipc", "[Task.Execute] stub — returning null (TODO: TaskProvider trait)");
988 Ok(json!(null))
989 })
990 };
991 Ok(Box::new(effect))
992 },
993
994 "Authentication.GetSession" => {
999 let effect =
1000 move |_run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
1001 Box::pin(async move {
1002 let provider_id =
1003 Parameters.get(0).and_then(Value::as_str).unwrap_or("").to_string();
1004 dev_log!("ipc", "[Authentication.GetSession] stub — provider={} (TODO: AuthenticationProvider trait)", provider_id);
1005 Ok(json!(null))
1006 })
1007 };
1008 Ok(Box::new(effect))
1009 },
1010
1011 "Authentication.GetAccounts" => {
1012 let effect =
1013 move |_run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
1014 Box::pin(async move {
1015 let provider_id =
1016 Parameters.get(0).and_then(Value::as_str).unwrap_or("").to_string();
1017 dev_log!("ipc", "[Authentication.GetAccounts] stub — provider={} (TODO: AuthenticationProvider trait)", provider_id);
1018 Ok(json!([]))
1019 })
1020 };
1021 Ok(Box::new(effect))
1022 },
1023
1024 "Clipboard.Read" => {
1027 let effect =
1028 move |_run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
1029 Box::pin(async move {
1030 dev_log!("ipc", "[Clipboard.Read] stub — returning '' (TODO: tauri-plugin-clipboard-manager)");
1031 Ok(json!(""))
1032 })
1033 };
1034 Ok(Box::new(effect))
1035 },
1036
1037 "Clipboard.Write" => {
1038 let effect =
1039 move |_run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
1040 Box::pin(async move {
1041 let text_len = Parameters.get(0).and_then(Value::as_str).map(str::len).unwrap_or(0);
1042 dev_log!("ipc", "[Clipboard.Write] stub — text_len={} (TODO: tauri-plugin-clipboard-manager)", text_len);
1043 Ok(json!(null))
1044 })
1045 };
1046 Ok(Box::new(effect))
1047 },
1048
1049 "NativeHost.OpenExternal" => {
1053 let effect =
1054 move |_run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
1055 Box::pin(async move {
1056 let uri = Parameters.get(0).and_then(Value::as_str).unwrap_or("").to_string();
1057 dev_log!("ipc", "[NativeHost.OpenExternal] stub — uri={} (TODO: tauri-plugin-shell)", uri);
1058 Ok(json!(true))
1059 })
1060 };
1061 Ok(Box::new(effect))
1062 },
1063
1064 "Languages.GetAll" => {
1068 let effect =
1069 move |_run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
1070 Box::pin(async move {
1071 dev_log!("ipc", "[Languages.GetAll] stub — returning [] (TODO: enumerate ScannedExtensions)");
1072 Ok(json!([]))
1073 })
1074 };
1075 Ok(Box::new(effect))
1076 },
1077
1078 _ => {
1080 dev_log!("ipc", "warn: [EffectCreation] Unknown method: {}", MethodName);
1081 Err(format!("Unknown method: {}", MethodName))
1082 },
1083 }
1084}