Skip to main content

Mountain/IPC/WindServiceHandlers/Model/
TextfileWrite.rs

1
2//! Write text to a file on disk. Counterpart to `TextfileRead`;
3//! does not touch the document registry. After a successful disk
4//! write, fires `$acceptModelSaved` to Cocoon so extensions
5//! receive `onDidSaveTextDocument` (T1.4).
6
7use std::sync::Arc;
8
9use serde_json::{Value, json};
10
11use crate::{RunTime::ApplicationRunTime::ApplicationRunTime, dev_log};
12
13pub async fn Fn(_runtime:Arc<ApplicationRunTime>, Arguments:Vec<Value>) -> Result<Value, String> {
14	let Path = Arguments
15		.first()
16		.and_then(|V| V.as_str())
17		.ok_or_else(|| "textFile:write requires path as first argument".to_string())?
18		.to_string();
19
20	let Content = Arguments.get(1).and_then(|V| V.as_str()).unwrap_or("").to_string();
21
22	tokio::fs::write(&Path, Content.as_bytes())
23		.await
24		.map_err(|Error| format!("textFile:write failed: {}", Error))?;
25
26	dev_log!("vfs", "textFile:write ok path={} bytes={}", Path, Content.len());
27
28	// T1.4 - notify Cocoon that the model on disk now matches the editor
29	// buffer, firing `onDidSaveTextDocument` for all subscribed extensions
30	// (format-on-save, organize-imports, save listeners, etc.).
31	// Fire-and-forget: the write is already complete; a Vine failure here
32	// must not cause the save IPC call to fail from the workbench's
33	// perspective.
34	let FileUri = format!("file://{}", Path);
35
36	tokio::spawn(async move {
37		if let Err(Error) = crate::Vine::Client::SendNotification::Fn(
38			"cocoon-main".to_string(),
39			"$acceptModelSaved".to_string(),
40			json!({ "uri": FileUri }),
41		)
42		.await
43		{
44			dev_log!("vfs", "warn: [TextfileWrite] $acceptModelSaved notify failed: {:?}", Error);
45		}
46	});
47
48	Ok(Value::Null)
49}