#![warn(missing_docs)]
pub use crossterm;
use crossterm::event::{self, Event, KeyCode};
use crossterm::style::{PrintStyledContent, StyledContent, Stylize};
use crossterm::terminal::{disable_raw_mode, enable_raw_mode, is_raw_mode_enabled};
use crossterm::Command;
#[cfg(feature = "spin_sleep")]
use spin_sleep::sleep;
use std::fmt::{self, Display, Formatter};
use std::io::{stdout, Write as _};
#[cfg(not(feature = "spin_sleep"))]
use std::thread::sleep;
use std::time::Duration;
#[macro_export]
macro_rules! slide {
($($command:expr),* $(,)?) => {{
use $crate::crossterm::execute;
use $crate::crossterm::terminal::{Clear, ClearType};
use $crate::WaitForInteraction;
use std::io::stdout;
execute!(stdout(), Clear(ClearType::All), $($command,)* WaitForInteraction)
}}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TypewriterPrint<T: Display>(pub T, pub Duration);
impl<T: Display> Command for TypewriterPrint<T> {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
for char in self.0.to_string().chars() {
f.write_char(char)?;
stdout()
.flush()
.expect("standard output stream should flush");
if !is_raw_mode_enabled().expect("should check if raw mode is enabled") {
enable_raw_mode().expect("raw mode should enable");
}
sleep(self.1);
if is_raw_mode_enabled().expect("should check if raw mode is enabled") {
disable_raw_mode().expect("raw mode should disable");
}
}
Ok(())
}
#[cfg(windows)]
fn execute_winapi(&self) -> crossterm::Result<()> {
panic!("tried to execute Print command using WinAPI, use ANSI instead");
}
#[cfg(windows)]
fn is_ansi_code_supported(&self) -> bool {
true
}
}
impl<T: Display> Display for TypewriterPrint<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[derive(Debug, Clone, Copy)]
pub struct TypewriterPrintStyledContent<D: Display>(pub StyledContent<D>, pub Duration);
impl<D: Display> Command for TypewriterPrintStyledContent<D> {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
for char in self.0.to_string().chars() {
PrintStyledContent(char.stylize()).write_ansi(f)?;
stdout()
.flush()
.expect("standard output stream should flush");
if !is_raw_mode_enabled().expect("should check if raw mode is enabled") {
enable_raw_mode().expect("raw mode should enable");
}
sleep(self.1);
if is_raw_mode_enabled().expect("should check if raw mode is enabled") {
disable_raw_mode().expect("raw mode should disable");
}
}
Ok(())
}
#[cfg(windows)]
fn execute_winapi(&self) -> crossterm::Result<()> {
Ok(())
}
}
impl Display for TypewriterPrintStyledContent<String> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
PrintStyledContent(self.0.clone()).fmt(f)
}
}
impl Display for TypewriterPrintStyledContent<&'static str> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
PrintStyledContent(self.0.clone()).fmt(f)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WaitForInteraction;
impl Command for WaitForInteraction {
fn write_ansi(&self, _f: &mut impl fmt::Write) -> fmt::Result {
stdout()
.flush()
.expect("standard output stream should flush");
if !is_raw_mode_enabled().expect("should check if raw mode is enabled") {
enable_raw_mode().expect("raw mode should enable");
}
loop {
if let Event::Key(key) = event::read().expect("should read event") {
if let KeyCode::Enter | KeyCode::Right | KeyCode::Char(' ') = key.code {
break;
}
}
}
if is_raw_mode_enabled().expect("should check if raw mode is enabled") {
disable_raw_mode().expect("raw mode should disable");
}
Ok(())
}
#[cfg(windows)]
fn execute_winapi(&self) -> crossterm::Result<()> {
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WaitFor(pub Duration);
impl Command for WaitFor {
fn write_ansi(&self, _f: &mut impl fmt::Write) -> fmt::Result {
stdout()
.flush()
.expect("standard output stream should flush");
if !is_raw_mode_enabled().expect("should check if raw mode is enabled") {
enable_raw_mode().expect("raw mode should enable");
}
sleep(self.0);
if is_raw_mode_enabled().expect("should check if raw mode is enabled") {
disable_raw_mode().expect("raw mode should disable");
}
Ok(())
}
#[cfg(windows)]
fn execute_winapi(&self) -> crossterm::Result<()> {
Ok(())
}
}