use std::ffi::OsString;
use std::io::{self, Read, Write};
use std::path::Path;
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PtySize {
pub rows: u16,
pub cols: u16,
pub pixel_width: u16,
pub pixel_height: u16,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PtyInputChunk {
pub data: Vec<u8>,
pub submit: bool,
}
pub type SharedPtyWriter = Arc<Mutex<Box<dyn Write + Send>>>;
type PtyInterruptOperation = Box<dyn FnOnce(&SharedPtyWriter) -> io::Result<bool> + Send + 'static>;
pub struct PtyInterruptTarget(PtyInterruptOperation);
impl PtyInterruptTarget {
pub(crate) fn new(
send: impl FnOnce(&SharedPtyWriter) -> io::Result<bool> + Send + 'static,
) -> Self {
Self(Box::new(send))
}
pub fn send(self, writer: &SharedPtyWriter) -> io::Result<bool> {
(self.0)(writer)
}
}
pub trait PtyMaster: Send + 'static {
fn try_clone_reader(&mut self) -> io::Result<Box<dyn Read + Send>>;
fn take_writer(&mut self) -> io::Result<Box<dyn Write + Send>>;
fn resize(&self, size: PtySize) -> io::Result<()>;
fn get_size(&self) -> io::Result<PtySize>;
#[deprecated(note = "use facade PTY control operations; removal planned for 5.0")]
fn process_group_leader(&self) -> Option<i32> {
None
}
#[deprecated(note = "use facade PTY operations; removal planned for 5.0")]
fn as_raw_fd(&self) -> Option<i32> {
None
}
#[cfg(feature = "pty")]
fn interrupt_target(&self) -> io::Result<PtyInterruptTarget> {
Ok(PtyInterruptTarget::new(|writer| {
let mut writer = writer
.lock()
.map_err(|_| io::Error::other("pty writer mutex poisoned"))?;
writer.write_all(&[0x03])?;
writer.flush()?;
Ok(true)
}))
}
#[cfg(feature = "pty")]
fn kill_process_group(&self) -> io::Result<()> {
Ok(())
}
#[cfg(feature = "pty")]
fn preferred_pid(&self, child: &dyn PtyChild) -> Option<u32> {
Some(child.pid())
}
}
pub trait PtyChild: Send + 'static {
fn pid(&self) -> u32;
fn try_wait(&mut self) -> io::Result<Option<u32>>;
fn wait(&mut self) -> io::Result<u32>;
fn kill(&mut self) -> io::Result<()>;
#[deprecated(note = "use facade PTY operations; removal planned for 5.0")]
fn as_raw_handle(&self) -> Option<*mut std::ffi::c_void> {
None
}
#[cfg(feature = "pty")]
fn prepare_process(
&self,
context: PtySpawnContext,
nice: Option<i32>,
) -> io::Result<PtyProcessGuard> {
crate::prepare_unmanaged_pty_child(context, nice)
}
}
pub trait PtySlave: Send + 'static {
type Child: PtyChild;
fn spawn(
self,
argv: &[OsString],
cwd: Option<&Path>,
env: Option<&[(OsString, OsString)]>,
) -> io::Result<Self::Child>;
}
pub trait PtyBackend {
type Master: PtyMaster;
type Slave: PtySlave;
fn openpty(size: PtySize) -> io::Result<(Self::Master, Self::Slave)>;
}
#[cfg(feature = "terminal-graphics")]
pub use crate::platform::terminal_graphics::TerminalGraphicsProbe;
#[cfg(not(feature = "terminal-graphics"))]
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct TerminalGraphicsProbe {
pub sixel_xtsmgraphics: Option<String>,
pub sixel_da1: Option<String>,
pub kitty_graphics: Option<String>,
pub iterm2_capabilities: Option<String>,
}
pub mod input {
pub use crate::terminal_input::*;
}
#[cfg(feature = "pty")]
pub use crate::{
Backend, ChildProcessInfo, ConPtyBackendKind, OrphanConhostInfo, PtyProcessGuard,
PtySpawnContext, TerminalInputSession,
};
#[cfg(feature = "pty")]
pub use crate::current_backend_kind;
#[cfg(feature = "pty")]
pub fn before_pty_spawn() -> PtySpawnContext {
crate::before_pty_spawn()
}
#[cfg(feature = "pty")]
pub fn prepare_pty_child(
context: PtySpawnContext,
child: &dyn PtyChild,
nice: Option<i32>,
) -> io::Result<PtyProcessGuard> {
child.prepare_process(context, nice)
}
#[cfg(feature = "pty")]
pub fn input_payload(data: &[u8]) -> Vec<u8> {
crate::input_payload(data)
}
#[cfg(feature = "pty")]
pub fn query_responses(data: &[u8]) -> Vec<Vec<u8>> {
crate::query_responses(data)
}
#[cfg(feature = "pty")]
pub fn shell_argv(command: &str) -> Vec<String> {
crate::shell_argv(command)
}
#[cfg(feature = "pty")]
pub fn wait_before_close_supported() -> bool {
crate::wait_before_pty_close_supported()
}
#[cfg(feature = "pty")]
pub fn is_ignorable_process_control_error(error: &io::Error) -> bool {
crate::is_ignorable_process_control_error(error)
}
#[cfg(feature = "pty")]
pub fn send_pty_interrupt(
target: PtyInterruptTarget,
writer: &SharedPtyWriter,
) -> io::Result<bool> {
target.send(writer)
}
#[cfg(feature = "pty")]
pub fn kill_pty_process_group(master: &dyn PtyMaster) -> io::Result<()> {
master.kill_process_group()
}
#[cfg(feature = "pty")]
pub fn terminate_pty_child(pid: u32) -> io::Result<bool> {
crate::terminate_pty_child(pid)
}
#[cfg(feature = "pty")]
pub fn signal_pty_tree(pid: u32, force: bool) -> io::Result<bool> {
crate::signal_pty_tree(pid, force)
}
#[cfg(feature = "pty")]
pub fn resize_pty(master: &dyn PtyMaster, size: PtySize) -> io::Result<()> {
crate::resize_pty(master, size)
}
#[cfg(feature = "pty")]
pub fn preferred_pty_pid(master: &dyn PtyMaster, child: &dyn PtyChild) -> Option<u32> {
master.preferred_pid(child)
}
#[cfg(feature = "pty")]
pub fn find_child_processes(parent_pid: u32) -> Vec<ChildProcessInfo> {
crate::find_child_processes(parent_pid)
}
#[cfg(feature = "pty")]
pub fn find_orphan_conhosts() -> Vec<OrphanConhostInfo> {
crate::find_orphan_conhosts()
}