|
@@ -1,12 +1,32 @@
|
|
|
+//! cliask is a crate to handle prompting the user for input in CLI applications that don't want
|
|
|
+//! a full TUI library such as [cursive](https://lib.rs/crates/cursive/) and want something simpler
|
|
|
+//! than [inquire](https://lib.rs/crates/inquire).
|
|
|
+
|
|
|
use std::io::Write;
|
|
|
use std::os::fd::AsFd;
|
|
|
use termion::{raw::IntoRawMode, input::TermRead};
|
|
|
|
|
|
+extern crate self as cliask;
|
|
|
+
|
|
|
+/// Derives [`ActionEnum`] for a given enum, automatically assigning keys based on uppercase
|
|
|
+/// characters in the enum variant names.
|
|
|
+///
|
|
|
+/// For example:
|
|
|
+/// ```
|
|
|
+/// #[derive(ActionEnum)]
|
|
|
+/// pub enum YesNoSkipAction {
|
|
|
+/// Yes, // key will be Y
|
|
|
+/// No, // key will be N
|
|
|
+/// Skip, // key will be S
|
|
|
+/// SkipAll, // key will be A, since S is used already
|
|
|
+/// }
|
|
|
+/// // prompt will be the choice (Y)es/(N)o/(S)kip/Skip(A)ll
|
|
|
+/// ```
|
|
|
pub use cliask_derive::ActionEnum;
|
|
|
|
|
|
+/// Represents errors encountered during prompting.
|
|
|
#[derive(Debug)]
|
|
|
pub enum AskError {
|
|
|
- EscapeRequest,
|
|
|
IOError(std::io::Error),
|
|
|
}
|
|
|
|
|
@@ -16,6 +36,7 @@ impl From<std::io::Error> for AskError {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/// Trait providing static information about action choices.
|
|
|
pub trait ActionEnum: 'static {
|
|
|
const LABELS: &'static [&'static str];
|
|
|
const KEYS: &'static [char];
|
|
@@ -25,6 +46,23 @@ pub trait ActionEnum: 'static {
|
|
|
fn action_index(&self) -> usize;
|
|
|
}
|
|
|
|
|
|
+/// A simple [`ActionEnum`] for asking yes/no questions.
|
|
|
+#[derive(ActionEnum)]
|
|
|
+pub enum YesNoAction {
|
|
|
+ Yes,
|
|
|
+ No,
|
|
|
+}
|
|
|
+
|
|
|
+impl From<YesNoAction> for bool {
|
|
|
+ fn from(value: YesNoAction) -> Self {
|
|
|
+ match value {
|
|
|
+ YesNoAction::Yes => true,
|
|
|
+ YesNoAction::No => false,
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// Prompt the user for an action from a static list.
|
|
|
pub struct ActionPrompt<AE: ActionEnum> {
|
|
|
default_action: Option<AE>,
|
|
|
}
|
|
@@ -117,16 +155,19 @@ impl<AE: ActionEnum> ActionPrompt<AE> {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ /// Run the prompt.
|
|
|
pub fn run(self) -> Result<AE, AskError> {
|
|
|
self.print_prompt()?;
|
|
|
self.wait_for_answer(false).map(Option::unwrap)
|
|
|
}
|
|
|
+ /// Run the prompt and allow cancellation via the escape key.
|
|
|
pub fn run_cancellable(self) -> Result<Option<AE>, AskError> {
|
|
|
self.print_prompt()?;
|
|
|
self.wait_for_answer(true)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/// Prompt the user for a selection from a dynamic list.
|
|
|
pub struct SelectPrompt<'l, T: std::fmt::Display> {
|
|
|
prompt: &'l str,
|
|
|
height: usize,
|
|
@@ -320,6 +361,7 @@ impl<'l, T: std::fmt::Display> SelectPrompt<'l, T> {
|
|
|
Ok(None)
|
|
|
}
|
|
|
|
|
|
+ /// Run the prompt.
|
|
|
pub fn run(mut self) -> Result<T, AskError> {
|
|
|
let mut stdout = std::io::stdout();
|
|
|
self.setup(&mut stdout)?;
|
|
@@ -329,6 +371,7 @@ impl<'l, T: std::fmt::Display> SelectPrompt<'l, T> {
|
|
|
r
|
|
|
}
|
|
|
|
|
|
+ /// Run the prompt and allow cancellation via the escape key.
|
|
|
pub fn run_cancellable(mut self) -> Result<Option<T>, AskError> {
|
|
|
let mut stdout = std::io::stdout();
|
|
|
self.setup(&mut stdout)?;
|