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;
41use url::Url;
42
43use super::MountainEnvironment::MountainEnvironment;
44use crate::dev_log;
45
46static CUSTOM_EDITOR_REGISTRY:OnceLock<Mutex<HashMap<String, String>>> = OnceLock::new();
51
52fn GetRegistry() -> &'static Mutex<HashMap<String, String>> {
53 CUSTOM_EDITOR_REGISTRY.get_or_init(|| Mutex::new(HashMap::new()))
54}
55
56pub fn LookupSidecarForViewType(ViewType:&str) -> String {
59 GetRegistry()
60 .lock()
61 .ok()
62 .and_then(|G| G.get(ViewType).cloned())
63 .unwrap_or_else(|| "cocoon-main".to_string())
64}
65
66#[async_trait]
67impl CustomEditorProvider for MountainEnvironment {
68 async fn RegisterCustomEditorProvider(&self, ViewType:String, _Options:Value) -> Result<(), CommonError> {
69 dev_log!(
70 "extensions",
71 "[CustomEditorProvider] Registering provider for view type: {}",
72 ViewType
73 );
74
75 if ViewType.is_empty() {
77 return Err(CommonError::InvalidArgument {
78 ArgumentName:"ViewType".to_string(),
79 Reason:"ViewType cannot be empty".to_string(),
80 });
81 }
82
83 let SidecarId = _Options
87 .get("sidecarId")
88 .and_then(Value::as_str)
89 .unwrap_or("cocoon-main")
90 .to_string();
91
92 if let Ok(mut Registry) = GetRegistry().lock() {
93 let IsNew = !Registry.contains_key(&ViewType);
94
95 Registry.insert(ViewType.clone(), SidecarId.clone());
96
97 dev_log!(
98 "extensions",
99 "[CustomEditorProvider] {} provider registered: viewType={} sidecar={}",
100 if IsNew { "New" } else { "Updated" },
101 ViewType,
102 SidecarId
103 );
104 }
105
106 Ok(())
107 }
108
109 async fn UnregisterCustomEditorProvider(&self, ViewType:String) -> Result<(), CommonError> {
110 dev_log!(
111 "extensions",
112 "[CustomEditorProvider] Unregistering provider for view type: {}",
113 ViewType
114 );
115
116 if let Ok(mut Registry) = GetRegistry().lock() {
117 let Removed = Registry.remove(&ViewType).is_some();
118
119 dev_log!(
120 "extensions",
121 "[CustomEditorProvider] Provider unregistered: viewType={} (was_present={})",
122 ViewType,
123 Removed
124 );
125 }
126
127 Ok(())
128 }
129
130 async fn OnSaveCustomDocument(&self, ViewType:String, ResourceURI:Url) -> Result<(), CommonError> {
131 dev_log!(
132 "extensions",
133 "[CustomEditorProvider] OnSaveCustomDocument called for '{}' at '{}'",
134 ViewType,
135 ResourceURI
136 );
137
138 let IPCProvider:Arc<dyn IPCProvider> = self.Require();
161
162 let DocumentIdentifier = json!({
163 "viewType": ViewType,
164 "resource": { "external": ResourceURI.to_string() },
165 });
166
167 let RPCMethod = format!("{}$onSaveCustomDocument", ProxyTarget::ExtHostCustomEditors.GetTargetPrefix());
168
169 let RPCParameters = json!([DocumentIdentifier, 0]);
170
171 match IPCProvider
172 .SendRequestToSideCar("cocoon-main".to_string(), RPCMethod, RPCParameters, 30_000)
173 .await
174 {
175 Ok(_) => {
176 dev_log!(
177 "extensions",
178 "[CustomEditorProvider] OnSaveCustomDocument completed for '{}' at '{}'",
179 ViewType,
180 ResourceURI
181 );
182
183 let _ = self.ApplicationHandle.emit(
184 "sky://customEditor/saved",
185 json!({
186 "viewType": ViewType,
187 "resource": ResourceURI.to_string(),
188 }),
189 );
190
191 Ok(())
192 },
193
194 Err(Error) => {
195 dev_log!(
196 "extensions",
197 "warn: [CustomEditorProvider] OnSaveCustomDocument failed for '{}' at '{}': {:?}",
198 ViewType,
199 ResourceURI,
200 Error
201 );
202
203 Err(Error)
204 },
205 }
206 }
207
208 async fn ResolveCustomEditor(
209 &self,
210
211 ViewType:String,
212
213 ResourceURI:Url,
214
215 WebviewPanelHandle:String,
216 ) -> Result<(), CommonError> {
217 dev_log!(
218 "extensions",
219 "[CustomEditorProvider] Resolving custom editor for '{}' on resource '{}'",
220 ViewType,
221 ResourceURI
222 );
223
224 let IPCProvider:Arc<dyn IPCProvider> = self.Require();
233
234 let ResourceURIComponents = json!({ "external": ResourceURI.to_string() });
235
236 let RPCMethod = format!("{}$resolveCustomEditor", ProxyTarget::ExtHostCustomEditors.GetTargetPrefix());
237
238 let RPCParameters = json!([ResourceURIComponents, ViewType, WebviewPanelHandle]);
239
240 IPCProvider
243 .SendNotificationToSideCar("cocoon-main".to_string(), RPCMethod, RPCParameters)
244 .await
245 }
246}