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;
52
53use super::{
54 ConfigurationState::ConfigurationState::State as ConfigurationState,
55 ExtensionState::State::State as ExtensionState,
56 FeatureState::State::State as FeatureState,
57 UIState::UIState::State as UIState,
58 WorkspaceState::WorkspaceState::State as WorkspaceState,
59};
60use crate::{Environment::TestProvider::TestProviderState::Struct as TestProviderState, dev_log};
61
62/// The central, shared, thread-safe state for the entire Mountain application.
63#[derive(Clone)]
64pub struct ApplicationState {
65 /// Workspace state containing workspace folders, trust, and active
66 /// document.
67 pub Workspace:WorkspaceState,
68
69 /// Configuration and storage state.
70 pub Configuration:ConfigurationState,
71
72 /// Extension management state.
73 pub Extension:ExtensionState,
74
75 /// Feature-specific state.
76 pub Feature:FeatureState,
77
78 /// User interface request state.
79 pub UI:UIState,
80
81 /// Test provider state.
82 pub TestProviderState:Arc<tokio::sync::RwLock<TestProviderState>>,
83
84 /// Memento storage paths.
85 pub GlobalMementoPath:Arc<StandardMutex<std::path::PathBuf>>,
86
87 pub WorkspaceMementoPath:Arc<StandardMutex<Option<std::path::PathBuf>>>,
88}
89
90impl Default for ApplicationState {
91 fn default() -> Self {
92 dev_log!("lifecycle", "[ApplicationState] Initializing default application state...");
93
94 Self {
95 Workspace:Default::default(),
96
97 Configuration:Default::default(),
98
99 Extension:Default::default(),
100
101 Feature:Default::default(),
102
103 UI:Default::default(),
104
105 TestProviderState:Arc::new(tokio::sync::RwLock::new(TestProviderState::new())),
106
107 GlobalMementoPath:Arc::new(StandardMutex::new(Default::default())),
108
109 WorkspaceMementoPath:Arc::new(StandardMutex::new(None)),
110 }
111 }
112}
113
114impl ApplicationState {
115 /// Gets the next available unique identifier for a provider registration.
116 pub fn GetNextProviderHandle(&self) -> u32 { self.Extension.GetNextProviderHandle() }
117
118 /// Gets the next available unique identifier for a terminal instance.
119 pub fn GetNextTerminalIdentifier(&self) -> u64 { self.Feature.GetNextTerminalIdentifier() }
120
121 /// Gets the next available unique identifier for an SCM provider.
122 pub fn GetNextSourceControlManagementProviderHandle(&self) -> u32 {
123 self.Feature.GetNextSourceControlManagementProviderHandle()
124 }
125
126 /// Gets the workspace identifier for the current application instance.
127 /// This is used to differentiate between different workspace instances
128 /// when running multiple instances of the application.
129 pub fn GetWorkspaceIdentifier(&self) -> Result<String, CommonError> {
130 // For now, generate a simple identifier based on the current timestamp
131 // In a proper implementation, this would be stored and persisted
132 use std::time::{SystemTime, UNIX_EPOCH};
133
134 let timestamp = SystemTime::now()
135 .duration_since(UNIX_EPOCH)
136 .map_err(|e| CommonError::Unknown { Description:format!("Failed to get system time: {}", e) })?;
137
138 Ok(format!("workspace-{:x}", timestamp.as_millis()))
139 }
140}
141
142/// A helper to map a mutex poison error into a CommonError.
143pub fn MapLockError<T>(Error:PoisonError<T>) -> CommonError {
144 CommonError::StateLockPoisoned { Context:Error.to_string() }
145}
146
147/// A helper to map a mutex poison error with recovery attempt.
148pub fn MapLockErrorWithRecovery<T>(Error:PoisonError<T>, RecoveryContext:&str) -> CommonError {
149 dev_log!(
150 "lifecycle",
151 "warn: [ApplicationState] Attempting recovery from poisoned lock in context: {}",
152 RecoveryContext
153 );
154
155 CommonError::StateLockPoisoned {
156 Context:format!("{} - Recovery attempted: {}", Error.to_string(), RecoveryContext),
157 }
158}
159
160/// Error handling result with recovery information.
161#[derive(Debug)]
162pub struct StateOperationResult<T> {
163 pub result:Result<T, CommonError>,
164
165 pub recovery_attempted:bool,
166
167 pub recovery_successful:bool,
168}