pub mod line;
pub mod scripted;
#[cfg(feature = "interactive")]
pub mod rich;
use rskit_errors::AppResult;
use super::key::Key;
pub use line::LineTerminal;
pub use scripted::ScriptedTerminal;
#[cfg(feature = "interactive")]
pub use rich::RichTerminal;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Capabilities {
keys: bool,
}
impl Default for Capabilities {
fn default() -> Self {
Self::line_driven()
}
}
impl Capabilities {
#[must_use]
pub const fn key_driven() -> Self {
Self { keys: true }
}
#[must_use]
pub const fn line_driven() -> Self {
Self { keys: false }
}
#[must_use]
pub const fn is_key_driven(self) -> bool {
self.keys
}
}
pub trait Terminal {
fn capabilities(&self) -> Capabilities;
fn read_line(&mut self) -> AppResult<Option<String>>;
fn read_key(&mut self) -> AppResult<Key>;
fn write(&mut self, text: &str) -> AppResult<()>;
fn write_line(&mut self, text: &str) -> AppResult<()>;
fn flush(&mut self) -> AppResult<()>;
fn clear_last_lines(&mut self, count: u16) -> AppResult<()>;
fn begin_interactive(&mut self) -> AppResult<()>;
fn end_interactive(&mut self) -> AppResult<()>;
}
impl Terminal for Box<dyn Terminal> {
fn capabilities(&self) -> Capabilities {
(**self).capabilities()
}
fn read_line(&mut self) -> AppResult<Option<String>> {
(**self).read_line()
}
fn read_key(&mut self) -> AppResult<Key> {
(**self).read_key()
}
fn write(&mut self, text: &str) -> AppResult<()> {
(**self).write(text)
}
fn write_line(&mut self, text: &str) -> AppResult<()> {
(**self).write_line(text)
}
fn flush(&mut self) -> AppResult<()> {
(**self).flush()
}
fn clear_last_lines(&mut self, count: u16) -> AppResult<()> {
(**self).clear_last_lines(count)
}
fn begin_interactive(&mut self) -> AppResult<()> {
(**self).begin_interactive()
}
fn end_interactive(&mut self) -> AppResult<()> {
(**self).end_interactive()
}
}
#[cfg(test)]
mod tests {
use super::{Capabilities, Terminal};
use crate::prompt::key::Key;
use crate::prompt::terminal::ScriptedTerminal;
#[test]
fn boxed_terminal_forwards_every_method_to_the_inner_terminal() {
let scripted = ScriptedTerminal::key_driven()
.with_line("typed")
.with_key(Key::Enter);
let mut boxed: Box<dyn Terminal> = Box::new(scripted);
assert_eq!(boxed.capabilities(), Capabilities::key_driven());
boxed.write("prompt").expect("write");
boxed.write_line("line").expect("write_line");
boxed.flush().expect("flush");
boxed.begin_interactive().expect("begin");
boxed.clear_last_lines(1).expect("clear");
assert_eq!(boxed.read_line().expect("line"), Some("typed".to_string()));
assert_eq!(boxed.read_key().expect("key"), Key::Enter);
boxed.end_interactive().expect("end");
}
}