Mountain/Environment/DocumentProvider/
OpenDocument.rs1use std::sync::Arc;
20
21use CommonLibrary::{
22 Effect::ApplicationRunTime::ApplicationRunTime as _,
23 Environment::Requires::Requires,
24 Error::CommonError::CommonError,
25 FileSystem::ReadFile::ReadFile,
26 IPC::{IPCProvider::IPCProvider, SkyEvent::SkyEvent},
27};
28use serde_json::{Value, json};
29use tauri::Manager;
34use url::Url;
35
36use crate::{
37 ApplicationState::DTO::DocumentStateDTO::DocumentStateDTO,
38 Environment::Utility,
39 IPC::SkyEmit::LogSkyEmit,
40 RunTime::ApplicationRunTime::ApplicationRunTime,
41 dev_log,
42};
43
44pub(super) async fn open_document(
48 environment:&crate::Environment::MountainEnvironment::MountainEnvironment,
49
50 uri_components_dto:Value,
51
52 language_identifier:Option<String>,
53
54 content:Option<String>,
55) -> Result<Url, CommonError> {
56 let uri = Utility::UriParsing::GetURLFromURIComponentsDTO(&uri_components_dto)?;
57
58 dev_log!("model", "[DocumentProvider] Opening document: {}", uri);
59
60 if let Some(existing_document) = environment
62 .ApplicationState
63 .Feature
64 .Documents
65 .OpenDocuments
66 .lock()
67 .map_err(Utility::ErrorMapping::MapApplicationStateLockErrorToCommonError)?
68 .get(uri.as_str())
69 {
70 dev_log!("model", "[DocumentProvider] Document {} is already open.", uri);
71
72 match existing_document.ToDTO() {
73 Ok(dto) => {
74 if let Err(error) = LogSkyEmit(&environment.ApplicationHandle, SkyEvent::DocumentsOpen.AsStr(), dto) {
75 dev_log!(
76 "model",
77 "error: [DocumentProvider] Failed to emit document open event: {}",
78 error
79 );
80 }
81 },
82
83 Err(error) => {
84 dev_log!(
85 "model",
86 "error: [DocumentProvider] Failed to serialize existing document DTO: {}",
87 error
88 );
89 },
90 }
91
92 return Ok(existing_document.URI.clone());
93 }
94
95 let file_content = if let Some(c) = content {
97 c
98 } else if uri.scheme() == "file" {
99 let file_path = uri.to_file_path().map_err(|_| {
100 CommonError::InvalidArgument {
101 ArgumentName:"URI".into(),
102 Reason:"Cannot convert non-file URI to path".into(),
103 }
104 })?;
105
106 let runtime = environment.ApplicationHandle.state::<Arc<ApplicationRunTime>>().inner().clone();
107
108 let file_content_bytes = runtime.Run(ReadFile(file_path.clone())).await?;
109
110 String::from_utf8(file_content_bytes)
111 .map_err(|error| CommonError::FileSystemIO { Path:file_path, Description:error.to_string() })?
112 } else {
113 dev_log!(
115 "model",
116 "[DocumentProvider] Non-native scheme '{}'. Attempting to resolve from sidecar.",
117 uri.scheme()
118 );
119
120 let ipc_provider:Arc<dyn IPCProvider> = environment.Require();
121
122 let rpc_result = ipc_provider
123 .SendRequestToSideCar(
124 "cocoon-main".to_string(),
126 "$provideTextDocumentContent".to_string(),
127 json!([uri_components_dto]),
128 10000,
129 )
130 .await?;
131
132 rpc_result.as_str().map(String::from).ok_or_else(|| {
133 CommonError::IPCError {
134 Description:format!("Failed to get valid string content for custom URI scheme '{}'", uri.scheme()),
135 }
136 })?
137 };
138
139 let new_document = DocumentStateDTO::Create(uri.clone(), language_identifier, file_content)?;
141
142 let dto_for_notification = new_document.ToDTO()?;
143
144 environment
145 .ApplicationState
146 .Feature
147 .Documents
148 .OpenDocuments
149 .lock()
150 .map_err(Utility::ErrorMapping::MapApplicationStateLockErrorToCommonError)?
151 .insert(uri.to_string(), new_document);
152
153 if let Err(error) = LogSkyEmit(
154 &environment.ApplicationHandle,
155 SkyEvent::DocumentsOpen.AsStr(),
156 dto_for_notification.clone(),
157 ) {
158 dev_log!(
159 "model",
160 "error: [DocumentProvider] Failed to emit document open event: {}",
161 error
162 );
163 }
164
165 crate::Environment::DocumentProvider::Notifications::notify_model_added(environment, &dto_for_notification).await;
166
167 Ok(uri)
168}