Skip to main content

Mountain/IPC/WindServiceHandler/
Model.rs

1#![allow(non_snake_case)]
2
3//! Model (Text Model Registry) domain handlers for Wind IPC.
4
5use std::sync::Arc;
6
7use serde_json::{Value, json};
8
9use crate::RunTime::ApplicationRunTime::ApplicationRunTime;
10
11/// Open a text model: read content from disk and register in DocumentState.
12/// Returns { uri, content, version, languageId }.
13pub async fn handle_model_open(Runtime:Arc<ApplicationRunTime>, Args:Vec<Value>) -> Result<Value, String> {
14	let Uri = Args
15		.first()
16		.and_then(|V| V.as_str())
17		.ok_or("model:open requires uri".to_string())?
18		.to_owned();
19
20	let FilePath = if Uri.starts_with("file://") {
21		Uri.trim_start_matches("file://").to_owned()
22	} else {
23		Uri.clone()
24	};
25
26	let Content = tokio::fs::read_to_string(&FilePath).await.unwrap_or_default();
27
28	let LanguageId = std::path::Path::new(&FilePath)
29		.extension()
30		.and_then(|E| E.to_str())
31		.map(|Ext| {
32			match Ext {
33				"rs" => "rust",
34				"ts" | "tsx" => "typescript",
35				"js" | "jsx" | "mjs" | "cjs" => "javascript",
36				"json" | "jsonc" => "json",
37				"toml" => "toml",
38				"yaml" | "yml" => "yaml",
39				"md" => "markdown",
40				"html" | "htm" => "html",
41				"css" | "scss" | "less" => "css",
42				"sh" | "bash" | "zsh" => "shellscript",
43				"py" => "python",
44				"go" => "go",
45				"c" | "h" => "c",
46				"cpp" | "cc" | "cxx" | "hpp" => "cpp",
47				_ => "plaintext",
48			}
49		})
50		.unwrap_or("plaintext")
51		.to_owned();
52
53	let Version = Runtime
54		.Environment
55		.ApplicationState
56		.Feature
57		.Documents
58		.Get(&Uri)
59		.map(|D| D.Version + 1)
60		.unwrap_or(1);
61
62	{
63		use crate::ApplicationState::DTO::DocumentStateDTO::DocumentStateDTO;
64
65		if let Ok(ParsedUri) = url::Url::parse(&Uri) {
66			let Lines:Vec<String> = Content.lines().map(|L| L.to_owned()).collect();
67			let Eol = if Content.contains("\r\n") { "\r\n" } else { "\n" }.to_owned();
68
69			let Document = DocumentStateDTO {
70				URI:ParsedUri,
71				LanguageIdentifier:LanguageId.clone(),
72				Version,
73				Lines,
74				EOL:Eol,
75				IsDirty:false,
76				Encoding:"utf-8".to_owned(),
77				VersionIdentifier:Version,
78			};
79
80			Runtime
81				.Environment
82				.ApplicationState
83				.Feature
84				.Documents
85				.AddOrUpdate(Uri.clone(), Document);
86		}
87	}
88
89	Ok(json!({
90		"uri": Uri,
91		"content": Content,
92		"version": Version,
93		"languageId": LanguageId,
94	}))
95}
96
97/// Close a text model and remove it from DocumentState.
98pub async fn handle_model_close(Runtime:Arc<ApplicationRunTime>, Args:Vec<Value>) -> Result<Value, String> {
99	let Uri = Args
100		.first()
101		.and_then(|V| V.as_str())
102		.ok_or("model:close requires uri".to_string())?;
103
104	Runtime.Environment.ApplicationState.Feature.Documents.Remove(Uri);
105	Ok(Value::Null)
106}
107
108/// Get the current snapshot of an open text model, or null if not open.
109pub async fn handle_model_get(Runtime:Arc<ApplicationRunTime>, Args:Vec<Value>) -> Result<Value, String> {
110	let Uri = Args
111		.first()
112		.and_then(|V| V.as_str())
113		.ok_or("model:get requires uri".to_string())?;
114
115	match Runtime.Environment.ApplicationState.Feature.Documents.Get(Uri) {
116		None => Ok(Value::Null),
117		Some(Document) => {
118			Ok(json!({
119				"uri": Uri,
120				"content": Document.Lines.join(&Document.EOL),
121				"version": Document.Version,
122				"languageId": Document.LanguageIdentifier,
123			}))
124		},
125	}
126}
127
128/// Return all currently open text models.
129pub async fn handle_model_get_all(Runtime:Arc<ApplicationRunTime>) -> Result<Value, String> {
130	let All = Runtime
131		.Environment
132		.ApplicationState
133		.Feature
134		.Documents
135		.GetAll()
136		.into_iter()
137		.map(|(Uri, Document)| {
138			json!({
139				"uri": Uri,
140				"content": Document.Lines.join(&Document.EOL),
141				"version": Document.Version,
142				"languageId": Document.LanguageIdentifier,
143			})
144		})
145		.collect::<Vec<_>>();
146
147	Ok(Value::Array(All))
148}
149
150/// Update the content of an open text model, incrementing its version.
151pub async fn handle_model_update_content(Runtime:Arc<ApplicationRunTime>, Args:Vec<Value>) -> Result<Value, String> {
152	let Uri = Args
153		.first()
154		.and_then(|V| V.as_str())
155		.ok_or("model:updateContent requires uri".to_string())?
156		.to_owned();
157
158	let NewContent = Args
159		.get(1)
160		.and_then(|V| V.as_str())
161		.ok_or("model:updateContent requires content".to_string())?
162		.to_owned();
163
164	let (NewVersion, LanguageId) = match Runtime.Environment.ApplicationState.Feature.Documents.Get(&Uri) {
165		None => return Err(format!("model:updateContent - model not open: {}", Uri)),
166		Some(mut Document) => {
167			Document.Version += 1;
168			Document.Lines = NewContent.lines().map(|L| L.to_owned()).collect();
169			Document.IsDirty = true;
170			let Version = Document.Version;
171			let LangId = Document.LanguageIdentifier.clone();
172			Runtime
173				.Environment
174				.ApplicationState
175				.Feature
176				.Documents
177				.AddOrUpdate(Uri.clone(), Document);
178			(Version, LangId)
179		},
180	};
181
182	Ok(json!({
183		"uri": Uri,
184		"content": NewContent,
185		"version": NewVersion,
186		"languageId": LanguageId,
187	}))
188}