Skip to main content

Mountain/Command/Hover/
Fn.rs

1//! # Hover Function
2//!
3//! Implements hover functionality for language features.
4//!
5//! ## Responsibilities
6//!
7//! - Handle hover requests from the frontend
8//! - Delegate to language feature providers
9//! - Transform provider responses to standard format
10//!
11//! ## Architectural Role
12//!
13//! This module is part of the **Command layer**, providing the actual
14//! hover functionality that bridges the frontend to the language service.
15//!
16//! ## Design
17//!
18//! - Single async function as the entry point
19//! - Validates input before processing
20//! - Delegates to providers for actual implementation
21//! - Returns standardized response
22
23use serde_json::Value;
24use tauri::{AppHandle, Wry};
25use url::Url;
26
27use crate::{
28	Command::Hover::Interface::{
29		HoverRequest::Struct as HoverRequest,
30		HoverResponse::Struct as HoverResponse,
31		Position::Struct as Position,
32	},
33	dev_log,
34};
35
36/// Validates a hover request
37fn ValidateRequest(uri:&str, position:&Value) -> Result<HoverRequest, String> {
38	// Parse URI
39	let document_uri = Url::parse(uri).map_err(|e| format!("Invalid URI: {}", e))?;
40
41	// Parse position from JSON value
42	let position_dto:Position =
43		serde_json::from_value(position.clone()).map_err(|e| format!("Invalid position: {}", e))?;
44
45	Ok(HoverRequest { uri:document_uri.to_string(), position:position_dto })
46}
47
48/// Provides hover information at the given document position.
49///
50/// This function is the main entry point for the hover command,
51/// called by the Tauri command dispatcher.
52///
53/// # Arguments
54///
55/// * `application_handle` - The Tauri application handle
56/// * `uri` - The URI of the document
57/// * `position` - The position in the document to get hover for
58///
59/// # Returns
60///
61/// Returns a `HoverResponse` containing the hover contents, or an error string.
62pub async fn Hover(application_handle:AppHandle<Wry>, uri:String, position:Value) -> Result<HoverResponse, String> {
63	dev_log!("commands", "[Hover] Providing hover for: {} at {:?}", uri, position);
64
65	// Validate request
66	let request = ValidateRequest(&uri, &position)?;
67
68	// Get the document URI
69	let document_uri = Url::parse(&request.uri).map_err(|e| format!("Failed to parse URI: {}", e))?;
70
71	// Delegate to the provider implementation
72	// Note: This is a stub - actual implementation would call the provider
73	let _result = ProvideHover(document_uri, request.position).await?;
74
75	// For now, return an empty response
76	// DEPENDENCY: Full hover implementation requires provider registry in
77	// ApplicationState and provider invocation via RPC to language server
78	Ok(HoverResponse::default())
79}
80
81/// Internal implementation to get hover from a provider.
82///
83/// This would typically invoke the language feature provider registry
84/// to find an appropriate provider for the document.
85async fn ProvideHover(_uri:Url, _position:Position) -> Result<HoverResponse, String> {
86	// DEPENDENCY: Provider invocation requires:
87	// 1. Provider registry lookup in ApplicationState by document URI
88	// 2. RPC call to language server via CocoonService
89	// 3. Result transformation to HoverResponse
90
91	dev_log!("commands", "[Hover] Calling provider for hover information");
92
93	Ok(HoverResponse::default())
94}
95
96#[cfg(test)]
97mod tests {
98	use super::*;
99
100	#[test]
101	fn test_validate_request_valid() {
102		let uri = "file:///test.rs";
103		let position = serde_json::json!({
104			"line": 10,
105			"character": 5
106		});
107
108		let result = ValidateRequest(uri, &position);
109		assert!(result.is_ok());
110
111		let request = result.unwrap();
112		assert_eq!(request.uri, uri);
113		assert_eq!(request.position.line, 10);
114		assert_eq!(request.position.character, 5);
115	}
116
117	#[test]
118	fn test_validate_request_invalid_uri() {
119		let uri = "not-a-valid-uri";
120		let position = serde_json::json!({
121			"line": 10,
122			"character": 5
123		});
124
125		let result = ValidateRequest(uri, &position);
126		assert!(result.is_err());
127	}
128
129	#[test]
130	fn test_validate_request_invalid_position() {
131		let uri = "file:///test.rs";
132		let position = serde_json::json!({
133			"not_a_position": true
134		});
135
136		let result = ValidateRequest(uri, &position);
137		assert!(result.is_err());
138	}
139
140	#[test]
141	fn test_hover_response_default() {
142		let response = HoverResponse::default();
143		assert!(response.contents.is_empty());
144		assert!(response.range.is_none());
145	}
146
147	#[test]
148	fn test_hover_response_with_contents() {
149		use crate::Command::Hover::Interface::HoverContent::Enum as HoverContent;
150
151		let contents = vec![HoverContent::PlainText("Test hover".to_string())];
152		let response = HoverResponse::new(contents);
153
154		assert_eq!(response.contents.len(), 1);
155		assert!(response.range.is_none());
156	}
157}