Skip to main content

Mountain/IPC/WindServiceHandlers/
Navigation.rs

1#![allow(non_snake_case, unused_variables, dead_code, unused_imports)]
2
3//! Navigation history and label handlers.
4
5use std::sync::Arc;
6
7use serde_json::{Value, json};
8
9use crate::{RunTime::ApplicationRunTime::ApplicationRunTime, dev_log};
10
11// ============================================================================
12// Navigation History Handlers
13// ============================================================================
14
15/// Navigate backward in the editor history stack.
16pub async fn HistoryGoBack(RunTime:Arc<ApplicationRunTime>) -> Result<Value, String> {
17	let Uri = RunTime.Environment.ApplicationState.Feature.NavigationHistory.GoBack();
18	Ok(Uri.map(Value::String).unwrap_or(Value::Null))
19}
20
21/// Navigate forward in the editor history stack.
22pub async fn HistoryGoForward(RunTime:Arc<ApplicationRunTime>) -> Result<Value, String> {
23	let Uri = RunTime.Environment.ApplicationState.Feature.NavigationHistory.GoForward();
24	Ok(Uri.map(Value::String).unwrap_or(Value::Null))
25}
26
27/// Return whether backward navigation is available.
28pub async fn HistoryCanGoBack(RunTime:Arc<ApplicationRunTime>) -> Result<Value, String> {
29	Ok(Value::Bool(
30		RunTime.Environment.ApplicationState.Feature.NavigationHistory.CanGoBack(),
31	))
32}
33
34/// Return whether forward navigation is available.
35pub async fn HistoryCanGoForward(RunTime:Arc<ApplicationRunTime>) -> Result<Value, String> {
36	Ok(Value::Bool(
37		RunTime.Environment.ApplicationState.Feature.NavigationHistory.CanGoForward(),
38	))
39}
40
41/// Push a URI onto the navigation history stack.
42pub async fn HistoryPush(RunTime:Arc<ApplicationRunTime>, Arguments:Vec<Value>) -> Result<Value, String> {
43	let Uri = Arguments
44		.first()
45		.and_then(|V| V.as_str())
46		.ok_or("history:push requires uri".to_string())?
47		.to_owned();
48
49	RunTime.Environment.ApplicationState.Feature.NavigationHistory.Push(Uri);
50	Ok(Value::Null)
51}
52
53/// Clear the entire navigation history stack.
54pub async fn HistoryClear(RunTime:Arc<ApplicationRunTime>) -> Result<Value, String> {
55	RunTime.Environment.ApplicationState.Feature.NavigationHistory.Clear();
56	Ok(Value::Null)
57}
58
59/// Return the full navigation history stack as an array of URI strings.
60pub async fn HistoryGetStack(RunTime:Arc<ApplicationRunTime>) -> Result<Value, String> {
61	let Stack = RunTime.Environment.ApplicationState.Feature.NavigationHistory.GetStack();
62	Ok(Value::Array(Stack.into_iter().map(Value::String).collect()))
63}
64
65// ============================================================================
66// Label Handlers
67// ============================================================================
68
69/// Resolve a human-readable display label for a URI.
70///
71/// Args: [uri: string, relative: bool]
72/// Returns: string label
73pub async fn LabelGetURI(RunTime:Arc<ApplicationRunTime>, Arguments:Vec<Value>) -> Result<Value, String> {
74	let Uri = Arguments
75		.first()
76		.and_then(|V| V.as_str())
77		.ok_or("label:getUri requires uri".to_string())?
78		.to_owned();
79
80	let Relative = Arguments.get(1).and_then(|V| V.as_bool()).unwrap_or(false);
81
82	if !Relative {
83		// Absolute: strip file:// scheme if present, return raw path
84		let Label = if Uri.starts_with("file://") {
85			Uri.trim_start_matches("file://").to_owned()
86		} else {
87			Uri.clone()
88		};
89		return Ok(Value::String(Label));
90	}
91
92	// Relative: make path relative to workspace root if possible
93	let WorkspaceRoot = RunTime
94		.Environment
95		.ApplicationState
96		.Workspace
97		.GetWorkspaceFolders()
98		.into_iter()
99		.next()
100		.map(|F| F.URI.to_string())
101		.unwrap_or_default();
102
103	let RawPath = if Uri.starts_with("file://") {
104		Uri.trim_start_matches("file://").to_owned()
105	} else {
106		Uri.clone()
107	};
108
109	let RootPath = if WorkspaceRoot.starts_with("file://") {
110		WorkspaceRoot.trim_start_matches("file://").to_owned()
111	} else {
112		WorkspaceRoot
113	};
114
115	let Label = if !RootPath.is_empty() && RawPath.starts_with(&RootPath) {
116		RawPath[RootPath.len()..].trim_start_matches('/').to_owned()
117	} else {
118		RawPath
119	};
120
121	Ok(Value::String(Label))
122}
123
124/// Return the display label for the current workspace root folder.
125pub async fn LabelGetWorkspace(RunTime:Arc<ApplicationRunTime>) -> Result<Value, String> {
126	let Label = RunTime
127		.Environment
128		.ApplicationState
129		.Workspace
130		.GetWorkspaceFolders()
131		.into_iter()
132		.next()
133		.map(|F| {
134			if !F.Name.is_empty() {
135				F.Name
136			} else {
137				F.URI
138					.path_segments()
139					.and_then(|mut S| S.next_back())
140					.map(|S| S.to_owned())
141					.unwrap_or_else(|| F.URI.to_string())
142			}
143		})
144		.unwrap_or_default();
145
146	Ok(Value::String(Label))
147}
148
149/// Return only the basename (filename + extension) of a URI.
150pub async fn LabelGetBase(Arguments:Vec<Value>) -> Result<Value, String> {
151	let Uri = Arguments
152		.first()
153		.and_then(|V| V.as_str())
154		.ok_or("label:getBase requires uri".to_string())?;
155
156	let Base = Uri.split('/').next_back().unwrap_or(Uri);
157	Ok(Value::String(Base.to_owned()))
158}