Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions packages/copper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ default = []
full = [
"cli",
"coroutine-heavy",
"prompt-password",
"prompt",
"process",
"json",
"yaml",
Expand All @@ -78,7 +78,6 @@ full = [
print = ["dep:oneshot", "dep:regex", "dep:env_filter", "dep:terminal_size", "dep:unicode-width", "dep:ctrlc"]
cli = ["dep:clap", "print"]
prompt = ["print"]
prompt-password = ["prompt"]

# --- Coroutine ---
coroutine = [
Expand Down Expand Up @@ -121,8 +120,8 @@ derive = ["dep:derive_more"]
__test = []

[[example]]
name = "prompt_password"
required-features = ["prompt-password", "cli", "parse"]
name = "prompt"
required-features = ["prompt", "cli", "parse"]

[[example]]
name = "process"
Expand Down
8 changes: 0 additions & 8 deletions packages/copper/Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,10 @@ tasks:
vars:
PACKAGE: pistonite-cu
FEATURES: prompt
- task: cargo:clippy-package-feature
vars:
PACKAGE: pistonite-cu
FEATURES: prompt-password
- task: cargo:clippy-package-feature
vars:
PACKAGE: pistonite-cu
FEATURES: prompt,cli
- task: cargo:clippy-package-feature
vars:
PACKAGE: pistonite-cu
FEATURES: prompt-password,cli
- task: cargo:clippy-package-feature
vars:
PACKAGE: pistonite-cu
Expand Down
3 changes: 3 additions & 0 deletions packages/copper/examples/prompt.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
y
name
rust
121 changes: 121 additions & 0 deletions packages/copper/examples/prompt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
use pistonite_cu as cu;

use cu::pre::*;

// can only manually test this because password not prompted from stdin
#[cu::cli]
fn main(_: cu::cli::Flags) -> cu::Result<()> {
// test cases:
// n, # cancel
// ^C, # cancel
// y, # pass
if !cu::yesno!("do you want to continue?")? {
return Ok(());
}
cu::info!("user picked yes");

// test cases:
// ^C # cancel
// test ("hi, test")
// ("hi, ")
let name = cu::prompt!("please enter your name")?;
cu::info!("hi, {name}");

// test cases:
// ^C ("foobar")
// "" ("")
// "123" ("123")
let password = cu::prompt("please enter your password")
.password()
.if_cancel("foobar")
.run()?;
cu::info!("user entered: {password}");

// test cases
// "asdf" ("try again"), javascript # error
// ^C, # cancel
// "asdf", ^C # cancel
// "asdf", "asdf" ("try again"), "rust" # pass
let expected = "rust";
let answer = cu::prompt(format!(
"what's your favorite programming language? please answer {}",
expected
))
.validate_with(move |answer| {
if answer == expected {
return Ok(true);
}
if answer == "javascript" {
cu::bail!("that's not good");
}
cu::error!("try again");
Ok(false)
})
.run()?;
let answer = cu::check!(answer, "user cancelled")?;
cu::ensure!(*answer == expected)?;

// test cases
// "not number" # loop
// "-1" # loop
// "6" # loop
// "3" # pass
let mut index: i32 = 0;
cu::prompt("select a number between 0 and 5")
.or_cancel()
.validate_with(|answer| {
let number = match cu::parse::<i32>(answer) {
Err(e) => {
cu::error!("{e}");
cu::hint!("please ensure you are entering a number");
return Ok(false);
}
Ok(x) => x,
};
if number < 0 {
cu::error!("the number you entered is too small");
return Ok(false);
}
if number > 5 {
cu::error!("the number you entered is too big");
return Ok(false);
}
index = number;
Ok(true)
})
.run()?;
cu::info!("index is {index}");

// test cases
// "" # too short
// "asdfasdfasdfasdfasdf" # too long
// "foo foo foo" # illegal
// "123456" # error
// "helloworld" # pass
let password = cu::prompt(
"please enter a password between 8 and 16 charactres and only contains sensible characters",
)
.password()
.or_cancel()
.validate_with(|answer| {
if answer == "123456" {
cu::bail!("how can you do that, bye");
}
if answer.len() < 8 {
cu::error!("password is too short");
return Ok(false);
}
if answer.len() > 16 {
cu::error!("password is too long");
return Ok(false);
}
if let Err(e) = cu::password_chars_legal(answer) {
cu::error!("invalid password: {e}");
return Ok(false);
}
Ok(true)
})
.run()?;
cu::print!("{password}");
Ok(())
}
80 changes: 0 additions & 80 deletions packages/copper/examples/prompt_password.rs

This file was deleted.

3 changes: 2 additions & 1 deletion packages/copper/src/cli/ctrlc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ pub fn add_global_ctrlc_handler<F: FnMut() + Send + 'static>(handler: F) -> cu::
/// and easier to reason about program states when aborting.
///
/// If you prefer automatically cancellation, consider this pattern:
/// ```rust,ignore
#[cfg_attr(not(feature = "coroutine"), doc = "```rust,ignore")]
#[cfg_attr(feature = "coroutine", doc = "```rust,no_run")]
/// # use pistonite_cu as cu;
/// # async fn main_() -> cu::Result<()> {
/// let (send, mut recv) = tokio::sync::mpsc::unbounded_channel();
Expand Down
4 changes: 3 additions & 1 deletion packages/copper/src/cli/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,9 @@ fn handle_result(start: Instant, result: crate::Result<()>) -> std::process::Exi
}
}
if crate::lv::is_print_time_enabled() {
crate::info!("finished in {elapsed:.2}s");
// use debug so the error trace is the last line,
// so user is directed to see what is the most important
crate::debug!("finished in {elapsed:.2}s");
}
std::process::ExitCode::FAILURE
} else {
Expand Down
Loading