Mountain/Environment/
LanguageFeatureProvider.rs

1// File: Mountain/Source/Environment/LanguageFeatureProvider.rs
2// Role: Implements the `LanguageFeatureProviderRegistry` trait for the
3// `MountainEnvironment`. Responsibilities:
4//   - The central hub for all language intelligence features.
5//   - Routes requests from the application to the appropriate extension
6//     provider hosted in the `Cocoon` sidecar.
7//   - Manages the registration and lifecycle of language providers.
8
9//! # LanguageFeatureProvider Implementation
10//!
11//! Implements the `LanguageFeatureProviderRegistry` trait for the
12//! `MountainEnvironment`. This provider is the central hub for all language
13//! intelligence features, routing requests from the application to the
14//! appropriate extension provider hosted in the `Cocoon` sidecar.
15
16#![allow(non_snake_case, non_camel_case_types)]
17
18use std::sync::Arc;
19
20use Common::{
21	Environment::Requires::Requires,
22	Error::CommonError::CommonError,
23	IPC::IPCProvider::IPCProvider,
24	LanguageFeature::{
25		DTO::{
26			CompletionContextDTO::CompletionContextDTO,
27			CompletionListDTO::CompletionListDTO,
28			HoverResultDTO::HoverResultDTO,
29			LocationDTO::LocationDTO,
30			PositionDTO::PositionDTO,
31			ProviderType::ProviderType,
32			TextEditDTO::TextEditDTO,
33		},
34		LanguageFeatureProviderRegistry::LanguageFeatureProviderRegistry,
35	},
36};
37use async_trait::async_trait;
38use log::{debug, info, warn};
39use serde::de::DeserializeOwned;
40use serde_json::{Value, json};
41use url::Url;
42
43use super::{MountainEnvironment::MountainEnvironment, Utility};
44use crate::ApplicationState::DTO::ProviderRegistrationDTO::ProviderRegistrationDTO;
45
46#[async_trait]
47impl LanguageFeatureProviderRegistry for MountainEnvironment {
48	async fn RegisterProvider(
49		&self,
50
51		SideCarIdentifier:String,
52
53		ProviderType:ProviderType,
54
55		SelectorDTO:Value,
56
57		ExtensionIdentifierDTO:Value,
58
59		OptionsDTO:Option<Value>,
60	) -> Result<u32, CommonError> {
61		let Handle = self.ApplicationState.GetNextProviderHandle();
62
63		info!(
64			"[LangFeatureProvider] Registering {:?} provider from '{}' with new handle {}",
65			ProviderType, SideCarIdentifier, Handle
66		);
67
68		let NewRegistration = ProviderRegistrationDTO {
69			Handle,
70
71			ProviderType,
72
73			Selector:SelectorDTO,
74
75			SideCarIdentifier,
76
77			Options:OptionsDTO,
78
79			ExtensionIdentifier:ExtensionIdentifierDTO,
80		};
81
82		self.ApplicationState
83			.LanguageProviders
84			.lock()
85			.map_err(Utility::MapApplicationStateLockErrorToCommonError)?
86			.insert(Handle, NewRegistration);
87
88		Ok(Handle)
89	}
90
91	async fn UnregisterProvider(&self, Handle:u32) -> Result<(), CommonError> {
92		info!("[LangFeatureProvider] Unregistering provider with handle {}", Handle);
93
94		if self
95			.ApplicationState
96			.LanguageProviders
97			.lock()
98			.map_err(Utility::MapApplicationStateLockErrorToCommonError)?
99			.remove(&Handle)
100			.is_none()
101		{
102			warn!(
103				"[LangFeatureProvider] Attempted to unregister a provider with handle {} that was not found.",
104				Handle
105			);
106		}
107		Ok(())
108	}
109
110	// --- Invocation Methods ---
111	async fn ProvideHover(
112		&self,
113
114		DocumentURI:Url,
115
116		PositionDTO:PositionDTO,
117	) -> Result<Option<HoverResultDTO>, CommonError> {
118		InvokeProvider(self, ProviderType::Hover, &DocumentURI, json!([PositionDTO])).await
119	}
120
121	async fn ProvideCompletions(
122		&self,
123
124		DocumentURI:Url,
125
126		PositionDTO:PositionDTO,
127
128		ContextDTO:CompletionContextDTO,
129
130		CancellationTokenValue:Option<Value>,
131	) -> Result<Option<CompletionListDTO>, CommonError> {
132		InvokeProvider(
133			self,
134			ProviderType::Completion,
135			&DocumentURI,
136			json!([PositionDTO, ContextDTO, CancellationTokenValue]),
137		)
138		.await
139	}
140
141	async fn ProvideDefinition(
142		&self,
143
144		DocumentURI:Url,
145
146		PositionDTO:PositionDTO,
147	) -> Result<Option<Vec<LocationDTO>>, CommonError> {
148		InvokeProvider(self, ProviderType::Definition, &DocumentURI, json!([PositionDTO])).await
149	}
150
151	async fn ProvideReferences(
152		&self,
153
154		DocumentURI:Url,
155
156		PositionDTO:PositionDTO,
157
158		ContextDTO:Value,
159	) -> Result<Option<Vec<LocationDTO>>, CommonError> {
160		InvokeProvider(self, ProviderType::References, &DocumentURI, json!([PositionDTO, ContextDTO])).await
161	}
162
163	async fn ProvideDocumentFormattingEdits(
164		&self,
165
166		DocumentURI:Url,
167
168		OptionsDTO:Value,
169	) -> Result<Option<Vec<TextEditDTO>>, CommonError> {
170		InvokeProvider(self, ProviderType::DocumentFormatting, &DocumentURI, json!([OptionsDTO])).await
171	}
172
173	async fn ProvideDocumentRangeFormattingEdits(
174		&self,
175
176		DocumentURI:Url,
177
178		RangeDTO:Value,
179
180		OptionsDTO:Value,
181	) -> Result<Option<Vec<TextEditDTO>>, CommonError> {
182		InvokeProvider(
183			self,
184			ProviderType::DocumentRangeFormatting,
185			&DocumentURI,
186			json!([RangeDTO, OptionsDTO]),
187		)
188		.await
189	}
190
191	// --- Stubs for other provider methods ---
192	async fn ProvideCodeActions(
193		&self,
194
195		_DocumentURI:Url,
196
197		_RangeOrSelectionDTO:Value,
198
199		_ContextDTO:Value,
200	) -> Result<Option<Value>, CommonError> {
201		warn!("[LangFeatureProvider] ProvideCodeActions is not implemented.");
202
203		Ok(None)
204	}
205
206	async fn ProvideCodeLenses(&self, _DocumentURI:Url) -> Result<Option<Value>, CommonError> {
207		warn!("[LangFeatureProvider] ProvideCodeLenses is not implemented.");
208
209		Ok(None)
210	}
211
212	async fn ProvideDocumentHighlights(
213		&self,
214
215		_DocumentURI:Url,
216
217		_PositionDTO:PositionDTO,
218	) -> Result<Option<Value>, CommonError> {
219		warn!("[LangFeatureProvider] ProvideDocumentHighlights is not implemented.");
220
221		Ok(None)
222	}
223
224	async fn ProvideDocumentLinks(&self, _DocumentURI:Url) -> Result<Option<Value>, CommonError> {
225		warn!("[LangFeatureProvider] ProvideDocumentLinks is not implemented.");
226
227		Ok(None)
228	}
229
230	async fn PrepareRename(&self, _DocumentURI:Url, _PositionDTO:PositionDTO) -> Result<Option<Value>, CommonError> {
231		warn!("[LangFeatureProvider] PrepareRename is not implemented.");
232
233		Ok(None)
234	}
235}
236
237// --- Internal Helper for Invocation ---
238
239/// Finds the best provider for a given feature and document.
240fn FindBestProvider(
241	Environment:&MountainEnvironment,
242
243	ProviderType:ProviderType,
244
245	DocumentURI:&Url,
246) -> Result<Option<ProviderRegistrationDTO>, CommonError> {
247	let Providers = Environment
248		.ApplicationState
249		.LanguageProviders
250		.lock()
251		.map_err(Utility::MapApplicationStateLockErrorToCommonError)?;
252
253	let Document = Environment
254		.ApplicationState
255		.OpenDocuments
256		.lock()
257		.map_err(Utility::MapApplicationStateLockErrorToCommonError)?
258		.get(DocumentURI.as_str())
259		.cloned();
260
261	if let Some(doc) = Document {
262		// This is a simplified selector matching logic. A real implementation would
263		// score providers based on how well their DocumentSelector matches the
264		// document.
265		for Provider in Providers.values() {
266			if Provider.ProviderType == ProviderType {
267				if let Some(SelectorArray) = Provider.Selector.as_array() {
268					for Selector in SelectorArray {
269						if let Some(Lang) = Selector.get("language").and_then(Value::as_str) {
270							if Lang == doc.LanguageIdentifier {
271								debug!("Found provider with handle {} for document {}", Provider.Handle, DocumentURI);
272
273								return Ok(Some(Provider.clone()));
274							}
275						}
276						// TODO: Add scheme and pattern matching logic here.
277					}
278				}
279			}
280		}
281	}
282	warn!("No provider found for {:?} on document {}", ProviderType, DocumentURI);
283
284	Ok(None)
285}
286
287/// A generic helper to find the best provider, invoke it via RPC, and
288/// deserialize the result.
289async fn InvokeProvider<TResponse:DeserializeOwned>(
290	Environment:&MountainEnvironment,
291
292	ProviderType:ProviderType,
293
294	DocumentURI:&Url,
295
296	mut ProviderArguments:Value,
297) -> Result<Option<TResponse>, CommonError> {
298	if let Some(Provider) = FindBestProvider(Environment, ProviderType, DocumentURI)? {
299		let RPCMethod = format!("$provide{}", Provider.ProviderType.to_string());
300
301		let URIComponents = json!({ "external": DocumentURI.to_string(), "$mid": 1 });
302
303		let ArgumentsVector = ProviderArguments.as_array_mut().ok_or_else(|| {
304			CommonError::InvalidArgument {
305				ArgumentName:"ProviderArguments".into(),
306
307				Reason:"Expected provider arguments to be a JSON array.".into(),
308			}
309		})?;
310
311		let mut FinalArgumentsVector = vec![json!(Provider.Handle), URIComponents];
312
313		FinalArgumentsVector.append(ArgumentsVector);
314
315		let FinalArguments = json!(FinalArgumentsVector);
316
317		let IPCProvider:Arc<dyn IPCProvider> = Environment.Require();
318
319		let Response = IPCProvider
320			.SendRequestToSideCar(Provider.SideCarIdentifier, RPCMethod, FinalArguments, 5000)
321			.await?;
322
323		if Response.is_null() {
324			return Ok(None);
325		}
326		serde_json::from_value(Response).map_err(|Error| {
327			CommonError::SerializationError {
328				Description:format!("Failed to deserialize response for {:?}: {}", ProviderType, Error),
329			}
330		})
331	} else {
332		Ok(None)
333	}
334}