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 `AirService`
15//! - Workspace provider is one of the foundational services alongside Document,
16//! Configuration, and Diagnostic providers
17//! - Integrates with `ApplicationState` for persistent workspace folder storage
18//!
19//! ERROR HANDLING:
20//! - Uses [`CommonError`](CommonLibrary::Error::CommonError) for all operations
21//! - Application state lock errors are mapped using
22//! [`Utility::MapApplicationStateLockErrorToCommonError`]
23//! - Some operations are stubbed with logging (FindFilesInWorkspace, OpenFile,
24//! ApplyWorkspaceEdit)
25//!
26//! PERFORMANCE:
27//! - Workspace folder lookup uses O(n) linear search through folder list
28//! - Lock contention on `ApplicationState.Workspace.WorkspaceFolders` should be
29//! minimized
30//! - File discovery and workspace edit application are not yet optimized
31//!
32//! VS CODE REFERENCE:
33//! - `vs/workbench/services/workspace/browser/workspaceService.ts` - workspace
34//! service implementation
35//! - `vs/workbench/contrib/files/common/editors/textFileEditor.ts` - file
36//! editor integration
37//! - `vs/platform/workspace/common/workspace.ts` - workspace types and
38//! interfaces
39//!
40//! TODO:
41//! - Implement actual file search with glob pattern matching
42//! - Implement file opening with workspace-relative paths
43//! - Complete workspace edit application logic
44//! - Add workspace event propagation to subscribers
45//! - Implement custom editor routing by view type
46//!
47//! MODULE CONTENTS:
48//! - [`WorkspaceProvider`](CommonLibrary::Workspace::WorkspaceProvider)
49//! implementation:
50//! - `GetWorkspaceFoldersInfo` - enumerate all workspace folders
51//! - `GetWorkspaceFolderInfo` - find folder containing a URI
52//! - `GetWorkspaceName` - workspace identifier from state
53//! - `GetWorkspaceConfigurationPath` - .code-workspace path
54//! - `IsWorkspaceTrusted` - trust status check
55//! - `RequestWorkspaceTrust` - trust acquisition (stub)
56//! - `FindFilesInWorkspace` - file discovery (stub)
57//! - `OpenFile` - file opening (stub)
58//! - [`WorkspaceEditApplier`](CommonLibrary::Workspace::WorkspaceEditApplier)
59//! implementation:
60//! - `ApplyWorkspaceEdit` - edit application (stub)
61//! - Data types: [`(Url, String, usize)`] tuple for folder info (URI, name,
62//! index)
63
64use std::path::PathBuf;
65
66use CommonLibrary::{
67 DTO::WorkspaceEditDTO::WorkspaceEditDTO,
68 Error::CommonError::CommonError,
69 Workspace::{WorkspaceEditApplier::WorkspaceEditApplier, WorkspaceProvider::WorkspaceProvider},
70};
71use async_trait::async_trait;
72use serde_json::Value;
73use url::Url;
74
75use super::{MountainEnvironment::MountainEnvironment, Utility};
76use crate::dev_log;
77
78#[async_trait]
79impl WorkspaceProvider for MountainEnvironment {
80 /// Retrieves information about all currently open workspace folders.
81 async fn GetWorkspaceFoldersInfo(&self) -> Result<Vec<(Url, String, usize)>, CommonError> {
82 dev_log!("workspaces", "[WorkspaceProvider] Getting workspace folders info.");
83 let FoldersGuard = self
84 .ApplicationState
85 .Workspace
86 .WorkspaceFolders
87 .lock()
88 .map_err(Utility::MapApplicationStateLockErrorToCommonError)?;
89 Ok(FoldersGuard.iter().map(|f| (f.URI.clone(), f.Name.clone(), f.Index)).collect())
90 }
91
92 /// Retrieves information for the specific workspace folder that contains a
93 /// given URI.
94 async fn GetWorkspaceFolderInfo(&self, URIToMatch:Url) -> Result<Option<(Url, String, usize)>, CommonError> {
95 let FoldersGuard = self
96 .ApplicationState
97 .Workspace
98 .WorkspaceFolders
99 .lock()
100 .map_err(Utility::MapApplicationStateLockErrorToCommonError)?;
101 for Folder in FoldersGuard.iter() {
102 if URIToMatch.as_str().starts_with(Folder.URI.as_str()) {
103 return Ok(Some((Folder.URI.clone(), Folder.Name.clone(), Folder.Index)));
104 }
105 }
106
107 Ok(None)
108 }
109
110 /// Gets the name of the current workspace.
111 async fn GetWorkspaceName(&self) -> Result<Option<String>, CommonError> {
112 self.ApplicationState.GetWorkspaceIdentifier().map(Some)
113 }
114
115 /// Gets the path to the workspace configuration file (`.code-workspace`).
116 async fn GetWorkspaceConfigurationPath(&self) -> Result<Option<PathBuf>, CommonError> {
117 Ok(self
118 .ApplicationState
119 .Workspace
120 .WorkspaceConfigurationPath
121 .lock()
122 .map_err(Utility::MapApplicationStateLockErrorToCommonError)?
123 .clone())
124 }
125
126 /// Checks if the current workspace is trusted.
127 async fn IsWorkspaceTrusted(&self) -> Result<bool, CommonError> {
128 Ok(self
129 .ApplicationState
130 .Workspace
131 .IsTrusted
132 .load(std::sync::atomic::Ordering::Relaxed))
133 }
134
135 /// Requests workspace trust from the user.
136 async fn RequestWorkspaceTrust(&self, _Options:Option<Value>) -> Result<bool, CommonError> {
137 dev_log!(
138 "workspaces",
139 "warn: [WorkspaceProvider] RequestWorkspaceTrust is not implemented; defaulting to trusted."
140 );
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 dev_log!("workspaces", "[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 dev_log!("workspaces", "[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 dev_log!("workspaces", "[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 dev_log!(
187 "workspaces",
188 "[WorkspaceEditApplier] Would apply {} edits to document: {}",
189 TextEdits.len(),
190 DocumentURI
191 );
192 }
193 },
194 }
195
196 // Apply a collection of document edits and file operations to the workspace.
197 // Parses the WorkspaceEditDTO and performs text edits on documents, creates
198 // and deletes files, and handles renames with proper validation. Key aspects:
199 // validate document URIs and workspace trust, apply text edits with coordinate
200 // conversion (line/column), handle all operations atomically with rollback on
201 // failure, emit before/after events for extension observability, and return
202 // false if any edit fails with detailed error information. This enables
203 // multi-file refactorings, code actions, and automated fixes.
204 dev_log!(
205 "workspaces",
206 "warn: [WorkspaceEditApplier] ApplyWorkspaceEdit is not fully implemented"
207 );
208
209 Ok(true)
210 }
211}