Skip to main content

cli_forge/
lib.rs

1//! # cli-forge
2//!
3//! A unified command-line framework where argument parsing and styled output
4//! speak one API. This release delivers the output layer every other piece — and
5//! every sibling crate in the cli collection — is built on: one styling system,
6//! reached three ways, over a single cross-platform terminal backend.
7//!
8//! ## The three styling paths
9//!
10//! Plain text is the common case and stays cheap — [`out`] and [`err`] do no
11//! parsing and no allocation for a string literal:
12//!
13//! ```
14//! use cli_forge::{out, err};
15//!
16//! out("building...");
17//! err("something went wrong");
18//! ```
19//!
20//! When you want color, opt into one of three paths that all render to the same
21//! bytes for the same intent:
22//!
23//! ```
24//! use cli_forge::{define_tag, out, parse, style, tag};
25//!
26//! // 1. The builder — chain methods, drop the result into `out`.
27//! out(style("done").green().bold());
28//!
29//! // 2. Inline tags — markup parsed only here, never in `out`.
30//! parse("<c=red><b>ERROR:</b></c> <c=#ff8800>disk almost full</c>");
31//!
32//! // 3. A named style — define once, reuse anywhere.
33//! define_tag("error", style("").red().bold());
34//! out(tag("error").render_with("build failed"));
35//! ```
36//!
37//! ## Colors and terminals
38//!
39//! Colors are the eight standard names, plus any 24-bit value via
40//! [`Style::hex`] / [`Style::rgb`] or a `<c=#rrggbb>` / `<c=r,g,b>` tag. The
41//! terminal's capability is detected once: on a true-color terminal the exact
42//! value is emitted; on a 256- or 16-color terminal it is downgraded to the
43//! nearest representable color; on a pipe, under `NO_COLOR`, or with the `color`
44//! feature off, styling is dropped and only text is written. The Windows console
45//! is handled behind the same API as Unix terminals.
46//!
47//! ## Commands
48//!
49//! Build a recursive [`Command`] tree, register commands into an [`App`] from
50//! anywhere, and let [`App::parse`] resolve the invocation, parse arguments, and
51//! run the selected command's handler:
52//!
53//! ```no_run
54//! use cli_forge::{App, Arg, Command, out};
55//!
56//! let mut app = App::new("forge");
57//! app.register(
58//!     Command::new("build")
59//!         .about("compile the project")
60//!         .arg(Arg::flag("release").short('r'))
61//!         .arg(Arg::option("jobs").short('j').default("1"))
62//!         .run(|m| out(format!("release={} jobs={}", m.flag("release"), m.value("jobs").unwrap_or("?")))),
63//! );
64//! let _ = app.parse();
65//! ```
66//!
67//! Malformed input never panics: [`App::parse`] prints a structured
68//! [`ParseError`] and exits, while [`App::try_parse_from`] returns it.
69//!
70//! ## Feature flags
71//!
72//! - **`std`** *(default)* — terminal detection, the stdout/stderr writers, and
73//!   the command layer.
74//! - **`color`** *(default)* — ANSI styled output. Disable for plain output; the
75//!   API stays complete and every styled value renders as its plain text.
76//! - **`auth`** — the authorization seam: `App::auth`, `AuthRequest`, and
77//!   enforcement of [`Command::requires_auth`].
78
79#![cfg_attr(not(feature = "std"), no_std)]
80#![cfg_attr(docsrs, feature(doc_cfg))]
81#![forbid(unsafe_code)]
82#![deny(missing_docs)]
83#![deny(unused_must_use)]
84#![deny(unused_results)]
85#![deny(clippy::unwrap_used)]
86#![deny(clippy::expect_used)]
87#![deny(clippy::todo)]
88#![deny(clippy::unimplemented)]
89#![deny(clippy::unreachable)]
90#![deny(clippy::print_stdout)]
91#![deny(clippy::print_stderr)]
92#![deny(clippy::dbg_macro)]
93
94#[cfg(feature = "std")]
95mod app;
96#[cfg(feature = "std")]
97mod arg;
98#[cfg(feature = "auth")]
99mod auth;
100#[cfg(feature = "std")]
101mod color;
102#[cfg(feature = "std")]
103mod command;
104#[cfg(feature = "std")]
105mod error;
106#[cfg(feature = "std")]
107mod help;
108#[cfg(feature = "std")]
109mod matches;
110#[cfg(feature = "std")]
111mod output;
112#[cfg(feature = "std")]
113mod parser;
114#[cfg(feature = "std")]
115mod registry;
116#[cfg(feature = "std")]
117mod style;
118#[cfg(feature = "std")]
119mod tags;
120#[cfg(feature = "std")]
121mod terminal;
122
123#[cfg(all(test, feature = "color"))]
124mod crosspath_tests;
125
126#[cfg(feature = "std")]
127pub use crate::app::App;
128#[cfg(feature = "std")]
129pub use crate::arg::Arg;
130#[cfg(feature = "auth")]
131pub use crate::auth::AuthRequest;
132#[cfg(feature = "std")]
133pub use crate::command::Command;
134#[cfg(feature = "std")]
135pub use crate::error::ParseError;
136#[cfg(feature = "std")]
137pub use crate::matches::Matches;
138#[cfg(feature = "std")]
139pub use crate::output::{err, out};
140#[cfg(feature = "std")]
141pub use crate::registry::{Tag, define_tag, tag};
142#[cfg(feature = "std")]
143pub use crate::style::{Style, style};
144#[cfg(feature = "std")]
145pub use crate::tags::parse;