1#![allow(unused_variables, dead_code, unused_imports)]
2
3pub mod Cocoon;
7
8#[path = "Commands/mod.rs"]
9pub mod Commands;
10
11#[path = "Configuration/mod.rs"]
12pub mod Configuration;
13
14pub mod Encryption;
15
16pub mod Extension;
17
18pub mod ExtensionHost;
19
20pub mod Extensions;
21
22pub mod FileSystem;
23
24pub mod Git;
25
26pub mod Model;
27
28pub mod NativeDialog;
29
30pub mod NativeHost;
31
32pub mod Navigation;
33
34pub mod Output;
35
36#[path = "Search/mod.rs"]
37pub mod Search;
38
39pub mod Sky;
40
41pub mod Storage;
42
43pub mod Terminal;
44
45pub mod UI;
46
47pub mod TreeView;
48
49pub mod Update;
50
51pub mod Utilities;
52
53use std::{collections::HashMap, path::PathBuf, sync::Arc};
59
60use Cocoon::{
61 ExtensionHostMessage::Fn as CocoonExtensionHostMessage,
62 Notify::Fn as CocoonNotify,
63 Request::Fn as CocoonRequest,
64};
65use ExtensionHost::{
66 DebugServiceClose::Fn as ExtensionHostDebugClose,
67 DebugServiceReload::Fn as ExtensionHostDebugReload,
68 StarterCreate::Fn as ExtensionHostStarterCreate,
69 StarterGetExitInfo::Fn as ExtensionHostStarterGetExitInfo,
70 StarterKill::Fn as ExtensionHostStarterKill,
71 StarterStart::Fn as ExtensionHostStarterStart,
72 StarterWaitForExit::Fn as ExtensionHostStarterWaitForExit,
73};
74use Sky::ReplayEvents::Fn as SkyReplayEvents;
75use TreeView::GetChildren::Fn as TreeGetChildren;
76use Update::{
77 ApplyUpdate::Fn as UpdateApplyUpdate,
78 CheckForUpdates::Fn as UpdateCheckForUpdates,
79 DownloadUpdate::Fn as UpdateDownloadUpdate,
80 GetInitialState::Fn as UpdateGetInitialState,
81 IsLatestVersion::Fn as UpdateIsLatestVersion,
82 QuitAndInstall::Fn as UpdateQuitAndInstall,
83};
84use Commands::{Execute::Fn as CommandsExecute, GetAll::Fn as CommandsGetAll};
85use Configuration::{
86 EnvironmentGet::Fn as EnvironmentGet,
87 Get::Fn as ConfigurationGet,
88 Update::Fn as ConfigurationUpdate,
89 Workbench::Fn as WorkbenchConfiguration,
90};
91use Encryption::{Decrypt::Fn as Decrypt, Encrypt::Fn as Encrypt};
92use Extensions::{
93 ExtensionsGet::Fn as ExtensionsGet,
94 ExtensionsGetAll::Fn as ExtensionsGetAll,
95 ExtensionsGetInstalled::Fn as ExtensionsGetInstalled,
96 ExtensionsIsActive::Fn as ExtensionsIsActive,
97};
98use FileSystem::{
99 Managed::{
100 FileCopy::Fn as FileCopy,
101 FileDelete::Fn as FileDelete,
102 FileExists::Fn as FileExists,
103 FileMkdir::Fn as FileMkdir,
104 FileMove::Fn as FileMove,
105 FileRead::Fn as FileRead,
106 FileReadBinary::Fn as FileReadBinary,
107 FileReaddir::Fn as FileReaddir,
108 FileStat::Fn as FileStat,
109 FileWrite::Fn as FileWrite,
110 FileWriteBinary::Fn as FileWriteBinary,
111 },
112 Native::{
113 FileCloneNative::Fn as FileCloneNative,
114 FileCloseFd::Fn as FileCloseFd,
115 FileDeleteNative::Fn as FileDeleteNative,
116 FileExistsNative::Fn as FileExistsNative,
117 FileMkdirNative::Fn as FileMkdirNative,
118 FileOpenFd::Fn as FileOpenFd,
119 FileReadNative::Fn as FileReadNative,
120 FileReaddirNative::Fn as FileReaddirNative,
121 FileRealpath::Fn as FileRealpath,
122 FileRenameNative::Fn as FileRenameNative,
123 FileStatNative::Fn as FileStatNative,
124 FileUnwatch::Fn as FileUnwatch,
125 FileWatch::Fn as FileWatch,
126 FileWriteNative::Fn as FileWriteNative,
127 },
128};
129use Model::{
130 ModelClose::Fn as ModelClose,
131 ModelGet::Fn as ModelGet,
132 ModelGetAll::Fn as ModelGetAll,
133 ModelOpen::Fn as ModelOpen,
134 ModelUpdateContent::Fn as ModelUpdateContent,
135 TextfileRead::Fn as TextfileRead,
136 TextfileSave::Fn as TextfileSave,
137 TextfileWrite::Fn as TextfileWrite,
138};
139use NativeHost::{
140 ClipboardHas::Fn as NativeHasClipboard,
141 ClipboardReadBuffer::Fn as NativeReadClipboardBuffer,
142 ClipboardReadFindText::Fn as NativeReadClipboardFindText,
143 ClipboardReadImage::Fn as NativeReadImage,
144 ClipboardReadText::Fn as NativeReadClipboardText,
145 ClipboardTriggerPaste::Fn as NativeTriggerPaste,
146 ClipboardWriteBuffer::Fn as NativeWriteClipboardBuffer,
147 ClipboardWriteFindText::Fn as NativeWriteClipboardFindText,
148 ClipboardWriteText::Fn as NativeWriteClipboardText,
149 Exit::Fn as Exit,
150 FindFreePort::Fn as NativeFindFreePort,
151 GetColorScheme::Fn as NativeGetColorScheme,
152 GetEnvironmentPaths::Fn as NativeGetEnvironmentPaths,
153 InstallShellCommand::Fn as InstallShellCommand,
154 IsFullscreen::Fn as NativeIsFullscreen,
155 IsMaximized::Fn as NativeIsMaximized,
156 IsRunningUnderARM64Translation::Fn as NativeIsRunningUnderARM64Translation,
157 KillProcess::Fn as KillProcess,
158 MoveItemToTrash::Fn as NativeMoveItemToTrash,
159 OSProperties::Fn as NativeOSProperties,
160 OSStatistics::Fn as NativeOSStatistics,
161 OpenDevTools::Fn as OpenDevTools,
162 OpenExternal::Fn as OpenExternal,
163 PickFolder::Fn as NativePickFolder,
164 Quit::Fn as Quit,
165 Relaunch::Fn as Relaunch,
166 Reload::Fn as Reload,
167 ShowItemInFolder::Fn as ShowItemInFolder,
168 ShowMessageBox::Fn as NativeShowMessageBox,
169 ShowOpenDialog::Fn as NativeShowOpenDialog,
170 ShowSaveDialog::Fn as NativeShowSaveDialog,
171 ShowSaveDialogUI::Fn as UserInterfaceShowSaveDialog,
172 ToggleDevTools::Fn as ToggleDevTools,
173 UninstallShellCommand::Fn as UninstallShellCommand,
174};
175use Navigation::{
176 HistoryCanGoBack::Fn as HistoryCanGoBack,
177 HistoryCanGoForward::Fn as HistoryCanGoForward,
178 HistoryClear::Fn as HistoryClear,
179 HistoryGetStack::Fn as HistoryGetStack,
180 HistoryGoBack::Fn as HistoryGoBack,
181 HistoryGoForward::Fn as HistoryGoForward,
182 HistoryPush::Fn as HistoryPush,
183 LabelGetBase::Fn as LabelGetBase,
184 LabelGetURI::Fn as LabelGetURI,
185 LabelGetWorkspace::Fn as LabelGetWorkspace,
186};
187use Output::{
188 OutputAppend::Fn as OutputAppend,
189 OutputAppendLine::Fn as OutputAppendLine,
190 OutputClear::Fn as OutputClear,
191 OutputCreate::Fn as OutputCreate,
192 OutputShow::Fn as OutputShow,
193};
194use Search::{FindFiles::Fn as SearchFindFiles, FindInFiles::Fn as SearchFindInFiles};
195use Storage::{
196 StorageDelete::Fn as StorageDelete,
197 StorageGet::Fn as StorageGet,
198 StorageGetItems::Fn as StorageGetItems,
199 StorageKeys::Fn as StorageKeys,
200 StorageSet::Fn as StorageSet,
201 StorageUpdateItems::Fn as StorageUpdateItems,
202};
203use Terminal::{
204 AttachToProcess::Fn as AttachToProcess,
205 DetachFromProcess::Fn as DetachFromProcess,
206 LocalPTYCreateProcess::Fn as LocalPTYCreateProcess,
207 LocalPTYFreePortKillProcess::Fn as LocalPTYFreePortKillProcess,
208 LocalPTYGetDefaultShell::Fn as LocalPTYGetDefaultShell,
209 LocalPTYGetEnvironment::Fn as LocalPTYGetEnvironment,
210 LocalPTYGetProfiles::Fn as LocalPTYGetProfiles,
211 LocalPTYResize::Fn as LocalPTYResize,
212 ReviveTerminalProcesses::Fn as ReviveTerminalProcesses,
213 SerializeTerminalState::Fn as SerializeTerminalState,
214 TerminalCreate::Fn as TerminalCreate,
215 TerminalDispose::Fn as TerminalDispose,
216 TerminalHide::Fn as TerminalHide,
217 TerminalSendText::Fn as TerminalSendText,
218 TerminalShow::Fn as TerminalShow,
219};
220use UI::{
221 DecorationsClear::Fn as DecorationsClear,
222 DecorationsGet::Fn as DecorationsGet,
223 DecorationsGetMany::Fn as DecorationsGetMany,
224 DecorationsSet::Fn as DecorationsSet,
225 KeybindingAdd::Fn as KeybindingAdd,
226 KeybindingGetAll::Fn as KeybindingGetAll,
227 KeybindingLookup::Fn as KeybindingLookup,
228 KeybindingRemove::Fn as KeybindingRemove,
229 LifecycleGetPhase::Fn as LifecycleGetPhase,
230 LifecycleRequestShutdown::Fn as LifecycleRequestShutdown,
231 LifecycleWhenPhase::Fn as LifecycleWhenPhase,
232 NotificationEndProgress::Fn as NotificationEndProgress,
233 NotificationShow::Fn as NotificationShow,
234 NotificationShowProgress::Fn as NotificationShowProgress,
235 NotificationUpdateProgress::Fn as NotificationUpdateProgress,
236 ProgressBegin::Fn as ProgressBegin,
237 ProgressEnd::Fn as ProgressEnd,
238 ProgressReport::Fn as ProgressReport,
239 QuickInputShowInputBox::Fn as QuickInputShowInputBox,
240 QuickInputShowQuickPick::Fn as QuickInputShowQuickPick,
241 ThemesGetActive::Fn as ThemesGetActive,
242 ThemesList::Fn as ThemesList,
243 ThemesSet::Fn as ThemesSet,
244 WorkingCopyGetAllDirty::Fn as WorkingCopyGetAllDirty,
245 WorkingCopyGetDirtyCount::Fn as WorkingCopyGetDirtyCount,
246 WorkingCopyIsDirty::Fn as WorkingCopyIsDirty,
247 WorkingCopySetDirty::Fn as WorkingCopySetDirty,
248 WorkspacesAddFolder::Fn as WorkspacesAddFolder,
249 WorkspacesGetFolders::Fn as WorkspacesGetFolders,
250 WorkspacesGetName::Fn as WorkspacesGetName,
251 WorkspacesRemoveFolder::Fn as WorkspacesRemoveFolder,
252};
253use Utilities::{
254 ApplicationRoot::{Get::Fn as get_static_application_root, Set::Fn as set_static_application_root},
255 ChannelPriority::Fn as ResolveChannelPriority,
256 FiddeeRoot::Fn as FiddeeRoot,
257 JsonValueHelpers::Fn as v_str,
258 MetadataEncoding::Fn as metadata_to_istat,
259 PathExtraction::{Fn as extract_path_from_arg, percent_decode},
260 RecentlyOpened::{
261 Mutate::Fn as MutateRecentlyOpened,
262 Path::Fn as RecentlyOpenedPath,
263 Read::Fn as ReadRecentlyOpened,
264 },
265 UserdataDir::{
266 Ensure::Fn as ensure_userdata_dirs,
267 Get::Fn as get_userdata_base_dir,
268 Set::Fn as set_userdata_base_dir,
269 },
270};
271use Echo::Task::Priority::Priority as EchoPriority;
272use serde_json::{Value, json};
273use tauri::{AppHandle, Manager};
274use CommonLibrary::Configuration::DTO::{
276 ConfigurationOverridesDTO as ConfigurationOverridesDTOModule,
277 ConfigurationTarget as ConfigurationTargetModule,
278};
279
280use crate::dev_log;
281
282type ConfigurationOverridesDTO = ConfigurationOverridesDTOModule::ConfigurationOverridesDTO;
283
284type ConfigurationTarget = ConfigurationTargetModule::ConfigurationTarget;
285
286use CommonLibrary::{
287 Command::CommandExecutor::CommandExecutor,
288 Configuration::ConfigurationProvider::ConfigurationProvider,
289 Environment::Requires::Requires,
290 Error::CommonError::CommonError,
291 ExtensionManagement::ExtensionManagementService::ExtensionManagementService,
292 FileSystem::{FileSystemReader::FileSystemReader, FileSystemWriter::FileSystemWriter},
293 IPC::SkyEvent::SkyEvent,
294 LanguageFeature::{
295 DTO::PositionDTO::PositionDTO,
296 LanguageFeatureProviderRegistry::LanguageFeatureProviderRegistry,
297 },
298 Storage::StorageProvider::StorageProvider,
299};
300
301use crate::{
302 ApplicationState::{
303 DTO::WorkspaceFolderStateDTO::WorkspaceFolderStateDTO,
304 State::{
305 ApplicationState::ApplicationState,
306 WorkspaceState::WorkspaceDelta::UpdateWorkspaceFoldersAndBroadcast,
307 },
308 },
309 RunTime::ApplicationRunTime::ApplicationRunTime,
310};
311
312pub async fn mountain_ipc_invoke(
329 ApplicationHandle:AppHandle,
330
331 command:String,
332
333 Arguments:Vec<Value>,
334) -> Result<Value, String> {
335 let IsHighFrequencyCommand = matches!(
338 command.as_str(),
339 "logger:log"
340 | "logger:info"
341 | "logger:debug"
342 | "logger:trace"
343 | "logger:warn"
344 | "logger:error"
345 | "logger:critical"
346 | "logger:flush"
347 | "logger:setLevel"
348 | "logger:getLevel"
349 | "logger:registerLogger"
350 | "logger:createLogger"
351 | "logger:deregisterLogger"
352 | "logger:getRegisteredLoggers"
353 | "logger:setVisibility"
354 | "log:registerLogger"
355 | "log:createLogger"
356 | "file:stat"
358 | "file:readFile"
359 | "file:readdir"
360 | "file:writeFile"
361 | "file:delete"
362 | "file:rename"
363 | "file:realpath"
364 | "file:read"
365 | "file:write"
366 | "file:open"
368 | "file:close"
369 | "textFile:save"
371 | "storage:getItems"
373 | "storage:updateItems"
374 | "configuration:lookup"
376 | "configuration:inspect"
377 | "themes:getColorTheme"
379 | "output:append"
381 | "progress:report"
382 | "menubar:updateMenubar"
384 | "storage:onDidChangeItems"
386 | "storage:logStorage"
387 | "configuration:onDidChange"
388 | "workspaces:onDidChangeWorkspaceFolders"
389 | "workspaces:onDidChangeWorkspaceName"
390 | "commands:registerCommand"
392 | "commands:unregisterCommand"
393 | "commands:onDidRegisterCommand"
394 | "commands:onDidExecuteCommand"
395 );
396
397 let OTLPStart = if IsHighFrequencyCommand { 0 } else { crate::IPC::DevLog::NowNano::Fn() };
398
399 if !IsHighFrequencyCommand {
407 dev_log!("ipc", "invoke: {} args_count={}", command, Arguments.len());
408 }
409
410 ensure_userdata_dirs();
412
413 let RunTime:Arc<ApplicationRunTime> = ApplicationHandle.state::<Arc<ApplicationRunTime>>().inner().clone();
417
418 if IsHighFrequencyCommand {
424 match command.as_str() {
425
426 "logger:error" | "logger:critical" => {
431
432 let Msg = Arguments.get(1).and_then(|V| V.as_str()).unwrap_or(
433 Arguments.first().and_then(|V| V.as_str()).unwrap_or(""),
434 );
435
436 if !Msg.is_empty() {
437
438 dev_log!("vscode-log", "[ERROR] {}", Msg);
439 }
440
441 return Ok(Value::Null);
442 },
443
444 "logger:warn" => {
445
446 let Msg = Arguments.get(1).and_then(|V| V.as_str()).unwrap_or(
447 Arguments.first().and_then(|V| V.as_str()).unwrap_or(""),
448 );
449
450 if !Msg.is_empty() {
451
452 dev_log!("vscode-log", "[WARN] {}", Msg);
453 }
454
455 return Ok(Value::Null);
456 },
457
458 "logger:log" | "logger:info" | "logger:debug" | "logger:trace"
459 | "logger:flush" | "logger:setLevel" | "logger:getLevel"
460 | "logger:createLogger" | "logger:registerLogger"
461 | "logger:deregisterLogger" | "logger:getRegisteredLoggers"
462 | "logger:setVisibility"
463 | "log:registerLogger" | "log:createLogger"
469 | "storage:onDidChangeItems" | "storage:logStorage"
471 | "commands:registerCommand" | "commands:unregisterCommand"
473 | "commands:onDidRegisterCommand" | "commands:onDidExecuteCommand"
474 | "configuration:onDidChange"
476 | "storage:optimize" | "storage:isUsed" | "storage:close"
478 | "workspaces:onDidChangeWorkspaceFolders"
480 | "workspaces:onDidChangeWorkspaceName" => {
481
482 return Ok(Value::Null);
483 },
484
485 "menubar:updateMenubar" => {
488
489 use std::sync::atomic::{AtomicU64, Ordering as AO};
490
491 static MENUBAR_CALLS_FAST:AtomicU64 = AtomicU64::new(0);
492
493 let N = MENUBAR_CALLS_FAST.fetch_add(1, AO::Relaxed) + 1;
494
495 if N == 1 || N % 100 == 0 {
496
497 dev_log!("menubar", "menubar:updateMenubar (fast-path call #{})", N);
498 }
499
500 return Ok(Value::Null);
501 },
502
503 _ => {}, }
505 }
506
507 let CommandPriority = ResolveChannelPriority(&command);
527
528 let Scheduler = RunTime.Scheduler.clone();
529
530 let (ResultSender, ResultReceiver) = tokio::sync::oneshot::channel::<Result<Value, String>>();
531
532 let DispatchAppHandle = ApplicationHandle.clone();
533
534 let DispatchRuntime = RunTime.clone();
535
536 let DispatchCommand = command.clone();
537
538 let DispatchArgs = Arguments;
539
540 Scheduler.Submit(
541 async move {
542 let ApplicationHandle = DispatchAppHandle;
543 let RunTime = DispatchRuntime;
544 let command = DispatchCommand;
545 let Arguments = DispatchArgs;
546
547 let MatchResult = match command.as_str() {
548 "configuration:get" | "configuration:getValue" => {
554 dev_log!("config", "{}", command);
555 ConfigurationGet(RunTime.clone(), Arguments).await
556 },
557 "configuration:update" | "configuration:updateValue" => {
558 dev_log!("config", "{}", command);
559 ConfigurationUpdate(RunTime.clone(), Arguments).await
560 },
561 "configuration:onDidChange" => Ok(Value::Null),
567
568 "configuration:lookup" => {
574 dev_log!("config", "configuration:lookup (→ get)");
575 ConfigurationGet(RunTime.clone(), Arguments).await
576 },
577
578 "configuration:inspect" => {
588 dev_log!("config", "configuration:inspect");
589 let CurrentValue = ConfigurationGet(RunTime.clone(), Arguments).await.unwrap_or(Value::Null);
590 Ok(json!({
591 "value": CurrentValue,
592 "default": CurrentValue,
593 "user": Value::Null,
594 "workspace": Value::Null,
595 "workspaceFolder": Value::Null,
596 "memory": Value::Null,
597 }))
598 },
599
600 "logger:log" | "logger:warn" | "logger:error" | "logger:info" | "logger:debug" | "logger:trace" => {
605 let Level = command.trim_start_matches("logger:");
606 let Msg = if Arguments.len() >= 2 {
607 let Tail:Vec<String> = Arguments
608 .iter()
609 .skip(1)
610 .filter_map(|V| V.as_str().map(str::to_owned).or_else(|| serde_json::to_string(V).ok()))
611 .collect();
612 Tail.join(" ")
613 } else {
614 Arguments
615 .first()
616 .and_then(|V| V.as_str().map(str::to_owned))
617 .unwrap_or_default()
618 };
619 if !Msg.is_empty() {
620 match Level {
621 "error" | "critical" => dev_log!("vscode-log", "[ERROR] {}", Msg),
622 "warn" => dev_log!("vscode-log", "[WARN] {}", Msg),
623 _ => dev_log!("vscode-log", "{}", Msg),
624 }
625 }
626 Ok(Value::Null)
627 },
628 "logger:flush"
629 | "logger:setLevel"
630 | "logger:getLevel"
631 | "logger:createLogger"
632 | "logger:registerLogger"
633 | "logger:deregisterLogger"
634 | "logger:getRegisteredLoggers"
635 | "logger:setVisibility" => Ok(Value::Null),
636
637 "file:read" | "file:readFile" => FileReadNative(Arguments).await,
649 "file:write" | "file:writeFile" => FileWriteNative(Arguments).await,
650 "file:stat" => FileStatNative(Arguments).await,
651 "file:exists" => FileExistsNative(Arguments).await,
652 "file:delete" => FileDeleteNative(Arguments).await,
653 "file:copy" => FileCloneNative(Arguments).await,
654 "file:move" | "file:rename" => FileRenameNative(Arguments).await,
655 "file:mkdir" => FileMkdirNative(Arguments).await,
656 "file:readdir" => FileReaddirNative(Arguments).await,
657 "file:readBinary" => FileReadBinary(RunTime.clone(), Arguments).await,
658 "file:writeBinary" => FileWriteBinary(RunTime.clone(), Arguments).await,
659 "file:watch" => FileWatch(RunTime.clone(), Arguments).await,
662 "file:unwatch" => FileUnwatch(RunTime.clone(), Arguments).await,
663
664 "storage:get" => StorageGet(RunTime.clone(), Arguments).await,
671 "storage:set" => StorageSet(RunTime.clone(), Arguments).await,
672 "storage:getItems" => {
673 dev_log!("storage-verbose", "storage:getItems");
677 StorageGetItems(RunTime.clone(), Arguments).await
678 },
679 "storage:updateItems" => {
680 dev_log!("storage-verbose", "storage:updateItems");
681 StorageUpdateItems(RunTime.clone(), Arguments).await
682 },
683 "storage:optimize" => {
684 dev_log!("storage", "storage:optimize");
685 Ok(Value::Null)
686 },
687 "storage:isUsed" => {
688 dev_log!("storage", "storage:isUsed");
689 Ok(Value::Null)
690 },
691 "storage:close" => {
692 dev_log!("storage", "storage:close");
693 Ok(Value::Null)
694 },
695 "storage:onDidChangeItems" | "storage:logStorage" => {
699 dev_log!("storage-verbose", "{} (stub-ack)", command);
700 Ok(Value::Null)
701 },
702
703 "environment:get" => {
705 dev_log!("config", "environment:get");
706 EnvironmentGet(RunTime.clone(), Arguments).await
707 },
708
709 "native:showItemInFolder" => ShowItemInFolder(RunTime.clone(), Arguments).await,
711 "native:openExternal" => OpenExternal(RunTime.clone(), Arguments).await,
712
713 "workbench:getConfiguration" => WorkbenchConfiguration(RunTime.clone(), Arguments).await,
715
716 "diagnostic:log" => {
722 let Tag = Arguments.first().and_then(|V| V.as_str()).unwrap_or("webview").to_string();
723 let Message = Arguments.get(1).and_then(|V| V.as_str()).unwrap_or("").to_string();
724 let Extras = if Arguments.len() > 2 {
725 let Tail:Vec<String> = Arguments
726 .iter()
727 .skip(2)
728 .map(|V| {
729 let S = serde_json::to_string(V).unwrap_or_default();
730 if S.len() > 240 {
736 let CutAt = S
737 .char_indices()
738 .map(|(Index, _)| Index)
739 .take_while(|Index| *Index <= 240)
740 .last()
741 .unwrap_or(0);
742 format!("{}…", &S[..CutAt])
743 } else {
744 S
745 }
746 })
747 .collect();
748 format!(" {}", Tail.join(" "))
749 } else {
750 String::new()
751 };
752 dev_log!("diagnostic", "[{}] {}{}", Tag, Message, Extras);
753 Ok(Value::Null)
754 },
755
756 "commands:execute" | "commands:executeCommand" => CommandsExecute(RunTime.clone(), Arguments).await,
761 "commands:getAll" | "commands:getCommands" => {
762 dev_log!("commands", "{}", command);
763 CommandsGetAll(RunTime.clone()).await
764 },
765 "commands:registerCommand"
770 | "commands:unregisterCommand"
771 | "commands:onDidRegisterCommand"
772 | "commands:onDidExecuteCommand" => Ok(Value::Null),
773
774 "extensions:getAll" => {
776 dev_log!("extensions", "extensions:getAll");
777 ExtensionsGetAll(RunTime.clone()).await
778 },
779 "extensions:get" => {
780 dev_log!("extensions", "extensions:get");
781 ExtensionsGet(RunTime.clone(), Arguments).await
782 },
783 "extensions:isActive" => {
784 dev_log!("extensions", "extensions:isActive");
785 ExtensionsIsActive(RunTime.clone(), Arguments).await
786 },
787 "extensions:activate" => {
793 let ExtensionId = Arguments.first().and_then(|V| V.as_str()).unwrap_or("").to_string();
794 dev_log!("extensions", "extensions:activate id={}", ExtensionId);
795 if ExtensionId.is_empty() {
796 Ok(Value::Null)
797 } else {
798 let Notification = json!({
799 "event": format!("onCustom:{}", ExtensionId),
800 "extensionId": ExtensionId,
801 });
802 let _ = crate::Vine::Client::SendNotification::Fn(
803 "cocoon-main".to_string(),
804 "$activateByEvent".to_string(),
805 Notification,
806 )
807 .await;
808 Ok(Value::Null)
809 }
810 },
811
812 "extensions:getInstalled" | "extensions:scanSystemExtensions" => {
825 let ArgsSummary = Arguments
831 .iter()
832 .enumerate()
833 .map(|(Idx, V)| {
834 let Preview = serde_json::to_string(V).unwrap_or_default();
835 let Trimmed = if Preview.len() > 180 {
838 let CutAt = Preview
839 .char_indices()
840 .map(|(Index, _)| Index)
841 .take_while(|Index| *Index <= 180)
842 .last()
843 .unwrap_or(0);
844 format!("{}…", &Preview[..CutAt])
845 } else {
846 Preview
847 };
848 format!("[{}]={}", Idx, Trimmed)
849 })
850 .collect::<Vec<_>>()
851 .join(" ");
852 dev_log!("extensions", "{} Arguments={}", command, ArgsSummary);
853 let EffectiveArgs = if command == "extensions:scanSystemExtensions" {
862 let mut Overridden = Arguments.clone();
863 if Overridden.is_empty() {
864 Overridden.push(Value::Null);
865 }
866 Overridden[0] = json!(0);
867 Overridden
868 } else {
869 Arguments.clone()
870 };
871 ExtensionsGetInstalled(RunTime.clone(), EffectiveArgs).await
872 },
873 "extensions:scanUserExtensions" => {
874 dev_log!("extensions", "{} (forwarded to getInstalled with type=User)", command);
883 let mut UserArgs = Arguments.clone();
884 if UserArgs.is_empty() {
885 UserArgs.push(Value::Null);
886 }
887 UserArgs[0] = json!(1);
888 ExtensionsGetInstalled(RunTime.clone(), UserArgs).await
889 },
890 "extensions:getUninstalled" => {
891 dev_log!("extensions", "{} (returning [])", command);
895 Ok(Value::Array(Vec::new()))
896 },
897 "extensions:query" | "extensions:getExtensions" | "extensions:getRecommendations" => {
901 dev_log!("extensions", "{} (offline gallery - returning [])", command);
902 Ok(Value::Array(Vec::new()))
903 },
904 "extensions:getExtensionsControlManifest" => {
910 dev_log!("extensions", "{} (offline gallery - empty manifest)", command);
911 Ok(json!({
912 "malicious": [],
913 "deprecated": {},
914 "search": [],
915 "autoUpdate": {},
916 }))
917 },
918 "extensions:resetPinnedStateForAllUserExtensions" => {
925 dev_log!("extensions", "{} (no-op, pin state is UI-local)", command);
926 Ok(Value::Null)
927 },
928 "extensions:install" => {
936 Extension::ExtensionInstall::Fn(ApplicationHandle.clone(), RunTime.clone(), Arguments).await
937 },
938 "extensions:uninstall" => {
939 Extension::ExtensionUninstall::Fn(ApplicationHandle.clone(), RunTime.clone(), Arguments).await
940 },
941
942 "extensions:getManifest" => {
951 let VsixPath = match Arguments.first() {
952 Some(serde_json::Value::String(Path)) => Path.clone(),
953 Some(Obj) => {
954 Obj.get("fsPath")
955 .and_then(|V| V.as_str())
956 .map(str::to_owned)
957 .or_else(|| Obj.get("path").and_then(|V| V.as_str()).map(str::to_owned))
958 .unwrap_or_default()
959 },
960 None => String::new(),
961 };
962 dev_log!("extensions", "extensions:getManifest vsix={}", VsixPath);
963 if VsixPath.is_empty() {
964 Err("extensions:getManifest: missing VSIX path argument".to_string())
965 } else {
966 let Path = std::path::PathBuf::from(&VsixPath);
967 match crate::ExtensionManagement::VsixInstaller::ReadFullManifest(&Path) {
968 Ok(Manifest) => Ok(Manifest),
969 Err(Error) => {
970 dev_log!(
971 "extensions",
972 "warn: [WindServiceHandlers] extensions:getManifest failed for '{}': {}",
973 VsixPath,
974 Error
975 );
976 Err(format!("extensions:getManifest failed: {}", Error))
977 },
978 }
979 }
980 },
981 "extensions:reinstall" | "extensions:updateMetadata" => {
986 dev_log!("extensions", "{} (no-op: no gallery backend)", command);
987 Ok(Value::Null)
988 },
989
990 "terminal:create" => {
992 dev_log!("terminal", "terminal:create");
993 TerminalCreate(RunTime.clone(), Arguments).await
994 },
995 "terminal:sendText" => {
996 dev_log!("terminal", "terminal:sendText");
997 TerminalSendText(RunTime.clone(), Arguments).await
998 },
999 "terminal:dispose" => {
1000 dev_log!("terminal", "terminal:dispose");
1001 TerminalDispose(RunTime.clone(), Arguments).await
1002 },
1003 "terminal:show" => {
1004 dev_log!("terminal", "terminal:show");
1005 TerminalShow(RunTime.clone(), Arguments).await
1006 },
1007 "terminal:hide" => {
1008 dev_log!("terminal", "terminal:hide");
1009 TerminalHide(RunTime.clone(), Arguments).await
1010 },
1011
1012 "output:create" => OutputCreate(ApplicationHandle.clone(), Arguments).await,
1014 "output:append" => {
1015 dev_log!("output", "output:append");
1016 OutputAppend(ApplicationHandle.clone(), Arguments).await
1017 },
1018 "output:appendLine" => {
1019 dev_log!("output", "output:appendLine");
1020 OutputAppendLine(ApplicationHandle.clone(), Arguments).await
1021 },
1022 "output:clear" => {
1023 dev_log!("output", "output:clear");
1024 OutputClear(ApplicationHandle.clone(), Arguments).await
1025 },
1026 "output:show" => {
1027 dev_log!("output", "output:show");
1028 OutputShow(ApplicationHandle.clone(), Arguments).await
1029 },
1030
1031 "textFile:read" => {
1033 dev_log!("textfile", "textFile:read");
1034 TextfileRead(RunTime.clone(), Arguments).await
1035 },
1036 "textFile:write" => {
1037 dev_log!("textfile", "textFile:write");
1038 TextfileWrite(RunTime.clone(), Arguments).await
1039 },
1040 "textFile:save" => TextfileSave(RunTime.clone(), Arguments).await,
1041
1042 "storage:delete" => {
1044 dev_log!("storage", "storage:delete");
1045 StorageDelete(RunTime.clone(), Arguments).await
1046 },
1047 "storage:keys" => {
1048 dev_log!("storage", "storage:keys");
1049 StorageKeys(RunTime.clone()).await
1050 },
1051
1052 "notification:show" => {
1054 dev_log!("notification", "notification:show");
1055 NotificationShow(ApplicationHandle.clone(), Arguments).await
1056 },
1057 "notification:showProgress" => {
1058 dev_log!("notification", "notification:showProgress");
1059 NotificationShowProgress(ApplicationHandle.clone(), Arguments).await
1060 },
1061 "notification:updateProgress" => {
1062 dev_log!("notification", "notification:updateProgress");
1063 NotificationUpdateProgress(ApplicationHandle.clone(), Arguments).await
1064 },
1065 "notification:endProgress" => {
1066 dev_log!("notification", "notification:endProgress");
1067 NotificationEndProgress(ApplicationHandle.clone(), Arguments).await
1068 },
1069
1070 "progress:begin" => {
1072 dev_log!("progress", "progress:begin");
1073 ProgressBegin(ApplicationHandle.clone(), Arguments).await
1074 },
1075 "progress:report" => {
1076 dev_log!("progress", "progress:report");
1077 ProgressReport(ApplicationHandle.clone(), Arguments).await
1078 },
1079 "progress:end" => {
1080 dev_log!("progress", "progress:end");
1081 ProgressEnd(ApplicationHandle.clone(), Arguments).await
1082 },
1083
1084 "quickInput:showQuickPick" => {
1086 dev_log!("quickinput", "quickInput:showQuickPick");
1087 QuickInputShowQuickPick(RunTime.clone(), Arguments).await
1088 },
1089 "quickInput:showInputBox" => {
1090 dev_log!("quickinput", "quickInput:showInputBox");
1091 QuickInputShowInputBox(RunTime.clone(), Arguments).await
1092 },
1093
1094 "workspaces:getFolders" | "workspaces:getWorkspaceFolders" | "workspaces:getWorkspace" => {
1099 dev_log!("workspaces", "{}", command);
1100 WorkspacesGetFolders(RunTime.clone()).await
1101 },
1102 "workspaces:addFolder" | "workspaces:addWorkspaceFolders" => {
1103 dev_log!("workspaces", "{}", command);
1104 WorkspacesAddFolder(RunTime.clone(), Arguments).await
1105 },
1106 "workspaces:removeFolder" | "workspaces:removeWorkspaceFolders" => {
1107 dev_log!("workspaces", "{}", command);
1108 WorkspacesRemoveFolder(RunTime.clone(), Arguments).await
1109 },
1110 "workspaces:getName" => {
1111 dev_log!("workspaces", "{}", command);
1112 WorkspacesGetName(RunTime.clone()).await
1113 },
1114 "themes:getActive" => {
1116 dev_log!("themes", "themes:getActive");
1117 ThemesGetActive(RunTime.clone()).await
1118 },
1119 "themes:list" => {
1120 dev_log!("themes", "themes:list");
1121 ThemesList(RunTime.clone()).await
1122 },
1123 "themes:set" => {
1124 dev_log!("themes", "themes:set");
1125 ThemesSet(RunTime.clone(), Arguments).await
1126 },
1127 "themes:getColorTheme" => {
1132 dev_log!("themes", "themes:getColorTheme (→ getActive)");
1133 ThemesGetActive(RunTime.clone()).await
1134 },
1135
1136 "search:findInFiles" | "search:textSearch" | "search:searchText" => {
1140 dev_log!("search", "{}", command);
1141 SearchFindInFiles(RunTime.clone(), Arguments).await
1142 },
1143 "search:findFiles" | "search:fileSearch" | "search:searchFile" => {
1144 dev_log!("search", "{}", command);
1145 SearchFindFiles(RunTime.clone(), Arguments).await
1146 },
1147 "search:cancel" | "search:clearCache" | "search:onDidChangeResult" => {
1152 dev_log!("search", "{} (stub-ack)", command);
1153 Ok(Value::Null)
1154 },
1155
1156 "decorations:get" => {
1158 dev_log!("decorations", "decorations:get");
1159 DecorationsGet(RunTime.clone(), Arguments).await
1160 },
1161 "decorations:getMany" => {
1162 dev_log!("decorations", "decorations:getMany");
1163 DecorationsGetMany(RunTime.clone(), Arguments).await
1164 },
1165 "decorations:set" => {
1166 dev_log!("decorations", "decorations:set");
1167 DecorationsSet(RunTime.clone(), Arguments).await
1168 },
1169 "decorations:clear" => {
1170 dev_log!("decorations", "decorations:clear");
1171 DecorationsClear(RunTime.clone(), Arguments).await
1172 },
1173
1174 "workingCopy:isDirty" => {
1176 dev_log!("workingcopy", "workingCopy:isDirty");
1177 WorkingCopyIsDirty(RunTime.clone(), Arguments).await
1178 },
1179 "workingCopy:setDirty" => {
1180 dev_log!("workingcopy", "workingCopy:setDirty");
1181 WorkingCopySetDirty(RunTime.clone(), Arguments).await
1182 },
1183 "workingCopy:getAllDirty" => {
1184 dev_log!("workingcopy", "workingCopy:getAllDirty");
1185 WorkingCopyGetAllDirty(RunTime.clone()).await
1186 },
1187 "workingCopy:getDirtyCount" => {
1188 dev_log!("workingcopy", "workingCopy:getDirtyCount");
1189 WorkingCopyGetDirtyCount(RunTime.clone()).await
1190 },
1191
1192 "keybinding:add" => {
1194 dev_log!("keybinding", "keybinding:add");
1195 KeybindingAdd(RunTime.clone(), Arguments).await
1196 },
1197 "keybinding:remove" => {
1198 dev_log!("keybinding", "keybinding:remove");
1199 KeybindingRemove(RunTime.clone(), Arguments).await
1200 },
1201 "keybinding:lookup" => {
1202 dev_log!("keybinding", "keybinding:lookup");
1203 KeybindingLookup(RunTime.clone(), Arguments).await
1204 },
1205 "keybinding:getAll" => {
1206 dev_log!("keybinding", "keybinding:getAll");
1207 KeybindingGetAll(RunTime.clone()).await
1208 },
1209
1210 "lifecycle:getPhase" => {
1212 dev_log!("lifecycle", "lifecycle:getPhase");
1213 LifecycleGetPhase(RunTime.clone()).await
1214 },
1215 "lifecycle:whenPhase" => {
1216 dev_log!("lifecycle", "lifecycle:whenPhase");
1217 LifecycleWhenPhase(RunTime.clone(), Arguments).await
1218 },
1219 "lifecycle:requestShutdown" => {
1220 dev_log!("lifecycle", "lifecycle:requestShutdown");
1221 LifecycleRequestShutdown(ApplicationHandle.clone()).await
1222 },
1223 "lifecycle:advancePhase" | "lifecycle:setPhase" => {
1224 dev_log!("lifecycle", "{}", command);
1225 let NewPhase = Arguments.first().and_then(|V| V.as_u64()).unwrap_or(1) as u8;
1230 RunTime
1231 .Environment
1232 .ApplicationState
1233 .Feature
1234 .Lifecycle
1235 .AdvanceAndBroadcast(NewPhase, &ApplicationHandle);
1236
1237 if NewPhase >= 3 {
1251 if let Some(MainWindow) = ApplicationHandle.get_webview_window("main") {
1252 if let Ok(false) = MainWindow.is_visible() {
1253 if let Err(Error) = MainWindow.show() {
1254 dev_log!(
1255 "lifecycle",
1256 "warn: [Lifecycle] main window show() failed on phase {}: {}",
1257 NewPhase,
1258 Error
1259 );
1260 } else {
1261 dev_log!(
1262 "lifecycle",
1263 "[Lifecycle] main window revealed on phase {} (hidden-until-ready)",
1264 NewPhase
1265 );
1266 let _ = MainWindow.set_focus();
1267 }
1268 }
1269 }
1270 }
1271
1272 Ok(json!(RunTime.Environment.ApplicationState.Feature.Lifecycle.GetPhase()))
1273 },
1274
1275 "label:getUri" => {
1277 dev_log!("label", "label:getUri");
1278 LabelGetURI(RunTime.clone(), Arguments).await
1279 },
1280 "label:getWorkspace" => {
1281 dev_log!("label", "label:getWorkspace");
1282 LabelGetWorkspace(RunTime.clone()).await
1283 },
1284 "label:getBase" => {
1285 dev_log!("label", "label:getBase");
1286 LabelGetBase(Arguments).await
1287 },
1288
1289 "model:open" => {
1291 dev_log!("model", "model:open");
1292 ModelOpen(RunTime.clone(), Arguments).await
1293 },
1294 "model:close" => {
1295 dev_log!("model", "model:close");
1296 ModelClose(RunTime.clone(), Arguments).await
1297 },
1298 "model:get" => {
1299 dev_log!("model", "model:get");
1300 ModelGet(RunTime.clone(), Arguments).await
1301 },
1302 "model:getAll" => {
1303 dev_log!("model", "model:getAll");
1304 ModelGetAll(RunTime.clone()).await
1305 },
1306 "model:updateContent" => {
1307 dev_log!("model", "model:updateContent");
1308 ModelUpdateContent(RunTime.clone(), Arguments).await
1309 },
1310
1311 "history:goBack" => {
1313 dev_log!("history", "history:goBack");
1314 HistoryGoBack(RunTime.clone()).await
1315 },
1316 "history:goForward" => {
1317 dev_log!("history", "history:goForward");
1318 HistoryGoForward(RunTime.clone()).await
1319 },
1320 "history:canGoBack" => {
1321 dev_log!("history", "history:canGoBack");
1322 HistoryCanGoBack(RunTime.clone()).await
1323 },
1324 "history:canGoForward" => {
1325 dev_log!("history", "history:canGoForward");
1326 HistoryCanGoForward(RunTime.clone()).await
1327 },
1328 "history:push" => {
1329 dev_log!("history", "history:push");
1330 HistoryPush(RunTime.clone(), Arguments).await
1331 },
1332 "history:clear" => {
1333 dev_log!("history", "history:clear");
1334 HistoryClear(RunTime.clone()).await
1335 },
1336 "history:getStack" => {
1337 dev_log!("history", "history:getStack");
1338 HistoryGetStack(RunTime.clone()).await
1339 },
1340
1341 "mountain_get_status" => {
1343 let status = json!({
1344 "connected": true,
1345 "version": "1.0.0"
1346 });
1347 Ok(status)
1348 },
1349 "mountain_get_configuration" => {
1350 let Config = RunTime.Environment.ApplicationState.Configuration.GetGlobalConfiguration();
1352 Ok(Config)
1353 },
1354 "mountain_get_services_status" => {
1355 let CocoonConnected = crate::Vine::Client::IsClientConnected::Fn("cocoon-main");
1356 Ok(json!({
1357 "cocoon": { "connected": CocoonConnected },
1358 "vine": { "running": true }
1359 }))
1360 },
1361 "mountain_get_state" => {
1362 let FolderCount = RunTime
1363 .Environment
1364 .ApplicationState
1365 .Workspace
1366 .WorkspaceFolders
1367 .lock()
1368 .map(|G| G.len())
1369 .unwrap_or(0);
1370 Ok(json!({
1371 "workspace": { "folderCount": FolderCount },
1372 "activeDocument": RunTime.Environment.ApplicationState.Workspace.GetActiveDocumentURI()
1373 }))
1374 },
1375
1376 "file:realpath" => FileRealpath(Arguments).await,
1382 "file:open" => FileOpenFd(Arguments).await,
1383 "file:close" => FileCloseFd(Arguments).await,
1384 "file:cloneFile" => FileCloneNative(Arguments).await,
1385
1386 "nativeHost:pickFolderAndOpen" => NativePickFolder(ApplicationHandle.clone(), Arguments).await,
1392 "nativeHost:pickFileAndOpen" => NativePickFolder(ApplicationHandle.clone(), Arguments).await,
1393 "nativeHost:pickFileFolderAndOpen" => NativePickFolder(ApplicationHandle.clone(), Arguments).await,
1394 "nativeHost:pickWorkspaceAndOpen" => NativePickFolder(ApplicationHandle.clone(), Arguments).await,
1395 "nativeHost:showOpenDialog" => NativeShowOpenDialog(ApplicationHandle.clone(), Arguments).await,
1396
1397 "UserInterface.ShowOpenDialog" => {
1403 match NativeShowOpenDialog(ApplicationHandle.clone(), Arguments).await {
1404 Ok(Response) => {
1405 let Paths = Response
1406 .get("filePaths")
1407 .and_then(|V| V.as_array())
1408 .cloned()
1409 .unwrap_or_default();
1410 Ok(Value::Array(Paths))
1411 },
1412 Err(Error) => Err(Error),
1413 }
1414 },
1415 "nativeHost:showSaveDialog" => NativeShowSaveDialog(ApplicationHandle.clone(), Arguments).await,
1416 "UserInterface.ShowSaveDialog" => {
1419 UserInterfaceShowSaveDialog(ApplicationHandle.clone(), Arguments).await
1420 },
1421 "nativeHost:showMessageBox" => NativeShowMessageBox(ApplicationHandle.clone(), Arguments).await,
1422
1423 "nativeHost:getEnvironmentPaths" => NativeGetEnvironmentPaths(ApplicationHandle.clone()).await,
1425
1426 "nativeHost:getOSColorScheme" => {
1428 dev_log!("nativehost", "nativeHost:getOSColorScheme");
1429 NativeGetColorScheme().await
1430 },
1431 "nativeHost:getOSProperties" => {
1432 dev_log!("nativehost", "nativeHost:getOSProperties");
1433 NativeOSProperties().await
1434 },
1435 "nativeHost:getOSStatistics" => {
1436 dev_log!("nativehost", "nativeHost:getOSStatistics");
1437 NativeOSStatistics().await
1438 },
1439 "nativeHost:getOSVirtualMachineHint" => {
1440 dev_log!("nativehost", "nativeHost:getOSVirtualMachineHint");
1441 Ok(json!(0))
1442 },
1443
1444 "nativeHost:isWindowAlwaysOnTop" => {
1446 dev_log!("window", "nativeHost:isWindowAlwaysOnTop");
1447 Ok(json!(false))
1448 },
1449 "nativeHost:isFullScreen" => {
1450 dev_log!("window", "nativeHost:isFullScreen");
1451 NativeIsFullscreen(ApplicationHandle.clone()).await
1452 },
1453 "nativeHost:isMaximized" => {
1454 dev_log!("window", "nativeHost:isMaximized");
1455 NativeIsMaximized(ApplicationHandle.clone()).await
1456 },
1457 "nativeHost:getActiveWindowId" => {
1458 dev_log!("window", "nativeHost:getActiveWindowId");
1459 Ok(json!(1))
1460 },
1461 "nativeHost:getCursorScreenPoint" => {
1476 dev_log!("window", "nativeHost:getCursorScreenPoint");
1477 Ok(json!({ "x": 0, "y": 0 }))
1482 },
1483 "nativeHost:getWindows" => {
1484 let Title = std::env::var("ProductNameShort").unwrap_or_else(|_| "Land".into());
1485 let ActiveDoc = RunTime
1486 .Environment
1487 .ApplicationState
1488 .Workspace
1489 .GetActiveDocumentURI()
1490 .unwrap_or_default();
1491 Ok(json!([{ "id": 1, "title": Title, "filename": ActiveDoc }]))
1492 },
1493 "nativeHost:getWindowCount" => Ok(json!(1)),
1494
1495 "nativeHost:openAgentsWindow" | "nativeHost:openDevToolsWindow" | "nativeHost:openAuxiliaryWindow" => {
1505 dev_log!("window", "{} (acknowledged, no-op - aux window unsupported)", command);
1506 Ok(Value::Null)
1507 },
1508
1509 "nativeHost:focusWindow" => {
1513 dev_log!("window", "{}", command);
1514 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1515 let _ = Window.set_focus();
1516 }
1517 Ok(Value::Null)
1518 },
1519 "nativeHost:maximizeWindow" => {
1520 dev_log!("window", "{}", command);
1521 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1522 let _ = Window.maximize();
1523 }
1524 Ok(Value::Null)
1525 },
1526 "nativeHost:unmaximizeWindow" => {
1527 dev_log!("window", "{}", command);
1528 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1529 let _ = Window.unmaximize();
1530 }
1531 Ok(Value::Null)
1532 },
1533 "nativeHost:minimizeWindow" => {
1534 dev_log!("window", "{}", command);
1535 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1536 let _ = Window.minimize();
1537 }
1538 Ok(Value::Null)
1539 },
1540 "nativeHost:toggleFullScreen" => {
1541 dev_log!("window", "{}", command);
1542 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1543 let IsFullscreen = Window.is_fullscreen().unwrap_or(false);
1544 let _ = Window.set_fullscreen(!IsFullscreen);
1545 }
1546 Ok(Value::Null)
1547 },
1548 "nativeHost:closeWindow" => {
1549 dev_log!("window", "{}", command);
1550 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1556 let _ = Window.destroy();
1557 }
1558 Ok(Value::Null)
1559 },
1560 "nativeHost:setWindowAlwaysOnTop" => {
1561 dev_log!("window", "{}", command);
1562 let OnTop = Arguments.first().and_then(|V| V.as_bool()).unwrap_or(false);
1563 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1564 let _ = Window.set_always_on_top(OnTop);
1565 }
1566 Ok(Value::Null)
1567 },
1568 "nativeHost:toggleWindowAlwaysOnTop" => {
1569 dev_log!("window", "{}", command);
1570 static ALWAYS_ON_TOP:std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
1571 let Next = !ALWAYS_ON_TOP.fetch_xor(true, std::sync::atomic::Ordering::Relaxed);
1572 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1573 let _ = Window.set_always_on_top(Next);
1574 }
1575 Ok(Value::Null)
1576 },
1577 "nativeHost:setRepresentedFilename" => {
1581 dev_log!("window", "{}", command);
1582 let Path = Arguments.first().and_then(|V| V.as_str()).unwrap_or("").to_string();
1583 if !Path.is_empty() {
1584 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1585 let Filename = std::path::Path::new(&Path)
1588 .file_name()
1589 .and_then(|N| N.to_str())
1590 .unwrap_or(&Path);
1591 let _ = Window.set_title(Filename);
1592 }
1593 }
1594 Ok(Value::Null)
1595 },
1596
1597 "nativeHost:setDocumentEdited" => {
1601 let _ = Arguments;
1602 Ok(Value::Null)
1603 },
1604
1605 "nativeHost:setMinimumSize" => {
1608 let Width = Arguments.first().and_then(|V| V.as_u64()).unwrap_or(400) as u32;
1609 let Height = Arguments.get(1).and_then(|V| V.as_u64()).unwrap_or(300) as u32;
1610 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1611 let _ = Window.set_min_size(Some(tauri::Size::Physical(tauri::PhysicalSize {
1612 width:Width,
1613 height:Height,
1614 })));
1615 }
1616 Ok(Value::Null)
1617 },
1618
1619 "nativeHost:positionWindow" => {
1622 if let Some(Rect) = Arguments.first() {
1623 let X = Rect.get("x").and_then(|V| V.as_i64()).unwrap_or(0) as i32;
1624 let Y = Rect.get("y").and_then(|V| V.as_i64()).unwrap_or(0) as i32;
1625 let W = Rect.get("width").and_then(|V| V.as_u64()).unwrap_or(0) as u32;
1626 let H = Rect.get("height").and_then(|V| V.as_u64()).unwrap_or(0) as u32;
1627 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1628 let _ =
1629 Window.set_position(tauri::Position::Physical(tauri::PhysicalPosition { x:X, y:Y }));
1630 if W > 0 && H > 0 {
1631 let _ =
1632 Window.set_size(tauri::Size::Physical(tauri::PhysicalSize { width:W, height:H }));
1633 }
1634 }
1635 }
1636 Ok(Value::Null)
1637 },
1638
1639 "nativeHost:updateWindowControls"
1641 | "nativeHost:notifyReady"
1642 | "nativeHost:saveWindowSplash"
1643 | "nativeHost:updateTouchBar"
1644 | "nativeHost:moveWindowTop"
1645 | "nativeHost:setBackgroundThrottling"
1646 | "nativeHost:updateWindowAccentColor" => {
1647 dev_log!("window", "{}", command);
1648 Ok(Value::Null)
1649 },
1650
1651 "nativeHost:isAdmin" => Ok(json!(false)),
1653 "nativeHost:isRunningUnderARM64Translation" => NativeIsRunningUnderARM64Translation().await,
1654 "nativeHost:hasWSLFeatureInstalled" => {
1655 #[cfg(target_os = "windows")]
1656 {
1657 Ok(json!(std::path::Path::new("C:\\Windows\\System32\\wsl.exe").exists()))
1658 }
1659 #[cfg(not(target_os = "windows"))]
1660 {
1661 Ok(json!(false))
1662 }
1663 },
1664 "nativeHost:showItemInFolder" => ShowItemInFolder(RunTime.clone(), Arguments).await,
1665 "nativeHost:openExternal" => OpenExternal(RunTime.clone(), Arguments).await,
1666 "nativeHost:moveItemToTrash" => {
1668 dev_log!("nativehost", "nativeHost:moveItemToTrash");
1669 NativeMoveItemToTrash(Arguments).await
1670 },
1671
1672 "nativeHost:readClipboardText" => {
1674 dev_log!("clipboard", "readClipboardText");
1675 NativeReadClipboardText(Arguments).await
1676 },
1677 "nativeHost:writeClipboardText" => {
1678 dev_log!("clipboard", "writeClipboardText");
1679 NativeWriteClipboardText(Arguments).await
1680 },
1681 "nativeHost:readClipboardFindText" => {
1682 dev_log!("clipboard", "readClipboardFindText");
1683 NativeReadClipboardFindText(Arguments).await
1684 },
1685 "nativeHost:writeClipboardFindText" => {
1686 dev_log!("clipboard", "writeClipboardFindText");
1687 NativeWriteClipboardFindText(Arguments).await
1688 },
1689 "nativeHost:readClipboardBuffer" => {
1690 dev_log!("clipboard", "readClipboardBuffer");
1691 NativeReadClipboardBuffer(Arguments).await
1692 },
1693 "nativeHost:writeClipboardBuffer" => {
1694 dev_log!("clipboard", "writeClipboardBuffer");
1695 NativeWriteClipboardBuffer(Arguments).await
1696 },
1697 "nativeHost:hasClipboard" => {
1698 dev_log!("clipboard", "hasClipboard");
1699 NativeHasClipboard(Arguments).await
1700 },
1701 "nativeHost:readImage" => {
1702 dev_log!("clipboard", "readImage");
1703 NativeReadImage(Arguments).await
1704 },
1705 "nativeHost:triggerPaste" => {
1706 dev_log!("clipboard", "triggerPaste");
1707 NativeTriggerPaste(Arguments).await
1708 },
1709
1710 "nativeHost:getProcessId" => Ok(json!(std::process::id())),
1712 "nativeHost:killProcess" => KillProcess(Arguments).await,
1713
1714 "nativeHost:findFreePort" => NativeFindFreePort(Arguments).await,
1716 "nativeHost:isPortFree" => {
1717 let Port = Arguments.first().and_then(|V| V.as_u64()).unwrap_or(0) as u16;
1718 if Port == 0 {
1719 Ok(json!(false))
1720 } else {
1721 let Free = tokio::net::TcpListener::bind(std::net::SocketAddr::from(([127, 0, 0, 1], Port)))
1722 .await
1723 .is_ok();
1724 Ok(json!(Free))
1725 }
1726 },
1727 "nativeHost:resolveProxy" => {
1732 let Url = Arguments.first().and_then(|V| V.as_str()).unwrap_or("");
1733 let Scheme = if Url.starts_with("https") { "HTTPS" } else { "HTTP" };
1734 let ProxyEnv = std::env::var(format!("{}_PROXY", Scheme))
1735 .or_else(|_| std::env::var(format!("{}_proxy", Scheme.to_lowercase())))
1736 .or_else(|_| std::env::var("ALL_PROXY"))
1737 .or_else(|_| std::env::var("all_proxy"));
1738 match ProxyEnv {
1739 Ok(P) if !P.is_empty() => {
1740 let Lower = P.to_lowercase();
1744 let (Keyword, Host) = if Lower.starts_with("socks") {
1745 let H = P
1746 .trim_start_matches("socks5://")
1747 .trim_start_matches("socks4://")
1748 .trim_start_matches("socks://");
1749
1750 ("SOCKS", H)
1751 } else {
1752 let H = P.trim_start_matches("http://").trim_start_matches("https://");
1753
1754 ("PROXY", H)
1755 };
1756
1757 Ok(json!(format!("{} {}", Keyword, Host)))
1758 },
1759 _ => Ok(json!("DIRECT")),
1760 }
1761 },
1762 "nativeHost:lookupAuthorization" => Ok(Value::Null),
1763 "nativeHost:lookupKerberosAuthorization" => Ok(Value::Null),
1764 "nativeHost:loadCertificates" => Ok(json!([])),
1765
1766 "nativeHost:relaunch" => Relaunch(ApplicationHandle.clone(), Arguments).await,
1768 "nativeHost:reload" => Reload(ApplicationHandle.clone(), Arguments).await,
1769 "nativeHost:quit" => Quit(ApplicationHandle.clone(), Arguments).await,
1770 "nativeHost:exit" => Exit(ApplicationHandle.clone(), Arguments).await,
1771
1772 "nativeHost:openDevTools" => OpenDevTools(ApplicationHandle.clone(), Arguments).await,
1774 "nativeHost:toggleDevTools" => ToggleDevTools(ApplicationHandle.clone(), Arguments).await,
1775
1776 "nativeHost:getSystemIdleState" => Ok(json!("active")),
1778 "nativeHost:getSystemIdleTime" => Ok(json!(0)),
1779 "nativeHost:getCurrentThermalState" => Ok(json!("nominal")),
1780 "nativeHost:isOnBatteryPower" => Ok(json!(false)),
1781 "nativeHost:startPowerSaveBlocker" => Ok(json!(0)),
1782 "nativeHost:stopPowerSaveBlocker" => Ok(json!(false)),
1783 "nativeHost:isPowerSaveBlockerStarted" => Ok(json!(false)),
1784
1785 "browserView:updateKeybindings"
1790 | "browserView:updateTheme"
1791 | "browserView:updateConfiguration"
1792 | "browserView:openDevTools"
1793 | "browserView:closeDevTools" => Ok(Value::Null),
1794 "browserView:getBrowserViews" => Ok(serde_json::json!([])),
1795
1796 "nativeHost:newWindowTab" => Ok(Value::Null),
1798 "nativeHost:showPreviousWindowTab" => Ok(Value::Null),
1799 "nativeHost:showNextWindowTab" => Ok(Value::Null),
1800 "nativeHost:moveWindowTabToNewWindow" => Ok(Value::Null),
1801 "nativeHost:mergeAllWindowTabs" => Ok(Value::Null),
1802 "nativeHost:toggleWindowTabsBar" => Ok(Value::Null),
1803 "nativeHost:installShellCommand" => InstallShellCommand(Arguments).await,
1804 "nativeHost:uninstallShellCommand" => UninstallShellCommand(Arguments).await,
1805
1806 "localPty:getProfiles" => {
1810 dev_log!("terminal", "localPty:getProfiles");
1811 LocalPTYGetProfiles().await
1812 },
1813 "localPty:getDefaultSystemShell" => {
1814 dev_log!("terminal", "localPty:getDefaultSystemShell");
1815 LocalPTYGetDefaultShell().await
1816 },
1817 "localPty:getTerminalLayoutInfo" => {
1825 dev_log!("terminal", "localPty:getTerminalLayoutInfo");
1826 use CommonLibrary::{Environment::Requires::Requires, Storage::StorageProvider::StorageProvider};
1827 let StorageProvider:Arc<dyn StorageProvider> = RunTime.Environment.Require();
1828 match StorageProvider.GetStorageValue(true, "terminal:layoutInfo").await {
1829 Ok(Some(Stored)) => Ok(Stored),
1830 Ok(None) => Ok(Value::Null),
1831 Err(Error) => {
1832 dev_log!("terminal", "warn: [getTerminalLayoutInfo] storage read failed: {}", Error);
1833 Ok(Value::Null)
1834 },
1835 }
1836 },
1837 "localPty:setTerminalLayoutInfo" => {
1840 dev_log!("terminal", "localPty:setTerminalLayoutInfo");
1841 use CommonLibrary::{Environment::Requires::Requires, Storage::StorageProvider::StorageProvider};
1842 let StorageProvider:Arc<dyn StorageProvider> = RunTime.Environment.Require();
1843 let Payload = Arguments.first().cloned().unwrap_or(Value::Null);
1844 let _ = StorageProvider
1845 .UpdateStorageValue(true, "terminal:layoutInfo".to_string(), Some(Payload))
1846 .await;
1847 Ok(Value::Null)
1848 },
1849 "localPty:getPerformanceMarks" => {
1850 dev_log!("terminal", "localPty:getPerformanceMarks");
1851 Ok(json!([]))
1852 },
1853 "localPty:reduceConnectionGraceTime" => {
1854 dev_log!("terminal", "localPty:reduceConnectionGraceTime");
1855 Ok(Value::Null)
1856 },
1857 "localPty:listProcesses" => {
1858 dev_log!("terminal", "localPty:listProcesses");
1859 Ok(json!([]))
1860 },
1861 "localPty:getEnvironment" => {
1862 dev_log!("terminal", "localPty:getEnvironment");
1863 LocalPTYGetEnvironment().await
1864 },
1865 "localPty:getLatency" => {
1877 dev_log!("terminal", "localPty:getLatency");
1878 Ok(json!([]))
1879 },
1880
1881 "cocoon:request" => {
1892 dev_log!("ipc", "cocoon:request method={:?}", Arguments.first());
1893 CocoonRequest(Arguments).await
1894 },
1895 "cocoon:notify" => {
1896 dev_log!("ipc", "cocoon:notify method={:?}", Arguments.first());
1897 CocoonNotify(Arguments).await
1898 },
1899
1900 "localPty:spawn" => {
1917 dev_log!("terminal", "{}", command);
1922 TerminalCreate(RunTime.clone(), Arguments).await
1923 },
1924 "localPty:createProcess" => {
1925 dev_log!("terminal", "{}", command);
1926 LocalPTYCreateProcess(RunTime.clone(), Arguments).await
1927 },
1928 "localPty:start" => {
1929 dev_log!("terminal", "{} no-op (eager-spawn)", command);
1942 Ok(Value::Null)
1943 },
1944 "localPty:input" | "localPty:write" => {
1945 dev_log!("terminal", "{}", command);
1946 TerminalSendText(RunTime.clone(), Arguments).await
1947 },
1948 "localPty:shutdown" | "localPty:dispose" => {
1949 dev_log!("terminal", "{}", command);
1950 TerminalDispose(RunTime.clone(), Arguments).await
1951 },
1952 "localPty:resize" => {
1953 dev_log!("terminal", "localPty:resize");
1954 LocalPTYResize(RunTime.clone(), Arguments).await
1955 },
1956 "localPty:acknowledgeDataEvent" => {
1957 Ok(Value::Null)
1959 },
1960 "localPty:getBackendOS" => {
1965 #[cfg(target_os = "macos")]
1966 {
1967 Ok(json!(1))
1968 }
1969 #[cfg(target_os = "linux")]
1970 {
1971 Ok(json!(2))
1972 }
1973 #[cfg(target_os = "windows")]
1974 {
1975 Ok(json!(3))
1976 }
1977 #[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
1978 {
1979 Ok(json!(2))
1980 }
1981 },
1982
1983 "localPty:refreshProperty" => {
1993 use CommonLibrary::{
1994 Environment::Requires::Requires,
1995 Terminal::TerminalProvider::TerminalProvider,
1996 };
1997 let TerminalId = Arguments.first().and_then(|V| V.as_u64()).unwrap_or(0);
1998 let PropId = Arguments.get(1).and_then(|V| V.as_u64()).unwrap_or(0);
1999 if TerminalId == 0 {
2000 Ok(Value::Null)
2001 } else if PropId == 1 {
2002 let Provider:Arc<dyn TerminalProvider> = RunTime.Environment.Require();
2003 match Provider.GetTerminalProcessId(TerminalId).await {
2004 Ok(Some(Pid)) => Ok(json!(Pid)),
2005 _ => Ok(Value::Null),
2006 }
2007 } else {
2008 Ok(Value::Null)
2009 }
2010 },
2011
2012 "localPty:updateProperty" => Ok(Value::Null),
2015
2016 "localPty:freePortKillProcess" => {
2019 dev_log!("terminal", "localPty:freePortKillProcess");
2020 LocalPTYFreePortKillProcess(Arguments).await
2021 },
2022
2023 "localPty:serializeTerminalState" => {
2028 dev_log!("terminal", "localPty:serializeTerminalState");
2029 SerializeTerminalState(RunTime.clone()).await
2030 },
2031
2032 "localPty:reviveTerminalProcesses" => {
2036 dev_log!(
2037 "terminal",
2038 "localPty:reviveTerminalProcesses count={}",
2039 Arguments.first().and_then(|V| V.as_array()).map(|A| A.len()).unwrap_or(0)
2040 );
2041 ReviveTerminalProcesses(RunTime.clone(), Arguments).await
2042 },
2043
2044 "localPty:getRevivedPtyNewId" => {
2050 let NewId = RunTime.Environment.ApplicationState.GetNextTerminalIdentifier();
2051 dev_log!("terminal", "localPty:getRevivedPtyNewId id={}", NewId);
2052 Ok(json!(NewId))
2053 },
2054
2055 "localPty:attachToProcess" => {
2061 dev_log!("terminal", "localPty:attachToProcess");
2062 AttachToProcess(RunTime.clone(), Arguments).await
2063 },
2064 "localPty:detachFromProcess" => {
2065 dev_log!("terminal", "localPty:detachFromProcess");
2066 DetachFromProcess(RunTime.clone(), Arguments).await
2067 },
2068
2069 "localPty:processBinary"
2073 | "localPty:orphanQuestionReply"
2074 | "localPty:updateTitle"
2075 | "localPty:updateIcon"
2076 | "localPty:installAutoReply"
2077 | "localPty:uninstallAllAutoReplies" => Ok(Value::Null),
2078
2079 "update:_getInitialState" => UpdateGetInitialState().await,
2083 "update:isLatestVersion" => UpdateIsLatestVersion().await,
2084 "update:checkForUpdates" => UpdateCheckForUpdates().await,
2085 "update:downloadUpdate" => UpdateDownloadUpdate().await,
2086 "update:applyUpdate" => UpdateApplyUpdate().await,
2087 "update:quitAndInstall" => UpdateQuitAndInstall().await,
2088
2089 "url:registerExternalUriOpener" => {
2101 dev_log!("url", "url:registerExternalUriOpener");
2102 Ok(Value::Null)
2103 },
2104
2105 "encryption:encrypt" => Encrypt(Arguments).await,
2109 "encryption:decrypt" => Decrypt(Arguments).await,
2110
2111 "extensionHostStarter:createExtensionHost" => {
2115 dev_log!("exthost", "extensionHostStarter:createExtensionHost");
2116 ExtensionHostStarterCreate(Arguments).await
2117 },
2118 "extensionHostStarter:start" => {
2119 dev_log!("exthost", "extensionHostStarter:start");
2120 ExtensionHostStarterStart(Arguments).await
2121 },
2122 "extensionHostStarter:kill" => {
2123 dev_log!("exthost", "extensionHostStarter:kill");
2124 ExtensionHostStarterKill(Arguments).await
2125 },
2126 "extensionHostStarter:getExitInfo" => {
2127 dev_log!("exthost", "extensionHostStarter:getExitInfo");
2128 ExtensionHostStarterGetExitInfo(Arguments).await
2129 },
2130 "extensionHostStarter:waitForExit" => {
2131 dev_log!("exthost", "extensionHostStarter:waitForExit");
2132 ExtensionHostStarterWaitForExit(Arguments).await
2133 },
2134
2135 "cocoon:extensionHostMessage" => {
2139 dev_log!("exthost", "cocoon:extensionHostMessage");
2140 CocoonExtensionHostMessage(ApplicationHandle.clone(), Arguments).await
2141 },
2142
2143 "extensionhostdebugservice:reload" => {
2147 dev_log!("exthost", "extensionhostdebugservice:reload");
2148 ExtensionHostDebugReload(ApplicationHandle.clone()).await
2149 },
2150 "extensionhostdebugservice:close" => {
2151 dev_log!("exthost", "extensionhostdebugservice:close");
2152 ExtensionHostDebugClose(ApplicationHandle.clone()).await
2153 },
2154 "extensionhostdebugservice:attachSession" | "extensionhostdebugservice:terminateSession" => {
2155 dev_log!("exthost", "{}", command);
2156 Ok(Value::Null)
2157 },
2158
2159 "workspaces:getRecentlyOpened" => {
2163 dev_log!("workspaces", "workspaces:getRecentlyOpened");
2164 ReadRecentlyOpened()
2165 },
2166 "workspaces:removeRecentlyOpened" => {
2167 dev_log!("workspaces", "workspaces:removeRecentlyOpened");
2168 let Uri = Arguments.first().and_then(|V| V.as_str()).unwrap_or("").to_string();
2169 if !Uri.is_empty() {
2170 MutateRecentlyOpened(|List| {
2171 if let Some(Workspaces) = List.get_mut("workspaces").and_then(|V| V.as_array_mut()) {
2172 Workspaces
2173 .retain(|Entry| Entry.get("uri").and_then(|V| V.as_str()).unwrap_or("") != Uri);
2174 }
2175 if let Some(Files) = List.get_mut("files").and_then(|V| V.as_array_mut()) {
2176 Files.retain(|Entry| Entry.get("uri").and_then(|V| V.as_str()).unwrap_or("") != Uri);
2177 }
2178 });
2179 }
2180 Ok(Value::Null)
2181 },
2182 "workspaces:addRecentlyOpened" => {
2183 dev_log!("workspaces", "workspaces:addRecentlyOpened");
2184 let Entries:Vec<Value> = Arguments.first().and_then(|V| V.as_array()).cloned().unwrap_or_default();
2186 if !Entries.is_empty() {
2187 MutateRecentlyOpened(|List| {
2188 let Workspaces = List
2189 .get_mut("workspaces")
2190 .and_then(|V| V.as_array_mut())
2191 .map(|V| std::mem::take(V))
2192 .unwrap_or_default();
2193 let Files = List
2194 .get_mut("files")
2195 .and_then(|V| V.as_array_mut())
2196 .map(|V| std::mem::take(V))
2197 .unwrap_or_default();
2198 let mut MergedWorkspaces = Workspaces;
2199 let mut MergedFiles = Files;
2200 for Entry in Entries {
2201 let Folder = Entry
2202 .get("folderUri")
2203 .cloned()
2204 .or_else(|| Entry.get("workspace").and_then(|W| W.get("configPath").cloned()));
2205 let File = Entry.get("fileUri").cloned();
2206 if let Some(FolderUri) = Folder.and_then(|V| v_str(&V)) {
2207 MergedWorkspaces
2208 .retain(|E| E.get("uri").and_then(|V| V.as_str()).unwrap_or("") != FolderUri);
2209 let mut Item = serde_json::Map::new();
2210 Item.insert("uri".into(), json!(FolderUri));
2211 if let Some(Label) = Entry.get("label").and_then(|V| V.as_str()) {
2212 Item.insert("label".into(), json!(Label));
2213 }
2214 MergedWorkspaces.insert(0, Value::Object(Item));
2215 }
2216 if let Some(FileUri) = File.and_then(|V| v_str(&V)) {
2217 MergedFiles
2218 .retain(|E| E.get("uri").and_then(|V| V.as_str()).unwrap_or("") != FileUri);
2219 let mut Item = serde_json::Map::new();
2220 Item.insert("uri".into(), json!(FileUri));
2221 MergedFiles.insert(0, Value::Object(Item));
2222 }
2223 }
2224 MergedWorkspaces.truncate(50);
2227 MergedFiles.truncate(50);
2228 List.insert("workspaces".into(), Value::Array(MergedWorkspaces));
2229 List.insert("files".into(), Value::Array(MergedFiles));
2230 });
2231 }
2232 Ok(Value::Null)
2233 },
2234 "workspaces:clearRecentlyOpened" => {
2235 dev_log!("workspaces", "workspaces:clearRecentlyOpened");
2236 MutateRecentlyOpened(|List| {
2237 List.insert("workspaces".into(), json!([]));
2238 List.insert("files".into(), json!([]));
2239 });
2240 Ok(Value::Null)
2241 },
2242 "workspaces:enterWorkspace" => {
2243 dev_log!("workspaces", "workspaces:enterWorkspace");
2244 Ok(Value::Null)
2245 },
2246 "workspaces:createUntitledWorkspace" => {
2247 dev_log!("workspaces", "workspaces:createUntitledWorkspace");
2248 Ok(Value::Null)
2249 },
2250 "workspaces:deleteUntitledWorkspace" => {
2251 dev_log!("workspaces", "workspaces:deleteUntitledWorkspace");
2252 Ok(Value::Null)
2253 },
2254 "workspaces:getWorkspaceIdentifier" => {
2255 let Workspace = &RunTime.Environment.ApplicationState.Workspace;
2262 let Folders = Workspace.GetWorkspaceFolders();
2263 if let Some(First) = Folders.first() {
2264 use std::{
2265 collections::hash_map::DefaultHasher,
2266 hash::{Hash, Hasher},
2267 };
2268 let mut Hasher = DefaultHasher::new();
2269 First.URI.as_str().hash(&mut Hasher);
2270 let Id = format!("{:016x}", Hasher.finish());
2271 Ok(json!({
2272 "id": Id,
2273 "configPath": Value::Null,
2274 "uri": First.URI.to_string(),
2275 }))
2276 } else {
2277 Ok(Value::Null)
2278 }
2279 },
2280 "workspaces:getDirtyWorkspaces" => Ok(json!([])),
2281
2282 "git:exec" => {
2287 dev_log!("git", "git:exec");
2288 Git::HandleExec::Fn(Arguments).await
2289 },
2290 "git:clone" => {
2291 dev_log!("git", "git:clone");
2292 Git::HandleClone::Fn(Arguments).await
2293 },
2294 "git:pull" => {
2295 dev_log!("git", "git:pull");
2296 Git::HandlePull::Fn(Arguments).await
2297 },
2298 "git:checkout" => {
2299 dev_log!("git", "git:checkout");
2300 Git::HandleCheckout::Fn(Arguments).await
2301 },
2302 "git:revParse" => {
2303 dev_log!("git", "git:revParse");
2304 Git::HandleRevParse::Fn(Arguments).await
2305 },
2306 "git:fetch" => {
2307 dev_log!("git", "git:fetch");
2308 Git::HandleFetch::Fn(Arguments).await
2309 },
2310 "git:revListCount" => {
2311 dev_log!("git", "git:revListCount");
2312 Git::HandleRevListCount::Fn(Arguments).await
2313 },
2314 "git:cancel" => {
2315 dev_log!("git", "git:cancel");
2316 Git::HandleCancel::Fn(Arguments).await
2317 },
2318 "git:isAvailable" => {
2319 dev_log!("git", "git:isAvailable");
2320 Git::HandleIsAvailable::Fn(Arguments).await
2321 },
2322
2323 "tree:getChildren" => TreeGetChildren(ApplicationHandle.clone(), RunTime.clone(), Arguments).await,
2330
2331 "tree.reveal" | "tree:reveal" => {
2334 use tauri::Emitter;
2335 let ViewId = Arguments.first().and_then(|V| V.as_str()).unwrap_or("").to_string();
2336 let Handle = Arguments.get(1).and_then(|V| V.as_str()).map(String::from).unwrap_or_default();
2337 let Options = Arguments.get(2).cloned().unwrap_or(Value::Null);
2338 dev_log!("ipc", "tree.reveal viewId={} handle={}", ViewId, Handle);
2339 let _ = ApplicationHandle.emit(
2340 "sky://tree-view/reveal",
2341 json!({
2342 "viewId": ViewId,
2343 "handle": Handle,
2344 "options": Options,
2345 }),
2346 );
2347 Ok(Value::Null)
2348 },
2349
2350 "tree:selectionChanged" | "tree:collapseElement" | "tree:expandElement" | "tree:visibilityChanged" => {
2354 let Payload = Arguments.first().cloned().unwrap_or(Value::Null);
2355 let Method = match command.as_str() {
2356 "tree:selectionChanged" => "$treeView:selectionChanged",
2357 "tree:collapseElement" => "$treeView:collapseElement",
2358 "tree:expandElement" => "$treeView:expandElement",
2359 _ => "$treeView:visibilityChanged",
2360 };
2361 tokio::spawn(async move {
2362 if let Err(E) = crate::Vine::Client::SendNotification::Fn(
2363 "cocoon-main".to_string(),
2364 Method.to_string(),
2365 Payload,
2366 )
2367 .await
2368 {
2369 dev_log!("ipc", "warn: [tree] Cocoon notify {} failed: {:?}", Method, E);
2370 }
2371 });
2372 Ok(Value::Null)
2373 },
2374
2375 "sky:replay-events" => SkyReplayEvents(ApplicationHandle.clone(), RunTime.clone()).await,
2377
2378 "editor:revealRange" | "window:revealRange" => {
2382 use tauri::Emitter;
2383 let Payload = Arguments.first().cloned().unwrap_or(Value::Null);
2384 let _ = ApplicationHandle.emit("sky://editor/revealRange", &Payload);
2385 Ok(Value::Null)
2386 },
2387
2388 "sky:editor:selectionChanged" => {
2396 let Uri = Arguments
2397 .first()
2398 .and_then(|V| V.get("uri"))
2399 .and_then(|V| V.as_str())
2400 .unwrap_or("")
2401 .to_string();
2402 let Selections = Arguments
2403 .first()
2404 .and_then(|V| V.get("selections"))
2405 .cloned()
2406 .unwrap_or(Value::Array(Vec::new()));
2407 dev_log!("model", "[SelectionChanged] uri={}", Uri);
2408 if !Uri.is_empty() {
2410 RunTime
2411 .Environment
2412 .ApplicationState
2413 .Workspace
2414 .SetActiveDocumentURI(Some(Uri.clone()));
2415 }
2416 let ViewColumn = Arguments
2417 .first()
2418 .and_then(|V| V.get("viewColumn"))
2419 .and_then(|V| V.as_u64())
2420 .unwrap_or(1);
2421 let Payload = json!({ "uri": Uri, "selections": Selections, "viewColumn": ViewColumn });
2425 let _ = crate::Vine::Client::SendNotification::Fn(
2426 "cocoon-main".to_string(),
2427 "window.didChangeTextEditorSelection".to_string(),
2428 Payload,
2429 )
2430 .await;
2431 Ok(Value::Null)
2432 },
2433
2434 "sky:model:contentChanged" => {
2440 let Payload = Arguments.first().cloned().unwrap_or(Value::Null);
2441 let Uri = Payload.get("uri").and_then(Value::as_str).unwrap_or("").to_string();
2442 if !Uri.is_empty() {
2443 let Content = Payload.get("content").and_then(Value::as_str).unwrap_or("").to_string();
2444 let Version = Payload.get("version").and_then(Value::as_i64).unwrap_or(1);
2445 if let Some(mut Doc) = RunTime.Environment.ApplicationState.Feature.Documents.Get(&Uri) {
2447 Doc.Version = Version;
2448 Doc.Lines = Content.lines().map(|L| L.to_owned()).collect();
2449 Doc.IsDirty = true;
2450 RunTime
2451 .Environment
2452 .ApplicationState
2453 .Feature
2454 .Documents
2455 .AddOrUpdate(Uri.clone(), Doc);
2456 }
2457 let Payload2 = json!([
2459 { "external": Uri.clone(), "$mid": 1 },
2460 { "content": Content, "versionId": Version, "isDirty": true, "changes": [] }
2461 ]);
2462 tokio::spawn(async move {
2463 let _ = crate::Vine::Client::SendNotification::Fn(
2464 "cocoon-main".to_string(),
2465 "$acceptModelChanged".to_string(),
2466 Payload2,
2467 )
2468 .await;
2469 });
2470 }
2471 Ok(Value::Null)
2472 },
2473
2474 "sky:editor:activeChanged" => {
2475 let Payload = Arguments.first().cloned().unwrap_or(Value::Null);
2476 let Uri = Payload.get("uri").and_then(Value::as_str).unwrap_or("").to_string();
2477 dev_log!("model", "[ActiveEditorChanged] uri={}", Uri);
2478 if !Uri.is_empty() {
2479 RunTime
2480 .Environment
2481 .ApplicationState
2482 .Workspace
2483 .SetActiveDocumentURI(Some(Uri.clone()));
2484 }
2485 let _ = crate::Vine::Client::SendNotification::Fn(
2486 "cocoon-main".to_string(),
2487 "window.didChangeActiveTextEditor".to_string(),
2488 Payload,
2489 )
2490 .await;
2491 Ok(Value::Null)
2492 },
2493
2494 "language:provideInlineCompletions" => {
2505 let Payload = Arguments.first().cloned().unwrap_or(Value::Null);
2506 let UriStr = Payload.get("uri").and_then(Value::as_str).unwrap_or("").to_string();
2507
2508 if UriStr.is_empty() {
2509 Ok(json!({ "items": [] }))
2510 } else {
2511 let Line = Payload
2512 .get("position")
2513 .and_then(|P| P.get("line"))
2514 .and_then(Value::as_u64)
2515 .unwrap_or(0) as i64 + 1;
2516 let Character = Payload
2517 .get("position")
2518 .and_then(|P| P.get("character"))
2519 .and_then(Value::as_u64)
2520 .unwrap_or(0) as i64 + 1;
2521 let Context = Payload.get("context").cloned().unwrap_or_else(|| json!({ "triggerKind": 0 }));
2522
2523 match url::Url::parse(&UriStr) {
2524 Ok(Uri) => {
2525 let Position = PositionDTO { LineNumber:Line as u32, Column:Character as u32 };
2526 match RunTime.Environment.ProvideInlineCompletionItems(Uri, Position, Context).await {
2527 Ok(Some(Result)) => {
2528 let Items = Result
2529 .get("items")
2530 .cloned()
2531 .unwrap_or_else(|| if Result.is_array() { Result } else { json!([]) });
2532 Ok(json!({ "items": Items }))
2533 },
2534 Ok(None) => Ok(json!({ "items": [] })),
2535 Err(Error) => {
2536 dev_log!("ipc", "warn: language:provideInlineCompletions error: {}", Error);
2537 Ok(json!({ "items": [] }))
2538 },
2539 }
2540 },
2541 Err(_) => Ok(json!({ "items": [] })),
2542 }
2543 }
2544 },
2545
2546 "languages:getAll" | "languages:getEncodedLanguageId" => {
2547 dev_log!("extensions", "languages: {} (→ Cocoon)", command);
2548 let Payload = Arguments.into_iter().next().unwrap_or(Value::Null);
2549 if !crate::Vine::Client::IsClientConnected::Fn("cocoon-main") {
2559 Ok(Value::Array(Vec::new()))
2560 } else {
2561 Ok(
2562 crate::Vine::Client::SendRequest::Fn("cocoon-main", command.clone(), Payload, 5_000)
2563 .await
2564 .unwrap_or(Value::Array(Vec::new())),
2565 )
2566 }
2567 },
2568
2569 "scm:createSourceControl" | "scm:getSourceControls" | "scm:setActiveProvider" => {
2573 dev_log!("ipc", "scm: {} (→ Cocoon)", command);
2574 let Payload = if Arguments.is_empty() {
2575 Value::Null
2576 } else if Arguments.len() == 1 {
2577 Arguments.into_iter().next().unwrap()
2578 } else {
2579 Value::Array(Arguments)
2580 };
2581 let _ = crate::Vine::Client::WaitForClientConnection::Fn("cocoon-main", 3000).await;
2582 Ok(
2583 crate::Vine::Client::SendRequest::Fn("cocoon-main", command.clone(), Payload, 10_000)
2584 .await
2585 .unwrap_or(Value::Null),
2586 )
2587 },
2588
2589 "debug:startDebugging"
2593 | "debug:stopDebugging"
2594 | "debug:getSessions"
2595 | "debug:getBreakpoints"
2596 | "debug:addBreakpoints"
2597 | "debug:removeBreakpoints" => {
2598 dev_log!("ipc", "debug: {} (→ Cocoon)", command);
2599 let Payload = if Arguments.is_empty() {
2600 Value::Null
2601 } else if Arguments.len() == 1 {
2602 Arguments.into_iter().next().unwrap()
2603 } else {
2604 Value::Array(Arguments)
2605 };
2606 let _ = crate::Vine::Client::WaitForClientConnection::Fn("cocoon-main", 3000).await;
2607 Ok(
2608 crate::Vine::Client::SendRequest::Fn("cocoon-main", command.clone(), Payload, 10_000)
2609 .await
2610 .unwrap_or(Value::Null),
2611 )
2612 },
2613
2614 "tasks:executeTask" | "tasks:getTasks" | "tasks:getTaskExecution" => {
2618 dev_log!("ipc", "tasks: {} (→ Cocoon)", command);
2619 let Payload = if Arguments.is_empty() {
2620 Value::Null
2621 } else if Arguments.len() == 1 {
2622 Arguments.into_iter().next().unwrap()
2623 } else {
2624 Value::Array(Arguments)
2625 };
2626 let _ = crate::Vine::Client::WaitForClientConnection::Fn("cocoon-main", 3000).await;
2627 Ok(
2628 crate::Vine::Client::SendRequest::Fn("cocoon-main", command.clone(), Payload, 10_000)
2629 .await
2630 .unwrap_or(Value::Null),
2631 )
2632 },
2633
2634 "auth:getSessions" | "auth:createSession" | "auth:removeSession" => {
2638 dev_log!("ipc", "auth: {} (→ Cocoon)", command);
2639 let Payload = if Arguments.is_empty() {
2640 Value::Null
2641 } else if Arguments.len() == 1 {
2642 Arguments.into_iter().next().unwrap()
2643 } else {
2644 Value::Array(Arguments)
2645 };
2646 let _ = crate::Vine::Client::WaitForClientConnection::Fn("cocoon-main", 3000).await;
2647 Ok(
2648 crate::Vine::Client::SendRequest::Fn("cocoon-main", command.clone(), Payload, 10_000)
2649 .await
2650 .unwrap_or(Value::Null),
2651 )
2652 },
2653
2654 _ => {
2667 use std::str::FromStr;
2668
2669 let TierIPC = std::env::var("TierIPC").unwrap_or_else(|_| "Mountain".into());
2674 let ShouldDefer = TierIPC == "NodeDeferred" || TierIPC == "Node";
2675
2676 if ShouldDefer {
2677 let Payload = if Arguments.is_empty() {
2681 Value::Null
2682 } else if Arguments.len() == 1 {
2683 Arguments.into_iter().next().unwrap()
2684 } else {
2685 Value::Array(Arguments)
2686 };
2687 dev_log!("ipc", "deferred → Cocoon: {}", command);
2688 let _ = crate::Vine::Client::WaitForClientConnection::Fn("cocoon-main", 3000).await;
2689 match crate::Vine::Client::SendRequest::Fn("cocoon-main", command.clone(), Payload, 15_000)
2690 .await
2691 {
2692 Ok(Response) => Ok(Response),
2693 Err(CocoonError) => {
2694 dev_log!(
2695 "ipc",
2696 "warn: [NodeDeferred] {} deferred but Cocoon rejected: {:?}",
2697 command,
2698 CocoonError
2699 );
2700 Ok(Value::Null)
2701 },
2702 }
2703 } else {
2704 match CommonLibrary::IPC::Channel::Channel::from_str(&command) {
2705 Ok(KnownChannel) => {
2706 dev_log!(
2707 "ipc",
2708 "error: [WindServiceHandlers] Channel {:?} is registered but has no dispatch arm",
2709 KnownChannel
2710 );
2711 Err(format!("IPC channel registered but unimplemented: {}", command))
2712 },
2713 Err(_) => {
2714 dev_log!("ipc", "error: [WindServiceHandlers] Unknown IPC command: {}", command);
2715 Err(format!("Unknown IPC command: {}", command))
2716 },
2717 }
2718 }
2719 },
2720 };
2721
2722 if ResultSender.send(MatchResult).is_err() {
2723 dev_log!(
2724 "ipc",
2725 "warn: [WindServiceHandlers] IPC result receiver dropped before dispatch completed"
2726 );
2727 }
2728 },
2729 CommandPriority,
2730 );
2731
2732 let Result = match ResultReceiver.await {
2733 Ok(Dispatched) => Dispatched,
2734
2735 Err(_) => {
2736 dev_log!(
2737 "ipc",
2738 "error: [WindServiceHandlers] IPC task cancelled before producing a result"
2739 );
2740
2741 Err("IPC task cancelled before result was produced".to_string())
2742 },
2743 };
2744
2745 if !IsHighFrequencyCommand {
2749 let IsErr = Result.is_err();
2750
2751 let SpanName = if IsErr {
2752 format!("land:mountain:ipc:{}:error", command)
2753 } else {
2754 format!("land:mountain:ipc:{}", command)
2755 };
2756
2757 crate::otel_span!(&SpanName, OTLPStart, &[("ipc.command", command.as_str())]);
2758
2759 let HandlerElapsedNanos = crate::IPC::DevLog::NowNano::Fn().saturating_sub(OTLPStart);
2763
2764 let HandlerDurationMs = HandlerElapsedNanos / 1_000_000;
2765
2766 crate::Binary::Build::PostHogPlugin::CaptureHandler::Fn(&command, HandlerDurationMs, !IsErr);
2767 }
2768
2769 if !IsHighFrequencyCommand {
2778 let ElapsedNanos = crate::IPC::DevLog::NowNano::Fn().saturating_sub(OTLPStart);
2779
2780 dev_log!("ipc", "done: {} ok={} t_ns={}", command, !Result.is_err(), ElapsedNanos);
2781 }
2782
2783 Result
2784}
2785
2786pub fn register_wind_ipc_handlers(ApplicationHandle:&tauri::AppHandle) -> Result<(), String> {
2787 dev_log!("lifecycle", "registering IPC handlers");
2788
2789 Ok(())
2793}