libpt_cli/
printing.rs

1//! Utilities for formatting, bordering, aligning and printing text content
2//!
3//! This module provides functions for formatting content with borders and colors, printing them to the console.
4//! The functions in this module are designed to simplify the process of creating visually appealing
5//! output for CLI applications.
6//!
7//! Note that most of the utilities in this module are focused on communication with humans, not
8//! with machines. Consider evaluating [`std::io::IsTerminal`] before using colorful, dynamic and bordered
9//! printing. If you are talking to a machine, it might be useful to not add extra space, add a
10//! newline per output or even output JSON. An example that does this well is `ls`:
11//!
12//! ```bash
13//! $ ls
14//! Cargo.lock  Cargo.toml  data  LICENSE  members  README.md  scripts  src  target
15//! ```
16//!
17//! ```bash
18//! $ ls | cat
19//! Cargo.lock
20//! Cargo.toml
21//! data
22//! LICENSE
23//! members
24//! README.md
25//! scripts
26//! src
27//! target
28//! ```
29//!
30//! See the [CLI Rustbook](https://rust-cli.github.io/book/in-depth/machine-communication.html) for
31//! more information on the topic.
32
33use comfy_table::presets;
34use comfy_table::{CellAlignment, ContentArrangement, Table};
35use console::{style, Color};
36
37/// Prints content with a simple border around it
38///
39/// This function is a convenience wrapper around [blockfmt] and [println]. It automatically
40/// formats the content with a border using the specified color and then prints it to the console.
41///
42/// # Example
43///
44/// ```
45/// use console::Color;
46/// use libpt_cli::printing::blockprint;
47/// # fn main() {
48/// blockprint("Hello world!", Color::Blue);
49/// # }
50/// ```
51#[inline]
52#[allow(clippy::needless_pass_by_value)] // we just take an impl, using a &impl is much less ergonomic
53pub fn blockprint(content: impl ToString, color: Color) {
54    println!("{}", blockfmt(content, color));
55}
56
57/// Formats content with a simple border around it
58///
59/// This function is a convenience wrapper around [`blockfmt_advanced`] with preset values for
60/// border style, content arrangement, and cell alignment. It automatically formats the content
61/// with a border as large as possible and centers the content. The resulting cell is colored in
62/// the specified color.
63///
64/// # Example
65///
66/// ```
67/// use console::Color;
68/// use libpt_cli::printing::blockfmt;
69/// # fn main() {
70/// let formatted_content = blockfmt("Hello world!", Color::Blue);
71/// println!("{}", formatted_content);
72/// # }
73/// ```
74#[inline]
75#[allow(clippy::needless_pass_by_value)] // we just take an impl, using a &impl is much less ergonomic
76pub fn blockfmt(content: impl ToString, color: Color) -> String {
77    blockfmt_advanced(
78        content,
79        Some(color),
80        presets::UTF8_BORDERS_ONLY,
81        ContentArrangement::DynamicFullWidth,
82        CellAlignment::Center,
83    )
84}
85
86/// Formats content with a border around it
87///
88/// Unless you are looking for something specific, use [blockfmt] or [blockprint].
89///
90/// The border can be created using box-drawing characters, and the content is formatted
91/// within the border. The function allows customization of the border's color, preset,
92/// content arrangement, and cell alignment.
93///
94/// # Example
95/// ```
96/// use comfy_table::{presets, CellAlignment, ContentArrangement};
97/// use console::Color;
98/// use libpt_cli::printing::blockfmt_advanced;
99/// # fn main() {
100/// println!(
101///     "{}",
102///     blockfmt_advanced(
103///         "Hello world!",
104///         Some(Color::Blue),
105///         presets::UTF8_FULL,
106///         ContentArrangement::DynamicFullWidth,
107///         CellAlignment::Center
108///     )
109/// );
110/// # }
111/// ```
112/// ```text
113/// ┌────────────────────────────────────────────────────────────────────────────────────────┐
114/// │                                      Hello world!                                      │
115/// └────────────────────────────────────────────────────────────────────────────────────────┘
116/// ```
117///
118/// # Parameters
119///
120/// - `content`: The content to be formatted within the border
121/// - `color`: The color of the border and text
122/// - `preset`: The preset style for the border
123/// - `arrangement`: The arrangement of the the border (e.g., stretch to sides, wrap around )
124/// - `alignment`: The alignment of the content within the cells (e.g., left, center, right)
125#[allow(clippy::missing_panics_doc)] // we add a row then unwrap it, no panic should be possible
126#[allow(clippy::needless_pass_by_value)] // we just take an impl, using a &impl is much less ergonomic
127pub fn blockfmt_advanced(
128    content: impl ToString,
129    color: Option<Color>,
130    preset: &str,
131    arrangement: ContentArrangement,
132    alignment: CellAlignment,
133) -> String {
134    let mut table = Table::new();
135    table
136        .load_preset(preset)
137        .set_content_arrangement(arrangement)
138        .add_row(vec![content.to_string()]);
139    table.column_mut(0).unwrap().set_cell_alignment(alignment);
140
141    match color {
142        Some(c) => format!("{}", style(table).fg(c)),
143        None => table.to_string(),
144    }
145}