Skip to main content

Mountain/Binary/Extension/
ScanPathConfigure.rs

1//! # Extension Scan Path Configure Module
2//!
3//! Configures extension scan paths from the executable directory.
4
5use std::path::PathBuf;
6
7use crate::{
8	ApplicationState::{ApplicationState, MapLockError},
9	dev_log,
10};
11
12/// Configures extension scan paths by resolving paths from the executable
13/// directory.
14///
15/// # Arguments
16///
17/// * `AppState` - The application state containing ExtensionScanPaths
18///
19/// # Returns
20///
21/// A `Result` indicating success or failure.
22///
23/// # Scan Path Configuration
24///
25/// This function adds the following default scan paths:
26/// - `../Resources/extensions` - Bundled extensions in app resources directory
27/// - `extensions` - Local extensions directory relative to executable
28///
29/// # Errors
30///
31/// Returns an error if ExtensionScanPaths mutex lock fails.
32pub fn ScanPathConfigure(AppState:&std::sync::Arc<ApplicationState>) -> Result<Vec<PathBuf>, String> {
33	dev_log!("extensions", "[Extensions] [ScanPaths] Locking ExtensionScanPaths...");
34
35	let mut ScanPathsGuard = AppState
36		.Extension
37		.Registry
38		.ExtensionScanPaths
39		.lock()
40		.map_err(MapLockError)
41		.map_err(|e| format!("Failed to lock ExtensionScanPaths: {}", e))?;
42
43	dev_log!("extensions", "[Extensions] [ScanPaths] Adding default scan paths...");
44
45	// Resolve paths from executable directory
46	if let Ok(ExecutableDirectory) = std::env::current_exe() {
47		if let Some(Parent) = ExecutableDirectory.parent() {
48			// Standard Tauri bundle path: ../Resources/extensions.
49			// When launched from a `.app`, Parent is `Contents/MacOS/` and
50			// this resolves to `Contents/Resources/extensions`.
51			let ResourcesPath = Parent.join("../Resources/extensions");
52			dev_log!("extensions", "[Extensions] [ScanPaths] + {}", ResourcesPath.display());
53			ScanPathsGuard.push(ResourcesPath);
54
55			// VS Code-style bundle layout: `.app/Contents/Resources/app/extensions`.
56			// Some tooling copies built-ins here; probe both conventions so a
57			// single bundle works regardless of which copy step placed them.
58			let ResourcesAppPath = Parent.join("../Resources/app/extensions");
59			dev_log!("extensions", "[Extensions] [ScanPaths] + {}", ResourcesAppPath.display());
60			ScanPathsGuard.push(ResourcesAppPath);
61
62			// Debug/dev path: Target/debug/extensions
63			let LocalPath = Parent.join("extensions");
64			dev_log!("extensions", "[Extensions] [ScanPaths] + {}", LocalPath.display());
65			ScanPathsGuard.push(LocalPath);
66
67			// Dev-only fallback paths: the monorepo layout
68			// (Element/Mountain/Target/debug/) is not present in shipped
69			// bundles. In production, the ../Resources/extensions path above
70			// is authoritative. Gate with cfg to keep release builds lean.
71			#[cfg(debug_assertions)]
72			{
73				// Sky Target path: where CopyVSCodeAssets copies built-in
74				// extensions during the build.
75				let SkyTargetPath = Parent.join("../../../Sky/Target/Static/Application/extensions");
76				if SkyTargetPath.exists() {
77					dev_log!(
78						"extensions",
79						"[Extensions] [ScanPaths] + {} (Sky Target, dev)",
80						SkyTargetPath.display()
81					);
82					ScanPathsGuard.push(SkyTargetPath);
83				}
84
85				// VS Code dependency path: built-in extensions from the VS
86				// Code source checkout — avoids requiring a copy step in dev.
87				let DependencyPath = Parent.join("../../../../Dependency/Microsoft/Dependency/Editor/extensions");
88				if DependencyPath.exists() {
89					dev_log!(
90						"extensions",
91						"[Extensions] [ScanPaths] + {} (VS Code Dependency, dev)",
92						DependencyPath.display()
93					);
94					ScanPathsGuard.push(DependencyPath);
95				}
96			}
97		}
98	}
99
100	// User-scope paths: always scanned, independent of whether the binary
101	// was launched from the repo, a `.app`, or a symlink on the Desktop.
102	// Mirrors VS Code's `~/.vscode-oss/extensions` convention.
103	if let Some(HomeDirectory) = dirs::home_dir() {
104		let UserExtensionPath = HomeDirectory.join(".land/extensions");
105		dev_log!(
106			"extensions",
107			"[Extensions] [ScanPaths] + {} (User)",
108			UserExtensionPath.display()
109		);
110		ScanPathsGuard.push(UserExtensionPath);
111	}
112
113	let ScanPaths = ScanPathsGuard.clone();
114
115	dev_log!("extensions", "[Extensions] [ScanPaths] Configured: {:?}", ScanPaths);
116
117	Ok(ScanPaths)
118}