Checkpoint
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "nye-console"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
colored = "3.1.1"
|
||||
dialoguer = "0.12.0"
|
||||
indicatif = { version = "0.18.6", features = ["tokio"] }
|
||||
@@ -0,0 +1,305 @@
|
||||
use std::fmt::Display;
|
||||
use std::time::Duration;
|
||||
|
||||
use colored::Colorize;
|
||||
use dialoguer::theme::Theme;
|
||||
use dialoguer::{Input, Select};
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
|
||||
/// Takes a result and logs it if it's an error.
|
||||
///
|
||||
/// Arguments:
|
||||
/// * `result` - The result.
|
||||
pub fn catch_err<T, E>(result: Result<T, E>)
|
||||
where
|
||||
E: Display,
|
||||
{
|
||||
if let Err(error) = result {
|
||||
err(error.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
/// Displays a spinner loading bar on the console.
|
||||
///
|
||||
/// Arguments:
|
||||
/// * `message` - The message to display with the spinner.
|
||||
///
|
||||
/// Returns:
|
||||
/// [`ProgressBar`] - The spinner bar already being displayed on the console.
|
||||
pub fn spinner(message: impl Into<String>) -> ProgressBar {
|
||||
let bar = ProgressBar::new_spinner()
|
||||
.with_message(message.into())
|
||||
.with_style(
|
||||
ProgressStyle::default_spinner()
|
||||
.tick_strings(&["[\\]", "[|]", "[/]", "[-]", "^w^"])
|
||||
.template("{spinner:.cyan} {msg}")
|
||||
.unwrap(),
|
||||
);
|
||||
bar.enable_steady_tick(Duration::from_millis(200));
|
||||
|
||||
bar
|
||||
}
|
||||
|
||||
/// Displays a bytes progress bar on the console.
|
||||
///
|
||||
/// Arguments:
|
||||
/// * `message` - The message to display with the progress bar.
|
||||
///
|
||||
/// Returns:
|
||||
/// [`ProgressBar`] - The progress bar with a ticking spinner.
|
||||
pub fn progress_bytes(message: impl Into<String>, total: u64) -> ProgressBar {
|
||||
let bar = ProgressBar::new(total)
|
||||
.with_message(message.into())
|
||||
.with_style(
|
||||
ProgressStyle::default_bar()
|
||||
.progress_chars("##")
|
||||
.tick_strings(&["[\\]", "[|]", "[/]", "[-]", "^w^"])
|
||||
.template(
|
||||
"{spinner:.cyan} {wide_msg} {bar:.cyan/black} {binary_bytes}/{binary_total_bytes}",
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
bar.enable_steady_tick(Duration::from_millis(200));
|
||||
|
||||
bar
|
||||
}
|
||||
|
||||
/// Displays a success log message.
|
||||
///
|
||||
/// Use this when finishing a task to indicate success.
|
||||
///
|
||||
/// Arguments:
|
||||
/// * `message` - The message to log.
|
||||
pub fn yay(message: impl Into<String>) {
|
||||
let prefix = "YAY".cyan();
|
||||
let message = message.into();
|
||||
|
||||
println!("{prefix} {message}");
|
||||
}
|
||||
|
||||
/// Displays an info log message.
|
||||
///
|
||||
/// Arguments:
|
||||
/// * `message` - The message to log.
|
||||
pub fn info(message: impl Into<String>) {
|
||||
let prefix = "III".blue();
|
||||
let message = message.into();
|
||||
|
||||
println!("{prefix} {message}");
|
||||
}
|
||||
|
||||
/// Displays a warning log message.
|
||||
///
|
||||
/// Arguments:
|
||||
/// * `message` - The message to log.
|
||||
pub fn warn(message: impl Into<String>) {
|
||||
let prefix = "WWW".yellow();
|
||||
let message = message.into();
|
||||
|
||||
println!("{prefix} {message}");
|
||||
}
|
||||
|
||||
/// Displays an error log message.
|
||||
///
|
||||
/// Arguments:
|
||||
/// * `message` - The message to log.
|
||||
pub fn err(message: impl Into<String>) {
|
||||
let prefix = "ERR".red();
|
||||
let message = message.into();
|
||||
|
||||
println!("{prefix} {message}");
|
||||
}
|
||||
|
||||
/// A theme for the dialoguer crate that is used to prompt the user for input and selection.
|
||||
struct InputTheme;
|
||||
|
||||
impl Theme for InputTheme {
|
||||
fn format_input_prompt(
|
||||
&self,
|
||||
f: &mut dyn std::fmt::Write,
|
||||
prompt: &str,
|
||||
_default: Option<&str>,
|
||||
) -> std::fmt::Result {
|
||||
let prefix = ">>>".purple();
|
||||
|
||||
write!(f, "{prefix} {prompt}")
|
||||
}
|
||||
|
||||
fn format_input_prompt_selection(
|
||||
&self,
|
||||
f: &mut dyn std::fmt::Write,
|
||||
prompt: &str,
|
||||
sel: &str,
|
||||
) -> std::fmt::Result {
|
||||
let prefix = ">>>".purple();
|
||||
|
||||
write!(f, "{prefix} {prompt}{sel}")
|
||||
}
|
||||
|
||||
fn format_select_prompt(&self, f: &mut dyn std::fmt::Write, prompt: &str) -> std::fmt::Result {
|
||||
let prefix = ">>>".purple();
|
||||
|
||||
write!(f, "{prefix} {prompt}")
|
||||
}
|
||||
|
||||
fn format_select_prompt_item(
|
||||
&self,
|
||||
f: &mut dyn std::fmt::Write,
|
||||
text: &str,
|
||||
active: bool,
|
||||
) -> std::fmt::Result {
|
||||
if active {
|
||||
write!(f, "{}", format!(" * {text}").purple())
|
||||
} else {
|
||||
write!(f, " {text}")
|
||||
}
|
||||
}
|
||||
|
||||
fn format_select_prompt_selection(
|
||||
&self,
|
||||
f: &mut dyn std::fmt::Write,
|
||||
prompt: &str,
|
||||
sel: &str,
|
||||
) -> std::fmt::Result {
|
||||
let prefix = ">>>".purple();
|
||||
|
||||
write!(f, "{prefix} {prompt}{}", sel.purple())
|
||||
}
|
||||
}
|
||||
|
||||
/// Prompts the user for input.
|
||||
///
|
||||
/// Arguments:
|
||||
/// * `prompt` - The message to prompt the user with.
|
||||
///
|
||||
/// Returns:
|
||||
/// * `Ok(String)` - The user's input.
|
||||
/// * `Err(Error)` - If the user cancelled the operation or if the user could not be prompted.
|
||||
pub fn input(prompt: impl Into<String>) -> Result<String, dialoguer::Error> {
|
||||
Input::with_theme(&InputTheme)
|
||||
.with_prompt(prompt)
|
||||
.interact_text()
|
||||
}
|
||||
|
||||
/// Prompts the user for input with a default value.
|
||||
///
|
||||
/// Arguments:
|
||||
/// * `prompt` - The message to prompt the user with.
|
||||
/// * `default` - The default value.
|
||||
///
|
||||
/// Returns:
|
||||
/// * `Ok(String)` - The user's input.
|
||||
/// * `Err(Error)` - If the user cancelled the operation or if the user could not be prompted.
|
||||
pub fn input_with_default(
|
||||
prompt: impl Into<String>,
|
||||
default: impl Into<String>,
|
||||
) -> Result<String, dialoguer::Error> {
|
||||
Input::with_theme(&InputTheme)
|
||||
.with_prompt(prompt)
|
||||
.default(default.into())
|
||||
.interact_text()
|
||||
}
|
||||
|
||||
/// Prompts the user to select an option.
|
||||
///
|
||||
/// Arguments:
|
||||
/// * `prompt` - The message to prompt the user with.
|
||||
/// * `options` - The options to give the user for selection.
|
||||
///
|
||||
/// Returns:
|
||||
/// * `Ok(usize)` - The index of the option selected by the user.
|
||||
/// * `Err(Error)` - If the user cancelled the operation or if the user could not be prompted.
|
||||
pub fn select(
|
||||
prompt: impl Into<String>,
|
||||
options: impl IntoIterator<Item = impl ToString>,
|
||||
) -> Result<usize, dialoguer::Error> {
|
||||
Select::with_theme(&InputTheme)
|
||||
.with_prompt(prompt)
|
||||
.items(options)
|
||||
.interact()
|
||||
}
|
||||
|
||||
/// Prompts the user to select an option with an option selected by default.
|
||||
///
|
||||
/// Arguments:
|
||||
/// * `prompt` - The message to prompt the user with.
|
||||
/// * `options` - The options to give the user for selection.
|
||||
/// * `default` - The index of the default option.
|
||||
///
|
||||
/// Returns:
|
||||
/// * `Ok(usize)` - The index of the option selected by the user.
|
||||
/// * `Err(Error)` - If the user cancelled the operation or if the user could not be prompted.
|
||||
pub fn select_with_default(
|
||||
prompt: impl Into<String>,
|
||||
options: impl IntoIterator<Item = impl ToString>,
|
||||
default: usize,
|
||||
) -> Result<usize, dialoguer::Error> {
|
||||
Select::with_theme(&InputTheme)
|
||||
.with_prompt(prompt)
|
||||
.items(options)
|
||||
.default(default)
|
||||
.interact()
|
||||
}
|
||||
|
||||
/// Prompts the user to select an option with an option selected by default, without reporting the
|
||||
/// selection.
|
||||
///
|
||||
/// Arguments:
|
||||
/// * `prompt` - The message to prompt the user with.
|
||||
/// * `options` - The options to give the user for selection.
|
||||
/// * `default` - The index of the default option.
|
||||
///
|
||||
/// Returns:
|
||||
/// * `Ok(usize)` - The index of the option selected by the user.
|
||||
/// * `Err(Error)` - If the user cancelled the operation or if the user could not be prompted.
|
||||
pub fn select_with_default_without_report(
|
||||
prompt: impl Into<String>,
|
||||
options: impl IntoIterator<Item = impl ToString>,
|
||||
default: usize,
|
||||
) -> Result<usize, dialoguer::Error> {
|
||||
Select::with_theme(&InputTheme)
|
||||
.with_prompt(prompt)
|
||||
.items(options)
|
||||
.default(default)
|
||||
.report(false)
|
||||
.interact()
|
||||
}
|
||||
|
||||
/// Formats items into a human-readable list.
|
||||
///
|
||||
/// For example,
|
||||
/// - `[1] => "1"`
|
||||
/// - `[1, 2] => "1 and 2"`
|
||||
/// - `[1, 2, 3] => "1, 2, and 3"`.
|
||||
/// - `[1, 2, 3, 4] => "1, 2, 3, and 4"`.
|
||||
///
|
||||
/// Arguments:
|
||||
/// * `items` - The items of the list.
|
||||
///
|
||||
/// Returns:
|
||||
/// [`String`] -> The formatted list.
|
||||
pub fn list<T>(items: &[T]) -> String
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
let mut string = String::new();
|
||||
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
let is_first = i == 0;
|
||||
let is_penultimate = i == items.len() - 2;
|
||||
let is_last = i == items.len() - 1;
|
||||
|
||||
match (is_first, is_penultimate, is_last) {
|
||||
(false, false, false) => string.push_str(&format!("{item}, ")),
|
||||
(false, false, true) => string.push_str(&item.to_string()),
|
||||
(false, true, false) => string.push_str(&format!("{item}, and ")),
|
||||
(false, true, true) => unreachable!(),
|
||||
(true, false, false) => string.push_str(&format!("{item}, ")),
|
||||
(true, false, true) => string.push_str(&item.to_string()),
|
||||
(true, true, false) => string.push_str(&format!("{item} and ")),
|
||||
(true, true, true) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
string
|
||||
}
|
||||
Reference in New Issue
Block a user