Mountain/Environment/WorkspaceProvider.rs
1//! # WorkspaceProvider (Environment)
2//!
3//! RESPONSIBILITIES:
4//! - Implements
5//! [`WorkspaceProvider`](CommonLibrary::Workspace::WorkspaceProvider) and
6//! [`WorkspaceEditApplier`](CommonLibrary::Workspace::WorkspaceEditApplier)
7//! traits for [`MountainEnvironment`]
8//! - Manages multi-root workspace folder operations and configuration
9//! - Provides workspace trust management and file discovery capabilities
10//! - Handles workspace edit application and custom editor routing
11//!
12//! ARCHITECTURAL ROLE:
13//! - Core provider in the Environment system, exposing workspace-level
14//! functionality to frontend via gRPC through the
15//! [`AirService`](crate::Air::AirServiceProvider)
16//! - Workspace provider is one of the foundational services alongside Document,
17//! Configuration, and Diagnostic providers
18//! - Integrates with
19//! [`ApplicationState`](crate::ApplicationState::ApplicationState) for
20//! persistent workspace folder storage
21//!
22//! ERROR HANDLING:
23//! - Uses [`CommonError`](CommonLibrary::Error::CommonError) for all operations
24//! - Application state lock errors are mapped using
25//! [`Utility::MapApplicationStateLockErrorToCommonError`]
26//! - Some operations are stubbed with logging (FindFilesInWorkspace, OpenFile,
27//! ApplyWorkspaceEdit)
28//!
29//! PERFORMANCE:
30//! - Workspace folder lookup uses O(n) linear search through folder list
31//! - Lock contention on `ApplicationState.Workspace.WorkspaceFolders` should be
32//! minimized
33//! - File discovery and workspace edit application are not yet optimized
34//!
35//! VS CODE REFERENCE:
36//! - `vs/workbench/services/workspace/browser/workspaceService.ts` - workspace
37//! service implementation
38//! - `vs/workbench/contrib/files/common/editors/textFileEditor.ts` - file
39//! editor integration
40//! - `vs/platform/workspace/common/workspace.ts` - workspace types and
41//! interfaces
42//!
43//! TODO:
44//! - Implement actual file search with glob pattern matching
45//! - Implement file opening with workspace-relative paths
46//! - Complete workspace edit application logic
47//! - Add workspace event propagation to subscribers
48//! - Implement custom editor routing by view type
49//!
50//! MODULE CONTENTS:
51//! - [`WorkspaceProvider`](CommonLibrary::Workspace::WorkspaceProvider)
52//! implementation:
53//! - `GetWorkspaceFoldersInfo` - enumerate all workspace folders
54//! - `GetWorkspaceFolderInfo` - find folder containing a URI
55//! - `GetWorkspaceName` - workspace identifier from state
56//! - `GetWorkspaceConfigurationPath` - .code-workspace path
57//! - `IsWorkspaceTrusted` - trust status check
58//! - `RequestWorkspaceTrust` - trust acquisition (stub)
59//! - `FindFilesInWorkspace` - file discovery (stub)
60//! - `OpenFile` - file opening (stub)
61//! - [`WorkspaceEditApplier`](CommonLibrary::Workspace::WorkspaceEditApplier)
62//! implementation:
63//! - `ApplyWorkspaceEdit` - edit application (stub)
64//! - Data types: [`(Url, String, usize)`] tuple for folder info (URI, name,
65//! index)
66
67use std::{path::PathBuf, sync::Arc};
68
69use CommonLibrary::{
70 DTO::WorkspaceEditDTO::WorkspaceEditDTO,
71 Error::CommonError::CommonError,
72 Workspace::{WorkspaceEditApplier::WorkspaceEditApplier, WorkspaceProvider::WorkspaceProvider},
73};
74use async_trait::async_trait;
75use log::{info, warn};
76use serde_json::Value;
77use url::Url;
78
79use super::{MountainEnvironment::MountainEnvironment, Utility};
80
81#[async_trait]
82impl WorkspaceProvider for MountainEnvironment {
83 /// Retrieves information about all currently open workspace folders.
84 async fn GetWorkspaceFoldersInfo(&self) -> Result<Vec<(Url, String, usize)>, CommonError> {
85 info!("[WorkspaceProvider] Getting workspace folders info.");
86 let FoldersGuard = self
87 .ApplicationState
88 .Workspace
89 .WorkspaceFolders
90 .lock()
91 .map_err(Utility::MapApplicationStateLockErrorToCommonError)?;
92 Ok(FoldersGuard.iter().map(|f| (f.URI.clone(), f.Name.clone(), f.Index)).collect())
93 }
94
95 /// Retrieves information for the specific workspace folder that contains a
96 /// given URI.
97 async fn GetWorkspaceFolderInfo(&self, URIToMatch:Url) -> Result<Option<(Url, String, usize)>, CommonError> {
98 let FoldersGuard = self
99 .ApplicationState
100 .Workspace
101 .WorkspaceFolders
102 .lock()
103 .map_err(Utility::MapApplicationStateLockErrorToCommonError)?;
104 for Folder in FoldersGuard.iter() {
105 if URIToMatch.as_str().starts_with(Folder.URI.as_str()) {
106 return Ok(Some((Folder.URI.clone(), Folder.Name.clone(), Folder.Index)));
107 }
108 }
109
110 Ok(None)
111 }
112
113 /// Gets the name of the current workspace.
114 async fn GetWorkspaceName(&self) -> Result<Option<String>, CommonError> {
115 self.ApplicationState.GetWorkspaceIdentifier().map(Some)
116 }
117
118 /// Gets the path to the workspace configuration file (`.code-workspace`).
119 async fn GetWorkspaceConfigurationPath(&self) -> Result<Option<PathBuf>, CommonError> {
120 Ok(self
121 .ApplicationState
122 .Workspace
123 .WorkspaceConfigurationPath
124 .lock()
125 .map_err(Utility::MapApplicationStateLockErrorToCommonError)?
126 .clone())
127 }
128
129 /// Checks if the current workspace is trusted.
130 async fn IsWorkspaceTrusted(&self) -> Result<bool, CommonError> {
131 Ok(self
132 .ApplicationState
133 .Workspace
134 .IsTrusted
135 .load(std::sync::atomic::Ordering::Relaxed))
136 }
137
138 /// Requests workspace trust from the user.
139 async fn RequestWorkspaceTrust(&self, _Options:Option<Value>) -> Result<bool, CommonError> {
140 warn!("[WorkspaceProvider] RequestWorkspaceTrust is not implemented; defaulting to trusted.");
141 Ok(true)
142 }
143
144 /// Finds files in the workspace matching the specified query.
145 async fn FindFilesInWorkspace(
146 &self,
147 _query:Value,
148 _:Option<Value>,
149 _:Option<usize>,
150 _:bool,
151 _:bool,
152 ) -> Result<Vec<Url>, CommonError> {
153 info!("[WorkspaceProvider] FindFilesInWorkspace called");
154 // Scan all workspace folders to find files matching the query pattern. This
155 // integrates with FileSystemReader to traverse directories, apply glob and
156 // exclude patterns, and return matching file URIs. Respect query parameters
157 // including maxResults, excludePatterns, and .gitignore rules. The result
158 // set supports fuzzy search, symbol search, and quick file open features.
159 // Currently returns an empty result set.
160 Ok(Vec::new())
161 }
162
163 /// Opens a file in the workspace.
164 async fn OpenFile(&self, path:PathBuf) -> Result<(), CommonError> {
165 info!("[WorkspaceProvider] OpenFile called for: {:?}", path);
166 // Open a file in the editor by delegating to the Workbench or command system.
167 // Resolves the path relative to workspace roots, handles URI schemes (file://,
168 // untitled:), and triggers the 'workbench.action.files.open' command or
169 // equivalent. Creates a new document tab with the file contents, activating
170 // the editor and adding the file to the recently opened list. Currently a
171 // no-op.
172 Ok(())
173 }
174}
175
176#[async_trait]
177impl WorkspaceEditApplier for MountainEnvironment {
178 /// Applies a workspace edit to the workspace.
179 async fn ApplyWorkspaceEdit(&self, Edit:WorkspaceEditDTO) -> Result<bool, CommonError> {
180 info!("[WorkspaceEditApplier] Applying workspace edit");
181
182 // For now, just log the edit details
183 match Edit {
184 WorkspaceEditDTO { Edits } => {
185 for (DocumentURI, TextEdits) in Edits {
186 info!(
187 "[WorkspaceEditApplier] Would apply {} edits to document: {}",
188 TextEdits.len(),
189 DocumentURI
190 );
191 }
192 },
193 }
194
195 // Apply a collection of document edits and file operations to the workspace.
196 // Parses the WorkspaceEditDTO and performs text edits on documents, creates
197 // and deletes files, and handles renames with proper validation. Key aspects:
198 // validate document URIs and workspace trust, apply text edits with coordinate
199 // conversion (line/column), handle all operations atomically with rollback on
200 // failure, emit before/after events for extension observability, and return
201 // false if any edit fails with detailed error information. This enables
202 // multi-file refactorings, code actions, and automated fixes.
203 warn!("[WorkspaceEditApplier] ApplyWorkspaceEdit is not fully implemented");
204
205 Ok(true)
206 }
207}