Skip to content

Commit

Permalink
Init project
Browse files Browse the repository at this point in the history
  • Loading branch information
NathanFlurry committed Jun 1, 2023
0 parents commit bd5dbc8
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/target
/Cargo.lock
13 changes: 13 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "rivet-term"
version = "0.1.0"
edition = "2021"
license = "MIT"

[dependencies]
console = "0.15"
derive_builder = "0.12"
tabled = "0.8"
term_size = "0.3"
thiserror = "1.0"
tokio = { version = "1.27", default-features = false, features = ["rt"] }
15 changes: 15 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
pub type Result<T> = std::result::Result<T, Error>;

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("io: {source}")]
Io {
#[from]
source: std::io::Error,
},
#[error("join: {source}")]
Join {
#[from]
source: tokio::task::JoinError,
},
}
17 changes: 17 additions & 0 deletions src/format.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use console::{style, StyledObject};
use tabled::{Table, Tabled};

pub fn table<T>(iter: impl IntoIterator<Item = T>)
where
T: Tabled,
{
let mut table = Table::new(iter).with(tabled::Style::rounded());
if let Some((w, _)) = term_size::dimensions() {
table = table.with(tabled::Width::wrap(w));
}
println!("{}", table);
}

pub fn link(msg: impl ToString) -> StyledObject<String> {
style(msg.to_string()).italic().underlined()
}
12 changes: 12 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Re-exports
pub use console;

// Modules
pub mod error;
pub mod format;
pub mod prompt;
pub mod status;

pub fn terminal() -> console::Term {
console::Term::stderr()
}
161 changes: 161 additions & 0 deletions src/prompt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
use std::str::FromStr;

use console::{style, Term};
use derive_builder::Builder;

use crate::{error::Result, status};

#[derive(Builder)]
#[builder(setter(into))]
pub struct Prompt {
message: String,
#[builder(setter(strip_option), default)]
context: Option<String>,
#[builder(setter(strip_option), default)]
docs: Option<String>,
#[builder(setter(strip_option), default)]
docs_url: Option<String>,
#[builder(setter(strip_option), default)]
default_value: Option<String>,
#[builder(default)]
indent: usize,
}

impl Prompt {
fn gen_indent(&self) -> String {
" ".repeat(self.indent)
}

fn print_header(&self) {
let i = self.gen_indent();

eprintln!();
eprint!("{i}");
if let Some(context) = &self.context {
eprint!("{} ", style(format!("[{context}]")).bold());
}
eprintln!("{}", style(&self.message).bold().blue());
if let Some(docs) = &self.docs {
eprintln!("{i} {}", style(&docs).italic());
}
if let Some(docs_url) = &self.docs_url {
eprintln!("{i} {}", style(&docs_url).italic().underlined().cyan());
}
if let Some(default_value) = &self.default_value {
eprintln!(
"{i} {} {}",
style("Defaults to").italic(),
style(&default_value).italic().bold()
);
}
}

async fn read_line(&self, term: &Term) -> Result<String> {
self.read_line_inner(term, false).await
}

async fn read_line_secure(&self, term: &Term) -> Result<String> {
self.read_line_inner(term, true).await
}

async fn read_line_inner(&self, term: &Term, secure: bool) -> Result<String> {
term.flush()?;

let input = if secure {
tokio::task::spawn_blocking({
let term = term.clone();
move || term.read_secure_line()
})
.await??
} else {
tokio::task::spawn_blocking({
let term = term.clone();
move || term.read_line()
})
.await??
};

let input_trimmed = input.trim();

if input_trimmed.is_empty() {
if let Some(default_value) = self.default_value.as_ref() {
return Ok(default_value.clone());
}
}

Ok(input_trimmed.to_string())
}

pub async fn bool(&self, term: &Term) -> Result<bool> {
let i = self.gen_indent();

self.print_header();

loop {
eprint!("{i} {}", style("[y/n] ").bold());
let input = self.read_line(term).await?;

match input.to_lowercase().as_str() {
"y" | "yes" | "t" | "true" => return Ok(true),
"n" | "no" | "f" | "false" => return Ok(false),
_ => {
status::error(format!("{i} Invalid bool"), "Must be y or n");
}
}
}
}

pub async fn parsed<T>(&self, term: &Term) -> Result<T>
where
T: FromStr,
{
let i = self.gen_indent();

self.print_header();

loop {
eprint!("{i} {} ", style(">").bold());
let input = self.read_line(term).await?;

if let Ok(parsed) = input.parse::<T>() {
return Ok(parsed);
} else {
status::error(format!("{i} Invalid input"), "");
}
}
}

pub async fn string(&self, term: &Term) -> Result<String> {
let i = self.gen_indent();

self.print_header();

loop {
eprint!("{i} {} ", style(">").bold());
let input = self.read_line(term).await?;

if !input.is_empty() {
return Ok(input);
} else {
status::error(format!("{i} Empty input"), "");
}
}
}

pub async fn string_secure(&self, term: &Term) -> Result<String> {
let i = self.gen_indent();

self.print_header();

loop {
eprint!("{i} {} ", style("[input hidden]").bold());
let input = self.read_line_secure(term).await?;

if !input.is_empty() {
return Ok(input);
} else {
status::error(format!("{i} Empty input"), "");
}
}
}
}
22 changes: 22 additions & 0 deletions src/status.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use console::style;
use std::fmt::Display;

pub fn info(msg: impl Display, data: impl Display) {
eprintln!("{} {}", style(msg).bold().blue(), data);
}

// pub fn progress(msg: impl Display, data: impl Display) {
// eprintln!("{} {}", style(msg).bold().green(), data);
// }

pub fn success(msg: impl Display, data: impl Display) {
eprintln!("{} {}", style(msg).bold().green(), data);
}

// pub fn warn(msg: impl Display, data: impl Display) {
// eprintln!("{} {}", style(msg).bold().yellow(), data);
// }

pub fn error(msg: impl Display, data: impl Display) {
eprintln!("{} {}", style(msg).bold().red(), data);
}

0 comments on commit bd5dbc8

Please sign in to comment.