use std::io::{stdout, Write};
use crossterm::{cursor::MoveToColumn,
style::{Print, ResetColor, Stylize},
terminal::{Clear, ClearType}};
use futures_util::FutureExt as _;
use miette::IntoDiagnostic as _;
use r3bl_ansi_color::{is_fully_uninteractive_terminal,
is_stdin_piped,
is_stdout_piped,
StdinIsPipedResult,
StdoutIsPipedResult,
TTYResult};
use r3bl_core::{InputDevice, LineStateControlSignal, OutputDevice, SharedWriter};
use crate::{Readline, ReadlineEvent};
pub struct TerminalAsync {
pub readline: Readline,
pub shared_writer: SharedWriter,
}
impl TerminalAsync {
pub async fn try_new(prompt: &str) -> miette::Result<Option<TerminalAsync>> {
if let StdinIsPipedResult::StdinIsPiped = is_stdin_piped() {
return Ok(None);
}
if let StdoutIsPipedResult::StdoutIsPiped = is_stdout_piped() {
return Ok(None);
}
if let TTYResult::IsNotInteractive = is_fully_uninteractive_terminal() {
return Ok(None);
}
let output_device = OutputDevice::new_stdout();
let input_device = InputDevice::new_event_stream();
let (readline, stdout) =
Readline::new(prompt.to_owned(), output_device, input_device)
.into_diagnostic()?;
Ok(Some(TerminalAsync {
readline,
shared_writer: stdout,
}))
}
pub fn clone_shared_writer(&self) -> SharedWriter { self.shared_writer.clone() }
pub async fn get_readline_event(&mut self) -> miette::Result<ReadlineEvent> {
self.readline.readline().fuse().await.into_diagnostic()
}
pub async fn println<T>(&mut self, content: T)
where
T: std::fmt::Display,
{
let _ = writeln!(self.shared_writer, "{}", content);
}
pub async fn println_prefixed<T>(&mut self, content: T)
where
T: std::fmt::Display,
{
let _ = writeln!(
self.shared_writer,
"{} {}",
" > ".red().bold().on_dark_grey(),
content
);
}
pub async fn flush(&mut self) {
let _ = self
.shared_writer
.line_state_control_channel_sender
.send(LineStateControlSignal::Flush)
.await;
}
pub async fn pause(&mut self) {
let _ = self
.shared_writer
.line_state_control_channel_sender
.send(LineStateControlSignal::Pause)
.await;
}
pub async fn resume(&mut self) {
let _ = self
.shared_writer
.line_state_control_channel_sender
.send(LineStateControlSignal::Resume)
.await;
}
pub fn print_exit_message(message: &str) -> miette::Result<()> {
crossterm::queue!(
stdout(),
MoveToColumn(0),
ResetColor,
Clear(ClearType::CurrentLine),
Print(message),
Print("\n"),
)
.into_diagnostic()?;
Ok(())
}
}