Mountain/ApplicationState/State/
ApplicationState.rs

1//! # ApplicationState Module (ApplicationState)
2//!
3//! ## RESPONSIBILITIES
4//! Central state management for the Mountain application, aggregating all
5//! state modules into a single source of truth.
6//!
7//! ## ARCHITECTURAL ROLE
8//! The ApplicationState is the **state container** that aggregates all
9//! domain-specific state modules and provides thread-safe access.
10//!
11//! ```text
12//! UI ──► Commands ──► ApplicationState (State) ──► Providers/Services
13//!                      │
14//!                      ↓
15//!                   Disk (Persistence)
16//! ```
17//!
18//! ### Design Principles:
19//! 1. **Single Source of Truth**: All state lives in one place
20//! 2. **Thread Safety**: All state is protected by Arc<Mutex<...>>
21//! 3. **Recovery-Oriented**: Comprehensive error handling and recovery
22//! 4. **Type Safety**: Strong typing at all levels
23//! 5. **Observability**: Comprehensive logging for state changes
24//!
25//! ## KEY COMPONENTS
26//! - Workspace: Workspace folders, trust, active document
27//! - Configuration: Configuration, memento storage
28//! - Extension: Extension registry, providers, scanned extensions
29//! - Feature: Diagnostics, documents, terminals, webviews, etc.
30//! - UI: Pending UI requests
31//!
32//! ## ERROR HANDLING
33//! All state operations use `Arc<Mutex<...>>` for thread-safety with proper
34//! error handling via `MapLockError` helpers.
35//!
36//! ## LOGGING
37//! State changes are logged at appropriate levels (debug, info, warn, error).
38//!
39//! ## PERFORMANCE CONSIDERATIONS
40//! - Lock mutexes briefly and release immediately
41//! - Avoid nested locks to prevent deadlocks
42//! - Use Arc for shared ownership across threads
43//!
44//! ## TODO
45//! - [ ] Add state validation invariants
46//! - [ ] Implement state metrics collection
47//! - [ ] Add state diffing for debugging
48
49use std::sync::{Arc, Mutex as StandardMutex, PoisonError};
50
51use CommonLibrary::Error::CommonError::CommonError;
52use log::debug;
53
54use super::{
55	ConfigurationState::State as ConfigurationState,
56	ExtensionState::State::State as ExtensionState,
57	FeatureState::State::State as FeatureState,
58	UIState::State as UIState,
59	WorkspaceState::State as WorkspaceState,
60};
61use crate::Environment::TestProvider::TestProviderState;
62
63/// The central, shared, thread-safe state for the entire Mountain application.
64#[derive(Clone)]
65pub struct ApplicationState {
66	/// Workspace state containing workspace folders, trust, and active
67	/// document.
68	pub Workspace:WorkspaceState,
69
70	/// Configuration and storage state.
71	pub Configuration:ConfigurationState,
72
73	/// Extension management state.
74	pub Extension:ExtensionState,
75
76	/// Feature-specific state.
77	pub Feature:FeatureState,
78
79	/// User interface request state.
80	pub UI:UIState,
81
82	/// Test provider state.
83	pub TestProviderState:Arc<tokio::sync::RwLock<TestProviderState>>,
84
85	/// Memento storage paths.
86	pub GlobalMementoPath:std::path::PathBuf,
87	pub WorkspaceMementoPath:Arc<StandardMutex<Option<std::path::PathBuf>>>,
88}
89
90impl Default for ApplicationState {
91	fn default() -> Self {
92		debug!("[ApplicationState] Initializing default application state...");
93
94		Self {
95			Workspace:Default::default(),
96			Configuration:Default::default(),
97			Extension:Default::default(),
98			Feature:Default::default(),
99			UI:Default::default(),
100			TestProviderState:Arc::new(tokio::sync::RwLock::new(TestProviderState::new())),
101			GlobalMementoPath:Default::default(),
102			WorkspaceMementoPath:Arc::new(StandardMutex::new(None)),
103		}
104	}
105}
106
107impl ApplicationState {
108	/// Gets the next available unique identifier for a provider registration.
109	pub fn GetNextProviderHandle(&self) -> u32 { self.Extension.GetNextProviderHandle() }
110
111	/// Gets the next available unique identifier for a terminal instance.
112	pub fn GetNextTerminalIdentifier(&self) -> u64 { self.Feature.GetNextTerminalIdentifier() }
113
114	/// Gets the next available unique identifier for an SCM provider.
115	pub fn GetNextSourceControlManagementProviderHandle(&self) -> u32 {
116		self.Feature.GetNextSourceControlManagementProviderHandle()
117	}
118
119	/// Gets the workspace identifier for the current application instance.
120	/// This is used to differentiate between different workspace instances
121	/// when running multiple instances of the application.
122	pub fn GetWorkspaceIdentifier(&self) -> Result<String, CommonError> {
123		// For now, generate a simple identifier based on the current timestamp
124		// In a proper implementation, this would be stored and persisted
125		use std::time::{SystemTime, UNIX_EPOCH};
126
127		let timestamp = SystemTime::now()
128			.duration_since(UNIX_EPOCH)
129			.map_err(|e| CommonError::Unknown { Description:format!("Failed to get system time: {}", e) })?;
130
131		Ok(format!("workspace-{:x}", timestamp.as_millis()))
132	}
133}
134
135/// A helper to map a mutex poison error into a CommonError.
136pub fn MapLockError<T>(Error:PoisonError<T>) -> CommonError {
137	CommonError::StateLockPoisoned { Context:Error.to_string() }
138}
139
140/// A helper to map a mutex poison error with recovery attempt.
141pub fn MapLockErrorWithRecovery<T>(Error:PoisonError<T>, RecoveryContext:&str) -> CommonError {
142	log::warn!(
143		"[ApplicationState] Attempting recovery from poisoned lock in context: {}",
144		RecoveryContext
145	);
146	CommonError::StateLockPoisoned {
147		Context:format!("{} - Recovery attempted: {}", Error.to_string(), RecoveryContext),
148	}
149}
150
151/// Error handling result with recovery information.
152#[derive(Debug)]
153pub struct StateOperationResult<T> {
154	pub result:Result<T, CommonError>,
155	pub recovery_attempted:bool,
156	pub recovery_successful:bool,
157}