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