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}