use crate::{
input::{events::AppEvent, DefaultStdIn},
output::command::{TerminalCommander, TerminalRequest},
sys::{Control, DefaultControl},
Termit,
};
use std::io;
pub struct Terminal<C, I, O> {
pub control: C,
pub input: I,
pub output: O,
}
impl<'a, C, I, O> Terminal<C, I, O>
where
C: Control + 'a,
I: futures_lite::AsyncRead + 'a,
O: io::Write + 'a,
{
pub fn into_termit<A: AppEvent>(self) -> Termit<'a, A> {
Termit::from(self)
}
}
#[derive(Default, Copy, Clone)]
struct NoIo;
impl Default for Terminal<NoIo, NoIo, NoIo> {
fn default() -> Self {
Self {
control: Default::default(),
input: Default::default(),
output: Default::default(),
}
}
}
impl Terminal<DefaultControl, DefaultStdIn, io::Stdout> {
pub fn try_system_default() -> io::Result<Self> {
crate::sys::terminal()
}
}
impl<C, I, O> Terminal<C, I, O> {
pub fn new(control: C, input: I, output: O) -> Terminal<C, I, O> {
Terminal {
control,
input,
output,
}
}
}
impl<C, I, O> Terminal<C, I, O>
where
O: io::Write,
{
pub fn controlling<C2>(self, control: C2) -> Terminal<C2, I, O> {
let Self {
control: _,
input,
output,
} = self;
Terminal {
control,
input,
output,
}
}
pub fn reading<I2>(self, input: I2) -> Terminal<C, I2, O> {
let Self {
control,
input: _,
output,
} = self;
Terminal {
control,
input,
output,
}
}
pub fn writing<O2>(self, output: O2) -> Terminal<C, I, O2>
where
O2: io::Write,
{
let Self {
control,
input,
output: _,
} = self;
Terminal {
control,
input,
output,
}
}
}
impl<C, I, O> TerminalCommander for Terminal<C, I, O>
where
O: io::Write,
C: Control,
{
fn send<T: TerminalRequest>(&mut self, request: T) -> io::Result<()> {
let mut commander = (&self.control, &mut self.output);
commander.send(request)
}
}
impl io::Write for NoIo {
fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
Err(io::Error::new(io::ErrorKind::BrokenPipe, "no io"))
}
fn flush(&mut self) -> io::Result<()> {
Err(io::Error::new(io::ErrorKind::BrokenPipe, "no io"))
}
}
impl futures_lite::AsyncRead for NoIo {
fn poll_read(
self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
_buf: &mut [u8],
) -> std::task::Poll<io::Result<usize>> {
std::task::Poll::Ready(Err(io::Error::new(io::ErrorKind::BrokenPipe, "no io")))
}
}
impl Control for NoIo {
fn enable_raw_mode(&self) -> std::io::Result<()> {
Err(io::Error::new(io::ErrorKind::BrokenPipe, "no io"))
}
fn get_size(&self) -> std::io::Result<crate::prelude::Point> {
Err(io::Error::new(io::ErrorKind::BrokenPipe, "no io"))
}
fn is_tty(&self) -> bool {
false
}
fn is_raw(&self) -> bool {
false
}
fn is_ansi(&self) -> bool {
false
}
fn output(&self) -> &crate::sys::ControlOut {
panic!("no output")
}
fn input(&self) -> &crate::sys::ControlIn {
panic!("no input")
}
fn clone(&self) -> Self
where
Self: Sized,
{
NoIo
}
#[cfg(all(windows, feature = "sys"))]
fn get_initial_style(&self) -> u16 {
panic!("no input")
}
#[cfg(all(windows, feature = "sys"))]
fn use_alternate_screen(&self, _alternate: bool) -> std::io::Result<()> {
Err(io::Error::new(io::ErrorKind::BrokenPipe, "no io"))
}
}
#[test]
fn get_tty_exists() {
let _: io::Result<_> = crate::sys::get_tty();
}
#[test]
fn terminal_exists() {
let _: io::Result<Terminal<_, _, _>> = crate::sys::terminal();
}