Skip to main content

running_process_platform_internal/platform/
terminal.rs

1//! Terminal, PTY, console, input, and terminal-I/O primitives.
2
3use std::ffi::OsString;
4use std::io::{self, Read, Write};
5use std::path::Path;
6use std::sync::{Arc, Mutex};
7
8/// Caller-facing PTY dimensions.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub struct PtySize {
11    pub rows: u16,
12    pub cols: u16,
13    pub pixel_width: u16,
14    pub pixel_height: u16,
15}
16
17/// One chunk read from the host terminal input source.
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct PtyInputChunk {
20    pub data: Vec<u8>,
21    pub submit: bool,
22}
23
24/// Independently lockable writer used by the PTY session policy layer.
25pub type SharedPtyWriter = Arc<Mutex<Box<dyn Write + Send>>>;
26
27/// Opaque host control data for a PTY master.
28///
29/// Shared callers can carry this token without observing a native descriptor
30/// or process-group value.
31#[allow(dead_code)]
32#[derive(Debug, Clone, Copy, Default)]
33pub struct PtyMasterControlToken {
34    pub(crate) process_group_leader: Option<i32>,
35    pub(crate) raw_fd: Option<i32>,
36}
37
38/// Opaque host control data for a spawned PTY child.
39///
40/// Native process handles never appear in the facade signature.
41#[allow(dead_code)]
42#[derive(Debug, Clone, Copy, Default)]
43pub struct PtyChildControlToken {
44    pub(crate) raw_handle: Option<usize>,
45}
46
47/// Platform-neutral handle for the master side of a pseudo-terminal.
48pub trait PtyMaster: Send + 'static {
49    fn try_clone_reader(&mut self) -> io::Result<Box<dyn Read + Send>>;
50    fn take_writer(&mut self) -> io::Result<Box<dyn Write + Send>>;
51    fn resize(&self, size: PtySize) -> io::Result<()>;
52    fn get_size(&self) -> io::Result<PtySize>;
53
54    /// Return opaque host control data without exposing native descriptors.
55    fn control_token(&self) -> PtyMasterControlToken {
56        PtyMasterControlToken::default()
57    }
58}
59
60/// Platform-neutral handle for a child process running inside a PTY.
61pub trait PtyChild: Send + 'static {
62    fn pid(&self) -> u32;
63    fn try_wait(&mut self) -> io::Result<Option<u32>>;
64    fn wait(&mut self) -> io::Result<u32>;
65    fn kill(&mut self) -> io::Result<()>;
66
67    /// Return opaque host control data without exposing a native process handle.
68    fn control_token(&self) -> PtyChildControlToken {
69        PtyChildControlToken::default()
70    }
71}
72
73/// Platform-neutral handle for the slave side of a pseudo-terminal.
74pub trait PtySlave: Send + 'static {
75    type Child: PtyChild;
76
77    fn spawn(
78        self,
79        argv: &[OsString],
80        cwd: Option<&Path>,
81        env: Option<&[(OsString, OsString)]>,
82    ) -> io::Result<Self::Child>;
83}
84
85/// Factory trait implemented by the selected host PTY backend.
86pub trait PtyBackend {
87    type Master: PtyMaster;
88    type Slave: PtySlave;
89
90    fn openpty(size: PtySize) -> io::Result<(Self::Master, Self::Slave)>;
91}
92
93/// Raw replies returned by a bounded active terminal-graphics probe.
94#[derive(Debug, Clone, Default, PartialEq, Eq)]
95pub struct TerminalGraphicsProbe {
96    pub sixel_xtsmgraphics: Option<String>,
97    pub sixel_da1: Option<String>,
98    pub kitty_graphics: Option<String>,
99    pub iterm2_capabilities: Option<String>,
100}
101
102/// Probe the controlling terminal without exposing terminal descriptors.
103pub fn active_graphics_probe(timeout: std::time::Duration) -> TerminalGraphicsProbe {
104    crate::active_graphics_probe(timeout)
105}
106
107pub mod input {
108    pub use crate::terminal_input::*;
109}
110
111#[cfg(feature = "pty")]
112pub use crate::{
113    Backend, ChildProcessInfo, ConPtyBackendKind, OrphanConhostInfo, PtyProcessGuard,
114    PtySpawnContext, TerminalInputSession,
115};
116
117#[cfg(feature = "pty")]
118pub use crate::current_backend_kind;
119
120#[cfg(feature = "pty")]
121pub fn before_pty_spawn() -> PtySpawnContext {
122    crate::before_pty_spawn()
123}
124
125#[cfg(feature = "pty")]
126pub fn prepare_pty_child(
127    context: PtySpawnContext,
128    child: PtyChildControlToken,
129    nice: Option<i32>,
130) -> io::Result<PtyProcessGuard> {
131    crate::prepare_pty_child(context, child, nice)
132}
133
134#[cfg(feature = "pty")]
135pub fn input_payload(data: &[u8]) -> Vec<u8> {
136    crate::input_payload(data)
137}
138
139#[cfg(feature = "pty")]
140pub fn query_responses(data: &[u8]) -> Vec<Vec<u8>> {
141    crate::query_responses(data)
142}
143
144#[cfg(feature = "pty")]
145pub fn shell_argv(command: &str) -> Vec<String> {
146    crate::shell_argv(command)
147}
148
149#[cfg(feature = "pty")]
150pub fn wait_before_close_supported() -> bool {
151    crate::wait_before_pty_close_supported()
152}
153
154#[cfg(feature = "pty")]
155pub fn is_ignorable_process_control_error(error: &io::Error) -> bool {
156    crate::is_ignorable_process_control_error(error)
157}
158
159#[cfg(feature = "pty")]
160pub fn send_pty_interrupt(
161    target: PtyMasterControlToken,
162    writer: &SharedPtyWriter,
163) -> io::Result<bool> {
164    crate::send_pty_interrupt(target, writer)
165}
166
167#[cfg(feature = "pty")]
168pub fn kill_pty_process_group(target: PtyMasterControlToken) -> io::Result<()> {
169    crate::kill_pty_process_group(target)
170}
171
172#[cfg(feature = "pty")]
173pub fn terminate_pty_child(pid: u32) -> io::Result<bool> {
174    crate::terminate_pty_child(pid)
175}
176
177#[cfg(feature = "pty")]
178pub fn signal_pty_tree(pid: u32, force: bool) -> io::Result<bool> {
179    crate::signal_pty_tree(pid, force)
180}
181
182#[cfg(feature = "pty")]
183pub fn resize_pty(master: &dyn PtyMaster, size: PtySize) -> io::Result<()> {
184    crate::resize_pty(master, size)
185}
186
187#[cfg(feature = "pty")]
188pub fn preferred_pty_pid(master: &dyn PtyMaster, child: &dyn PtyChild) -> Option<u32> {
189    crate::preferred_pty_pid(master, child)
190}
191
192#[cfg(feature = "pty")]
193pub fn find_child_processes(parent_pid: u32) -> Vec<ChildProcessInfo> {
194    crate::find_child_processes(parent_pid)
195}
196
197#[cfg(feature = "pty")]
198pub fn find_orphan_conhosts() -> Vec<OrphanConhostInfo> {
199    crate::find_orphan_conhosts()
200}