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}