#![cfg_attr(docsrs, feature(doc_auto_cfg))]
pub mod core;
pub use crate::core::{
Buffer,
Line,
Stream,
GetLine
};
mod data;
pub mod edit;
pub mod input;
pub use input::Input;
pub mod spin;
pub use spin::Spinner;
mod push;
pub use push::{
Inline,
Pushable,
Tag,
Wrap,
WrapBold
};
#[doc(hidden)]
pub use push::LambdaFmt;
pub mod print;
pub use print::{
Print,
List,
Tree
};
pub mod style;
pub use style::{
Paint,
Palette,
Color,
Tags
};
pub mod term;
use std::ops::DerefMut;
use crate::core::InitialContent;
use crate::edit::{
Editable,
Edited
};
use crate::input::Confirm;
use crate::style::TAGS;
pub trait Conciliator: for<'l> GetLine<'l> {
fn line<I: InitialContent>(&self, init: I) -> <Self as GetLine>::Line {
let mut line = self.get_line();
init.init_buffer(line.deref_mut());
line
}
fn status<I: InitialContent>(&self, init: I) -> <Self as GetLine>::Line {
let mut line = self.get_line();
line.tag(Color::Alpha, TAGS.status);
init.init_buffer(line.deref_mut());
line
}
fn info<I: InitialContent>(&self, init: I) -> <Self as GetLine>::Line {
let mut line = self.get_line();
line.tag(Color::Beta, TAGS.info);
init.init_buffer(line.deref_mut());
line
}
fn warn<I: InitialContent>(&self, init: I) -> <Self as GetLine>::Line {
let mut line = self.get_line();
line.tag(Color::Gamma, TAGS.warn);
init.init_buffer(line.deref_mut());
line
}
fn error<I: InitialContent>(&self, init: I) -> <Self as GetLine>::Line {
let mut line = self.get_line();
line.tag(Color::Delta, TAGS.error);
init.init_buffer(line.deref_mut());
line
}
fn print<T: Print>(&self, thing: T) {
thing.print(self);
}
}
pub struct Claw {
out: Stream,
err: Stream
}
pub fn init() -> Claw {
Claw {
out: Stream::stdout(None),
err: Stream::stderr(None)
}
}
impl Claw {
pub(crate) fn clone(&self) -> Self {
Self {
out: self.out.clone(),
err: self.err.clone()
}
}
pub fn stderr_line<I: InitialContent>(&self, init: I) -> Line<'_> {
let mut line = self.err.line();
init.init_buffer(&mut line);
line
}
pub fn stderr_print<T: Print>(&self, thing: T) {
thing.print(&self.err);
}
#[must_use]
pub fn confirm<Q, M>(&self, default: bool, question: Q) -> bool
where Confirm<Q, M>: Input<T = bool>
{
self.input(Confirm::new(default, question))
}
pub fn input<I: Input>(&self, mut request: I) -> I::T {
request.print(self);
let mut input_buf = String::new();
loop {
request.prompt(&mut self.line(..).no_newline());
std::io::stdin().read_line(&mut input_buf).unwrap();
if let Some(thing) = request.validate(input_buf.trim()) {
return thing
}
else {input_buf.clear();}
}
}
pub fn select<T: Inline>(
&self,
mut things: Vec<T>,
description: &str,
question: &str)
-> Option<T>
{
match things.len() {
0 => None,
1 => things.pop(),
_ => {
let list = List::indexed(things.iter()).with_count(description);
let select = input::Select::new(list, question);
let index = self.input(select);
Some(things.swap_remove(index))
}
}
}
pub fn edit<E: Editable>(&self, to_edit: E) -> Edited<E::E> {
edit::edit(self, to_edit.into_edit())
}
#[cfg_attr(
feature = "tokio",
doc = "# #[tokio::main] async fn main() {")
]
#[cfg_attr(feature = "tokio", doc = "# }")]
#[must_use = "Spinner spins until dropped"]
pub fn spin<I: InitialContent>(&mut self, message: I) -> Spinner {
Spinner::new(self, spin::CHASE, message)
}
#[cfg(feature = "tokio")]
pub async fn spin_while<I, F, T>(&mut self, message: I, future: F) -> T
where I: InitialContent,
F: std::future::Future<Output = T>
{
let sp = Spinner::new(self, spin::CHASE, message);
let thing = future.await;
sp.clear().await;
thing
}
}
impl<'l> GetLine<'l> for Claw {
type Line = Line<'l>;
fn get_line(&'l self) -> Self::Line {
self.out.line()
}
}
impl Conciliator for Claw {}