Skip to main content

DevelopmentNodeEnvironment_MicrosoftVSCodeDependency_22NodeVersion_Bundle_Clean_Debug_ElectronProfile_EsbuildCompiler_Mountain/IPC/WindServiceHandlers/Terminal/
SerializeTerminalState.rs

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