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