Skip to main content

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}