Skip to main content

Mountain/IPC/WindServiceHandlers/NativeHost/
PickFolder.rs

1//! Wire method: `nativeHost:pickFolderAndOpen`, `:pickFileAndOpen`,
2//! `:pickFileFolderAndOpen`, `:pickWorkspaceAndOpen`.
3//!
4//! Atom I1 (2026-04-21): before webview reload, mutate
5//! ApplicationState.Workspace and fire `$deltaWorkspaceFolders` to Cocoon so
6//! extensions see the folder arrive synchronously.
7
8use std::sync::Arc;
9
10use serde_json::Value;
11use tauri::{AppHandle, Manager};
12
13use crate::{
14	ApplicationState::{
15		DTO::WorkspaceFolderStateDTO::WorkspaceFolderStateDTO,
16		State::{
17			ApplicationState::ApplicationState,
18			WorkspaceState::WorkspaceDelta::UpdateWorkspaceFoldersAndBroadcast,
19		},
20	},
21	dev_log,
22};
23
24pub async fn Fn(ApplicationHandle:AppHandle, _Arguments:Vec<Value>) -> Result<Value, String> {
25	use std::path::PathBuf;
26
27	use tauri_plugin_dialog::DialogExt;
28
29	dev_log!("folder", "pickFolderAndOpen requested");
30
31	let Handle = ApplicationHandle.clone();
32
33	tokio::task::spawn_blocking(move || {
34		let FolderPath = Handle.dialog().file().blocking_pick_folder();
35
36		if let Some(Path) = FolderPath {
37			let PathStr = Path.to_string();
38
39			dev_log!("folder", "picked: {}", PathStr);
40
41			if let Some(State) = Handle.try_state::<Arc<ApplicationState>>() {
42				let PathBuf = PathBuf::from(&PathStr);
43
44				let Canonical = PathBuf.canonicalize().unwrap_or(PathBuf.clone());
45
46				if let Ok(Uri) = url::Url::from_directory_path(&Canonical) {
47					let Name = Canonical
48						.file_name()
49						.and_then(|N| N.to_str())
50						.map(str::to_string)
51						.unwrap_or_else(|| Canonical.display().to_string());
52
53					match WorkspaceFolderStateDTO::New(Uri, Name, 0) {
54						Ok(Dto) => {
55							dev_log!("folder", "pre-nav workspace-delta: broadcasting 1 folder to Cocoon");
56
57							UpdateWorkspaceFoldersAndBroadcast(&Handle, &State.Workspace, vec![Dto]);
58						},
59						Err(Error) => {
60							dev_log!(
61								"folder",
62								"warn: [pickFolderAndOpen] WorkspaceFolderStateDTO::New failed: {}",
63								Error
64							);
65						},
66					}
67				} else {
68					dev_log!(
69						"folder",
70						"warn: [pickFolderAndOpen] path → file URI conversion failed for {}",
71						PathStr
72					);
73				}
74			} else {
75				dev_log!(
76					"folder",
77					"warn: [pickFolderAndOpen] ApplicationState not managed by Tauri - delta skipped"
78				);
79			}
80
81			if let Some(Window) = Handle.get_webview_window("main") {
82				if let Ok(CurrentUrl) = Window.url() {
83					let Origin = CurrentUrl.origin().unicode_serialization();
84
85					let EncodedPath = url::form_urlencoded::Serializer::new(String::new())
86						.append_pair("folder", &PathStr)
87						.finish();
88
89					let NewUrl = format!("{}/?{}", Origin, EncodedPath);
90
91					dev_log!("folder", "navigating: {}", NewUrl);
92
93					let _ = Window.navigate(NewUrl.parse().unwrap());
94
95					dev_log!("folder", "post-nav Window.navigate() returned; webview reloading");
96				}
97			}
98		} else {
99			dev_log!("folder", "pickFolderAndOpen cancelled by user");
100		}
101	});
102
103	Ok(Value::Null)
104}