use tracing::Instrument as _;
#[non_exhaustive]
pub struct ActiveTerminal {
pub task_handle: tokio::task::JoinHandle<()>,
pub surface_output_rx: tokio::sync::mpsc::Receiver<crate::output::native::Output>,
pub pty_input_tx: tokio::sync::mpsc::Sender<crate::pty::BytesFromSTDIN>,
pub control_tx: tokio::sync::broadcast::Sender<crate::Protocol>,
}
impl ActiveTerminal {
#[inline]
#[must_use]
pub fn start(config: crate::shadow_terminal::Config) -> Self {
tracing::debug!("Starting shadow terminal...");
let (pty_input_tx, pty_input_rx) = tokio::sync::mpsc::channel(1);
let (surface_output_tx, surface_output_rx) = tokio::sync::mpsc::channel(1);
let mut shadow_terminal =
crate::shadow_terminal::ShadowTerminal::new(config, surface_output_tx);
let control_tx = shadow_terminal.channels.control_tx.clone();
let current_span = tracing::Span::current();
let task_handle = tokio::spawn(async move {
shadow_terminal
.run(pty_input_rx)
.instrument(current_span)
.await;
});
tracing::debug!("Shadow terminal started.");
Self {
task_handle,
surface_output_rx,
pty_input_tx,
control_tx,
}
}
#[inline]
pub async fn send_input(
&self,
bytes: crate::pty::BytesFromSTDIN,
) -> Result<(), tokio::sync::mpsc::error::SendError<crate::pty::BytesFromSTDIN>> {
self.pty_input_tx.send(bytes).await
}
#[inline]
pub fn kill(&self) -> Result<usize, tokio::sync::broadcast::error::SendError<crate::Protocol>> {
tracing::debug!("`kill()` called on `ActiveTerminal`");
self.control_tx.send(crate::Protocol::End)
}
#[inline]
pub fn resize(
&self,
width: u16,
height: u16,
) -> Result<usize, tokio::sync::broadcast::error::SendError<crate::Protocol>> {
self.control_tx
.send(crate::Protocol::Resize { width, height })
}
#[inline]
pub fn scroll_up(
&self,
) -> Result<usize, tokio::sync::broadcast::error::SendError<crate::Protocol>> {
self.control_tx
.send(crate::Protocol::Scroll(crate::Scroll::Up))
}
#[inline]
pub fn scroll_down(
&self,
) -> Result<usize, tokio::sync::broadcast::error::SendError<crate::Protocol>> {
self.control_tx
.send(crate::Protocol::Scroll(crate::Scroll::Down))
}
#[inline]
pub fn scroll_cancel(
&self,
) -> Result<usize, tokio::sync::broadcast::error::SendError<crate::Protocol>> {
self.control_tx
.send(crate::Protocol::Scroll(crate::Scroll::Cancel))
}
}
impl Drop for ActiveTerminal {
#[inline]
fn drop(&mut self) {
let result = self.kill();
if let Err(error) = result {
tracing::debug!("`ActiveTerminal.drop()`: {error:?}");
}
}
}