fyi_msg/lib.rs
1/*!
2# FYI Msg
3
4[](https://docs.rs/fyi_msg/)
5<br>
6[](https://crates.io/crates/fyi_msg)
7[](https://github.com/Blobfolio/fyi/actions)
8[](https://deps.rs/repo/github/blobfolio/fyi)<br>
9[](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}