Skip to main content

pistonite_cu/cli/
mod.rs

1//! # Printting and Command Line Interface
2//!
3//! There are 4 feature flags related to CLI
4//! - `print`: This is the most minimal feature set. Using
5//!   features from this feature flag means you acknowledge your code
6//!   is being called from a program that uses `cu::cli` (i.e. the `cli` feature)
7//! - `cli`: Use this if your crate is the end binary (i.e. not a library).
8//!   This integrates and re-exports [`clap`](https://docs.rs/clap).
9//!   - This turns on `print` automatically
10//! - `prompt`: This implies `print` and will also enable the ability to show prompts in the terminal,
11//!   including password prompts (which hide the input when user types into the terminal).
12//!
13//! # Integration with `clap`
14//!
15//! When the `cli` feature is enabled, `clap` is re-exported from the prelude,
16//! so you can use `clap` as if it's a dependency, without actually adding
17//! it to your `Cargo.toml`
18//! ```rust,no_run
19//! # use pistonite_cu as cu;
20//! use cu::pre::*;
21//! use clap::Parser;
22//!
23//! #[derive(Parser)]
24//! struct MyCli {
25//!     /// Just an example flag
26//!     #[clap(short, long)]
27//!     hello: bool,
28//! }
29//! ```
30//!
31//! # Common Command Options
32//! The [`Flags`] struct implement `clap::Args` to provide common
33//! options that integrates with the rest of the crate:
34//! - `--verbose`/`-v` to increase verbose level.
35//! - `--quiet`/`-q` to decrease verbose level.
36//! - `--color` to set color mode
37//!
38//! The `prompt` feature enables these additional options:
39//! - `--yes`/`-y` to answer `y` to all yes/no prompts.
40//! - `--non-interactive`: Disallow prompts, prompts will fail with an error instead
41//!   - With `--yes --non-interactive`, yes/no prompts gets answered `yes` and other prompts are
42//!     blocked
43//! - `--interactive`: This is the default, and cancels the effect of one `--non-interactive`
44//!
45//! The [`cu::cli`](macro@crate::cli) macro generates a shim
46//! to parse the flags and pass it to your main function.
47//! It also handles the `Result` returned back. See the example
48//! below and more usage examples in the documentation for the macro.
49//! ```rust,no_run
50//! # use pistonite_cu as cu;
51//! use cu::pre::*;
52//! // clap will be part of the prelude
53//! // when the `cli` feature is enabled
54//!
55//! // Typically, you want to have a wrapper struct
56//! // so you can derive additional options with clap,
57//! // and provide a description via doc comments, like below
58//!
59//! // clap will parse the doc comment of the Args struct
60//! // as the help text
61//!
62//! /// My program
63//! ///
64//! /// This is my program, it is very good.
65//! #[derive(clap::Parser, Clone)]
66//! struct Args {
67//!     /// Input of the program
68//!     #[clap(short, long)]
69//!     input: String,
70//!     /// Output of the program
71//!     #[clap(short, long)]
72//!     output: Option<String>,
73//!     #[clap(flatten)]
74//!     inner: cu::cli::Flags,
75//! }
76//! // use the flags attribute to refer to the cu::cli::Flags field inside the Args struct
77//! #[cu::cli(flags = "inner")]
78//! fn main(args: Args) -> cu::Result<()> {
79//!     cu::info!("input is {}", args.input);
80//!     cu::info!("output is {:?}", args.output);
81//!     Ok(())
82//! }
83//! ```
84//!
85//! # Printing and Logging
86//! In addition to the logging macros re-exported from the [`log`](https://docs.rs/log)
87//! crate, `cu` provides `print` and `hint` macros:
88//! - `print`: like `info`, but has a higher importance
89//! - `hint`: like `print`, but specifically for hinting actions the user can take
90//!   (to resolve an error, for example).
91//!
92//! These 2 levels are not directly controlled by `log`,
93//! and can still print when logging is statically disabled.
94//!
95//! The following table shows what are printed for each level,
96//! |         | `-qq` | ` -q` | `   ` | ` -v` | `-vv` |
97//! |-|-      |-     |-       |-     |-      |
98//! | [`error!`](crate::error) | ❌ | ✅ | ✅ | ✅ | ✅ |
99//! | [`hint!`](crate::hint) | ❌ | ✅ | ✅ | ✅ | ✅ |
100//! | [`print!`](macro@crate::print) | ❌ | ✅ | ✅ | ✅ | ✅ |
101//! | [`warn!`](crate::warn)  | ❌ | ❌ | ✅ | ✅ | ✅ |
102//! | [`info!`](crate::info)  | ❌ | ❌ | ✅ | ✅ | ✅ |
103//! | [`debug!`](crate::debug) | ❌ | ❌ | ❌ | ✅ | ✅ |
104//! | [`trace!`](crate::trace) | ❌ | ❌ | ❌ | ❌ | ✅ |
105//!
106//! The `RUST_LOG` environment variable is also supported in the same
107//! way as in [`env_logger`](https://docs.rs/env_logger/latest/env_logger/#enabling-logging).
108//! When mixing `RUST_LOG` and verbosity flags, logging messages are filtered
109//! by `RUST_LOG`, and the verbosity would only apply to `print` and `hint`
110//!
111//! # Other
112//! When setting up test, you can use [`cu::cli::level`] to quickly inititialize logging
113//! without dealing with the details.
114//!
115//! [`cu::cli::set_thread_name`] can be used to add a prefix to all messages printed
116//! by the current thread.
117//!
118//! Messages that are too long and multi-line messages are automatically wrapped.
119//!
120//! # Manual Parsing CLI args
121//! [`cu::cli::try_parse`](crate::cli::try_parse)
122//! and [`cu::cli::print_help`](crate::cli::print_help) can be useful
123//! when you want to manually invoke a command parser. These
124//! respect the `--color` option passed to the program.
125//!
126//! # Ctrl-C Signals
127//! We wrap the [`ctrlc`](https://docs.rs/ctrlc) crate because it only allows
128//! for one global handler. See [Handling Ctrl-C](fn@crate::cli::ctrlc_frame)
129//!
130//! # Progress Bars
131//! See [Progress Bars](fn@crate::progress)
132//!
133//! # Prompting
134//! See [Prompting](fn@crate::prompt)
135//!
136#[cfg(feature = "cli")]
137mod flags;
138#[cfg(all(feature = "coroutine", feature = "cli"))]
139pub use flags::__co_run;
140#[cfg(feature = "cli")]
141pub use flags::{__run, Flags, print_help, reset_color, try_parse};
142
143mod print_init;
144pub use print_init::{DefaultLogConfig, LogConfig, init_options, level};
145mod macros;
146pub use macros::{__print_payload_with_level, __print_with_level};
147
148mod thread_name;
149use thread_name::THREAD_NAME;
150pub use thread_name::{reset_thread_name, set_thread_name};
151mod printer;
152pub use printer::{Target, animate_to, print_to};
153
154mod progress;
155pub use progress::{ProgressBar, ProgressBarBuilder, ProgressHandle, progress};
156
157#[cfg(feature = "prompt")]
158mod prompt;
159#[cfg(feature = "prompt")]
160pub use prompt::{PromptBuilder, prompt, yesno};
161#[cfg(feature = "prompt")]
162mod password;
163#[cfg(feature = "prompt")]
164mod prompter;
165#[cfg(feature = "prompt")]
166pub use password::password_chars_legal;
167
168mod ctrlc;
169#[cfg(feature = "cli")]
170pub use ctrlc::add_global_ctrlc_handler;
171pub use ctrlc::{CtrlcBuilder, CtrlcSignal, ctrlc_frame};
172
173/// Formatting utils
174pub(crate) mod fmt;
175
176// 50ms between each cycle
177const TICK_INTERVAL: std::time::Duration = std::time::Duration::from_millis(10);
178// 2B ticks * 10ms = 251 days.
179// overflown tick means ETA will be inaccurate (after 251 days)
180type Tick = u32;