fyi_msg/
lib.rs

1/*!
2# FYI Msg
3
4[![docs.rs](https://img.shields.io/docsrs/fyi_msg.svg?style=flat-square&label=docs.rs)](https://docs.rs/fyi_msg/)
5<br>
6[![crates.io](https://img.shields.io/crates/v/fyi_msg.svg?style=flat-square&label=crates.io)](https://crates.io/crates/fyi_msg)
7[![ci](https://img.shields.io/github/actions/workflow/status/Blobfolio/fyi/ci.yaml?style=flat-square&label=ci)](https://github.com/Blobfolio/fyi/actions)
8[![deps.rs](https://deps.rs/repo/github/blobfolio/fyi/status.svg?style=flat-square&label=deps.rs)](https://deps.rs/repo/github/blobfolio/fyi)<br>
9[![license](https://img.shields.io/badge/license-wtfpl-ff1493?style=flat-square)](https://en.wikipedia.org/wiki/WTFPL)
10
11This crate contains the objects providing the heart of the [FYI command line application](https://github.com/blobfolio/fyi), namely [`Msg`], a simple struct for status-like messages that can be easily printed to `STDOUT` or `STDERR`.
12
13
14
15## Examples
16
17```
18use fyi_msg::{Msg, MsgKind};
19
20// One way.
21Msg::new(MsgKind::Success, "You did it!")
22    .with_newline(true)
23    .print();
24
25// Another equivalent way.
26Msg::success("You did it!").print();
27```
28
29For more usage examples, check out the `examples/msg` demo, which covers just about every common use case.
30
31
32
33## Macros
34
35| Macro | Equivalent |
36| ----- | ---------- |
37| `confirm!(…)` | `Msg::new(MsgKind::Confirm, "Some question…").prompt()` |
38
39
40
41## Optional Features
42
43| Feature | Description |
44| ------- | ----------- |
45| `fitted` | Enables [`Msg::fitted`] for obtaining a slice trimmed to a specific display width. |
46| `progress` | Enables [`Progless`], a thread-safe CLI progress bar displayer.
47| `timestamps` | Enables timestamp-related methods and flags like [`Msg::with_timestamp`]. |
48*/
49
50#![deny(unsafe_code)]
51
52#![deny(
53	clippy::allow_attributes_without_reason,
54	clippy::correctness,
55	unreachable_pub,
56)]
57
58#![warn(
59	clippy::complexity,
60	clippy::nursery,
61	clippy::pedantic,
62	clippy::perf,
63	clippy::style,
64
65	clippy::allow_attributes,
66	clippy::clone_on_ref_ptr,
67	clippy::create_dir,
68	clippy::filetype_is_file,
69	clippy::format_push_string,
70	clippy::get_unwrap,
71	clippy::impl_trait_in_params,
72	clippy::lossy_float_literal,
73	clippy::missing_assert_message,
74	clippy::missing_docs_in_private_items,
75	clippy::needless_raw_strings,
76	clippy::panic_in_result_fn,
77	clippy::pub_without_shorthand,
78	clippy::rest_pat_in_fully_bound_structs,
79	clippy::semicolon_inside_block,
80	clippy::str_to_string,
81	clippy::string_to_string,
82	clippy::todo,
83	clippy::undocumented_unsafe_blocks,
84	clippy::unneeded_field_pattern,
85	clippy::unseparated_literal_suffix,
86	clippy::unwrap_in_result,
87
88	macro_use_extern_crate,
89	missing_copy_implementations,
90	missing_docs,
91	non_ascii_idents,
92	trivial_casts,
93	trivial_numeric_casts,
94	unused_crate_dependencies,
95	unused_extern_crates,
96	unused_import_braces,
97)]
98
99#![expect(clippy::redundant_pub_crate, reason = "Unresolvable.")]
100
101#![cfg_attr(docsrs, feature(doc_cfg))]
102
103
104
105mod ansi;
106mod msg;
107#[cfg(feature = "fitted")]   mod fitted;
108#[cfg(feature = "progress")] mod progress;
109
110pub use ansi::AnsiColor;
111pub use msg::{
112	Msg,
113	kind::MsgKind,
114};
115
116#[cfg(feature = "fitted")]
117#[cfg_attr(docsrs, doc(cfg(feature = "fitted")))]
118pub use fitted::{
119	fit_to_width,
120	length_width,
121	width,
122};
123
124#[cfg(feature = "progress")]
125#[cfg_attr(docsrs, doc(cfg(feature = "progress")))]
126pub use progress::{
127	ba::BeforeAfter,
128	Progless,
129	error::ProglessError,
130};
131
132// Re-export.
133#[cfg_attr(docsrs, doc(cfg(feature = "signal-hook")))]
134#[cfg(feature = "signal-hook")] pub use signal_hook;
135
136#[cfg(test)] use brunch as _;
137#[cfg(test)] use rayon as _;
138
139#[macro_use]
140/// # Macros.
141mod macros {
142	#[macro_export(local_inner_macros)]
143	/// # Confirm.
144	///
145	/// This is a convenience macro for generating a confirmation message,
146	/// handling the prompting, and returning the response `bool`.
147	///
148	/// ## Example
149	///
150	/// ```no_run
151	/// use fyi_msg::{confirm, Msg, MsgKind};
152	///
153	/// // The manual way:
154	/// if Msg::new(MsgKind::Confirm, "Do you like chickens?").prompt() {
155	///     println!("That's great! They like you too!");
156	/// }
157	///
158	/// // The macro way:
159	/// if confirm!("Do you like chickens?") {
160	///     println!("That's great! They like you too!");
161	/// }
162	///
163	/// // If you want to default to yes, prefix thusly:
164	/// if confirm!(yes: "Do you like chickens?") {
165	///     println!("That's great! They like you too!");
166	/// }
167	///
168	/// // Indentation can be set with the macro too by appending a second
169	/// // argument:
170	/// if confirm!("Do you like chickens?", 1) {
171	///     println!("    That's great! They like you too!");
172	/// }
173	///
174	/// // The "yes:" prefix also works here.
175	/// if confirm!(yes: "Do you like chickens?", 1) {
176	///     println!("    That's great! They like you too!");
177	/// }
178	/// ```
179	macro_rules! confirm {
180		(yes: $text:expr) => (
181			$crate::Msg::new($crate::MsgKind::Confirm, $text).prompt_with_default(true)
182		);
183		(yes: $text:expr, $indent:expr) => (
184			$crate::Msg::new($crate::MsgKind::Confirm, $text)
185				.with_indent($indent)
186				.prompt_with_default(true)
187		);
188		(no: $text:expr) => (
189			$crate::Msg::new($crate::MsgKind::Confirm, $text).prompt()
190		);
191		(no: $text:expr, $indent:expr) => (
192			$crate::Msg::new($crate::MsgKind::Confirm, $text)
193				.with_indent($indent)
194				.prompt()
195		);
196		($text:expr) => (
197			$crate::Msg::new($crate::MsgKind::Confirm, $text).prompt()
198		);
199		($text:expr, $indent:expr) => (
200			$crate::Msg::new($crate::MsgKind::Confirm, $text)
201				.with_indent($indent)
202				.prompt()
203		);
204	}
205}