DevelopmentNodeEnvironment_MicrosoftVSCodeDependency_22NodeVersion_Bundle_Clean_Debug_ElectronProfile_EsbuildCompiler_Mountain/Environment/
CustomEditorProvider.rs1use std::{
28 collections::HashMap,
29 sync::{Arc, Mutex, OnceLock},
30};
31
32use CommonLibrary::{
33 CustomEditor::CustomEditorProvider::CustomEditorProvider,
34 Environment::Requires::Requires,
35 Error::CommonError::CommonError,
36 IPC::{DTO::ProxyTarget::ProxyTarget, IPCProvider::IPCProvider},
37};
38use async_trait::async_trait;
39use serde_json::{Value, json};
40use tauri::{Emitter, Manager};
41use url::Url;
42
43use super::MountainEnvironment::MountainEnvironment;
44use crate::{
45 RunTime::ApplicationRunTime::ApplicationRunTime,
46 Track::Effect::CreateEffectForRequest::Utilities::Proxy::proxy_cocoon,
47 dev_log,
48};
49
50static CUSTOM_EDITOR_REGISTRY:OnceLock<Mutex<HashMap<String, String>>> = OnceLock::new();
55
56fn GetRegistry() -> &'static Mutex<HashMap<String, String>> {
57 CUSTOM_EDITOR_REGISTRY.get_or_init(|| Mutex::new(HashMap::new()))
58}
59
60pub fn LookupSidecarForViewType(ViewType:&str) -> String {
63 GetRegistry()
64 .lock()
65 .ok()
66 .and_then(|G| G.get(ViewType).cloned())
67 .unwrap_or_else(|| "cocoon-main".to_string())
68}
69
70#[async_trait]
71impl CustomEditorProvider for MountainEnvironment {
72 async fn RegisterCustomEditorProvider(&self, ViewType:String, _Options:Value) -> Result<(), CommonError> {
73 dev_log!(
74 "extensions",
75 "[CustomEditorProvider] Registering provider for view type: {}",
76 ViewType
77 );
78
79 if ViewType.is_empty() {
81 return Err(CommonError::InvalidArgument {
82 ArgumentName:"ViewType".to_string(),
83 Reason:"ViewType cannot be empty".to_string(),
84 });
85 }
86
87 let SidecarId = _Options
91 .get("sidecarId")
92 .and_then(Value::as_str)
93 .unwrap_or("cocoon-main")
94 .to_string();
95
96 if let Ok(mut Registry) = GetRegistry().lock() {
97 let IsNew = !Registry.contains_key(&ViewType);
98
99 Registry.insert(ViewType.clone(), SidecarId.clone());
100
101 dev_log!(
102 "extensions",
103 "[CustomEditorProvider] {} provider registered: viewType={} sidecar={}",
104 if IsNew { "New" } else { "Updated" },
105 ViewType,
106 SidecarId
107 );
108 }
109
110 Ok(())
111 }
112
113 async fn UnregisterCustomEditorProvider(&self, ViewType:String) -> Result<(), CommonError> {
114 dev_log!(
115 "extensions",
116 "[CustomEditorProvider] Unregistering provider for view type: {}",
117 ViewType
118 );
119
120 if let Ok(mut Registry) = GetRegistry().lock() {
121 let Removed = Registry.remove(&ViewType).is_some();
122
123 dev_log!(
124 "extensions",
125 "[CustomEditorProvider] Provider unregistered: viewType={} (was_present={})",
126 ViewType,
127 Removed
128 );
129 }
130
131 Ok(())
132 }
133
134 async fn OnSaveCustomDocument(&self, ViewType:String, ResourceURI:Url) -> Result<(), CommonError> {
135 dev_log!(
136 "extensions",
137 "[CustomEditorProvider] OnSaveCustomDocument called for '{}' at '{}'",
138 ViewType,
139 ResourceURI
140 );
141
142 let run_time:Arc<ApplicationRunTime> =
165 self.ApplicationHandle.state::<Arc<ApplicationRunTime>>().inner().clone();
166
167 let DocumentIdentifier = json!({
168 "viewType": ViewType,
169 "resource": { "external": ResourceURI.to_string() },
170 });
171
172 let RPCParameters = json!([DocumentIdentifier, 0]);
173
174 match proxy_cocoon(
175 &run_time,
176 ProxyTarget::ExtHostCustomEditors,
177 "onSaveCustomDocument",
178 RPCParameters,
179 30_000,
180 )
181 .await
182 .map_err(|e| CommonError::IPCError { Description:e })
183 {
184 Ok(_) => {
185 dev_log!(
186 "extensions",
187 "[CustomEditorProvider] OnSaveCustomDocument completed for '{}' at '{}'",
188 ViewType,
189 ResourceURI
190 );
191
192 let _ = self.ApplicationHandle.emit(
193 "sky://customEditor/saved",
194 json!({
195 "viewType": ViewType,
196 "resource": ResourceURI.to_string(),
197 }),
198 );
199
200 Ok(())
201 },
202
203 Err(Error) => {
204 dev_log!(
205 "extensions",
206 "warn: [CustomEditorProvider] OnSaveCustomDocument failed for '{}' at '{}': {:?}",
207 ViewType,
208 ResourceURI,
209 Error
210 );
211
212 Err(Error)
213 },
214 }
215 }
216
217 async fn ResolveCustomEditor(
218 &self,
219
220 ViewType:String,
221
222 ResourceURI:Url,
223
224 WebviewPanelHandle:String,
225 ) -> Result<(), CommonError> {
226 dev_log!(
227 "extensions",
228 "[CustomEditorProvider] Resolving custom editor for '{}' on resource '{}'",
229 ViewType,
230 ResourceURI
231 );
232
233 let IPCProvider:Arc<dyn IPCProvider> = self.Require();
242
243 let ResourceURIComponents = json!({ "external": ResourceURI.to_string() });
244
245 let RPCMethod = format!("{}$resolveCustomEditor", ProxyTarget::ExtHostCustomEditors.GetTargetPrefix());
246
247 let RPCParameters = json!([ResourceURIComponents, ViewType, WebviewPanelHandle]);
248
249 IPCProvider
252 .SendNotificationToSideCar("cocoon-main".to_string(), RPCMethod, RPCParameters)
253 .await
254 }
255}