Skip to main content

DevelopmentNodeEnvironment_MicrosoftVSCodeDependency_22NodeVersion_Bundle_Clean_Debug_ElectronProfile_EsbuildCompiler_Mountain/IPC/WindServiceHandlers/Terminal/
SerializeTerminalState.rs

1//! Serialise all active terminals to the `ISerializedTerminalState[]` shape
2//! that VS Code's `ILocalPtyService.serializeTerminalProcesses` contract
3//! requires.
4//!
5//! VS Code calls this immediately before a window reload to snapshot running
6//! PTY state. The result is written to storage and later passed back via
7//! `localPty:reviveTerminalProcesses` so the workbench can restore the panel
8//! without the user losing their shell sessions.
9//!
10//! ## Output shape per terminal
11//! ```json
12//! {
13//!   "id": 1,
14//!   "shellLaunchConfig": { "name": "zsh", "executable": "/bin/zsh", "args": [] },
15//!   "processDetails":    { "cwd": "/...", "pid": 1234, "title": "zsh" },
16//!   "orphanQuestionReply": false,
17//!   "replayEvent":        { "events": [] },
18//!   "timestamp":          1716134400000
19//! }
20//! ```
21//!
22//! Runtime handles (`PTYMaster`, `PTYInputTransmitter`, task `JoinHandle`s)
23//! are `#[serde(skip)]` in `TerminalStateDTO` and are intentionally absent
24//! from the wire payload - only the configuration fields needed to respawn
25//! the shell are serialised.
26
27use std::sync::Arc;
28
29use serde_json::{Value, json};
30
31use crate::RunTime::ApplicationRunTime::ApplicationRunTime;
32
33pub async fn Fn(RunTime:Arc<ApplicationRunTime>) -> Result<Value, String> {
34	let Terminals = RunTime
35		.Environment
36		.ApplicationState
37		.Feature
38		.Terminals
39		.ActiveTerminals
40		.lock()
41		.map_err(|Error| format!("SerializeTerminalState: lock poisoned: {}", Error))?;
42
43	let NowMs = std::time::SystemTime::now()
44		.duration_since(std::time::UNIX_EPOCH)
45		.map(|D| D.as_millis() as u64)
46		.unwrap_or(0);
47
48	let Serialized:Vec<Value> = Terminals
49		.iter()
50		.filter_map(|(TerminalId, ArcState)| {
51			let State = ArcState.lock().ok()?;
52
53			let Cwd = State.GetWorkingDirectory();
54
55			let Pid = State.OSProcessIdentifier.unwrap_or(0) as u64;
56
57			Some(json!({
58				"id": TerminalId,
59				"shellLaunchConfig": {
60					"name":       State.Name,
61					"executable": State.ShellPath,
62					"args":       State.ShellArguments,
63					"cwd":        Cwd,
64				},
65				"processDetails": {
66					"cwd":   Cwd,
67					"pid":   Pid,
68					"title": State.Name,
69				},
70				// False means the orphan-question dialog was NOT shown;
71				// revived terminals start fresh without a stale prompt.
72				"orphanQuestionReply": false,
73				// Empty replay - the xterm buffer will be restored from the
74				// output replay buffer separately via `sky:replay-events`.
75				"replayEvent": { "events": [] },
76				"timestamp": NowMs,
77			}))
78		})
79		.collect();
80
81	Ok(Value::Array(Serialized))
82}