osp_cli/core/output.rs
1//! Output-mode enums shared across config parsing, CLI flags, and the UI.
2//!
3//! These types exist so the rest of the crate can talk about rendering intent
4//! without passing around raw strings. They define the stable vocabulary for
5//! format, richness, color, and unicode behavior.
6//!
7//! Contract:
8//!
9//! - these enums should stay small and broadly reusable
10//! - parsing here should accept the user-facing spellings supported by config
11//! and CLI flags
12//! - higher-level modules may interpret `Auto`, but the canonical labels live
13//! here
14
15/// Supported output formats for rendered command results.
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum OutputFormat {
18 /// Chooses a format based on the command result and terminal context.
19 Auto,
20 /// Renders guidance-oriented documents.
21 Guide,
22 /// Emits JSON output.
23 Json,
24 /// Renders tabular output.
25 Table,
26 /// Renders Markdown tables or documents.
27 Markdown,
28 /// Renders the legacy mreg text format.
29 Mreg,
30 /// Emits a scalar or compact value view.
31 Value,
32}
33
34impl OutputFormat {
35 /// Returns the canonical config and CLI spelling for this format.
36 ///
37 /// # Examples
38 ///
39 /// ```
40 /// use osp_cli::core::output::OutputFormat;
41 ///
42 /// assert_eq!(OutputFormat::Markdown.as_str(), "md");
43 /// assert_eq!(OutputFormat::Json.as_str(), "json");
44 /// ```
45 pub fn as_str(self) -> &'static str {
46 match self {
47 OutputFormat::Auto => "auto",
48 OutputFormat::Guide => "guide",
49 OutputFormat::Json => "json",
50 OutputFormat::Table => "table",
51 OutputFormat::Markdown => "md",
52 OutputFormat::Mreg => "mreg",
53 OutputFormat::Value => "value",
54 }
55 }
56
57 /// Parses the user-facing output format spellings accepted by config and
58 /// CLI flags.
59 ///
60 /// # Examples
61 ///
62 /// ```
63 /// use osp_cli::core::output::OutputFormat;
64 ///
65 /// assert_eq!(OutputFormat::parse("guide"), Some(OutputFormat::Guide));
66 /// assert_eq!(OutputFormat::parse(" markdown "), Some(OutputFormat::Markdown));
67 /// assert_eq!(OutputFormat::parse("MD"), Some(OutputFormat::Markdown));
68 /// assert_eq!(OutputFormat::parse("wat"), None);
69 /// ```
70 pub fn parse(value: &str) -> Option<Self> {
71 match value.trim().to_ascii_lowercase().as_str() {
72 "auto" => Some(OutputFormat::Auto),
73 "guide" => Some(OutputFormat::Guide),
74 "json" => Some(OutputFormat::Json),
75 "table" => Some(OutputFormat::Table),
76 "md" | "markdown" => Some(OutputFormat::Markdown),
77 "mreg" => Some(OutputFormat::Mreg),
78 "value" => Some(OutputFormat::Value),
79 _ => None,
80 }
81 }
82}
83
84/// Rendering mode preference for terminal output.
85#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub enum RenderMode {
87 /// Chooses plain or rich rendering automatically.
88 Auto,
89 /// Forces plain rendering.
90 Plain,
91 /// Forces rich rendering.
92 Rich,
93}
94
95impl RenderMode {
96 /// Returns the canonical config and CLI spelling for this render mode.
97 ///
98 /// # Examples
99 ///
100 /// ```
101 /// use osp_cli::core::output::RenderMode;
102 ///
103 /// assert_eq!(RenderMode::Rich.as_str(), "rich");
104 /// ```
105 pub fn as_str(self) -> &'static str {
106 match self {
107 RenderMode::Auto => "auto",
108 RenderMode::Plain => "plain",
109 RenderMode::Rich => "rich",
110 }
111 }
112
113 /// Parses the render-mode spellings accepted by config and CLI flags.
114 ///
115 /// # Examples
116 ///
117 /// ```
118 /// use osp_cli::core::output::RenderMode;
119 ///
120 /// assert_eq!(RenderMode::parse("RICH"), Some(RenderMode::Rich));
121 /// assert_eq!(RenderMode::parse(" plain "), Some(RenderMode::Plain));
122 /// assert_eq!(RenderMode::parse("wat"), None);
123 /// ```
124 pub fn parse(value: &str) -> Option<Self> {
125 match value.trim().to_ascii_lowercase().as_str() {
126 "auto" => Some(RenderMode::Auto),
127 "plain" => Some(RenderMode::Plain),
128 "rich" => Some(RenderMode::Rich),
129 _ => None,
130 }
131 }
132}
133
134/// Color handling policy for rendered output.
135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
136pub enum ColorMode {
137 /// Chooses color usage from terminal capabilities.
138 Auto,
139 /// Always emits color sequences.
140 Always,
141 /// Never emits color sequences.
142 Never,
143}
144
145impl ColorMode {
146 /// Returns the canonical config and CLI spelling for this color mode.
147 ///
148 /// # Examples
149 ///
150 /// ```
151 /// use osp_cli::core::output::ColorMode;
152 ///
153 /// assert_eq!(ColorMode::Always.as_str(), "always");
154 /// ```
155 pub fn as_str(self) -> &'static str {
156 match self {
157 ColorMode::Auto => "auto",
158 ColorMode::Always => "always",
159 ColorMode::Never => "never",
160 }
161 }
162
163 /// Parses the color-mode spellings accepted by config and CLI flags.
164 ///
165 /// # Examples
166 ///
167 /// ```
168 /// use osp_cli::core::output::ColorMode;
169 ///
170 /// assert_eq!(ColorMode::parse("never"), Some(ColorMode::Never));
171 /// assert_eq!(ColorMode::parse(" AUTO "), Some(ColorMode::Auto));
172 /// assert_eq!(ColorMode::parse("wat"), None);
173 /// ```
174 pub fn parse(value: &str) -> Option<Self> {
175 match value.trim().to_ascii_lowercase().as_str() {
176 "auto" => Some(ColorMode::Auto),
177 "always" => Some(ColorMode::Always),
178 "never" => Some(ColorMode::Never),
179 _ => None,
180 }
181 }
182}
183
184/// Unicode handling policy for rendered output.
185#[derive(Debug, Clone, Copy, PartialEq, Eq)]
186pub enum UnicodeMode {
187 /// Chooses Unicode usage from terminal capabilities.
188 Auto,
189 /// Always emits Unicode output.
190 Always,
191 /// Never emits Unicode output.
192 Never,
193}
194
195impl UnicodeMode {
196 /// Returns the canonical config and CLI spelling for this unicode mode.
197 ///
198 /// # Examples
199 ///
200 /// ```
201 /// use osp_cli::core::output::UnicodeMode;
202 ///
203 /// assert_eq!(UnicodeMode::Never.as_str(), "never");
204 /// ```
205 pub fn as_str(self) -> &'static str {
206 match self {
207 UnicodeMode::Auto => "auto",
208 UnicodeMode::Always => "always",
209 UnicodeMode::Never => "never",
210 }
211 }
212
213 /// Parses the unicode-mode spellings accepted by config and CLI flags.
214 ///
215 /// # Examples
216 ///
217 /// ```
218 /// use osp_cli::core::output::UnicodeMode;
219 ///
220 /// assert_eq!(UnicodeMode::parse("always"), Some(UnicodeMode::Always));
221 /// assert_eq!(UnicodeMode::parse(" Auto "), Some(UnicodeMode::Auto));
222 /// assert_eq!(UnicodeMode::parse("wat"), None);
223 /// ```
224 pub fn parse(value: &str) -> Option<Self> {
225 match value.trim().to_ascii_lowercase().as_str() {
226 "auto" => Some(UnicodeMode::Auto),
227 "always" => Some(UnicodeMode::Always),
228 "never" => Some(UnicodeMode::Never),
229 _ => None,
230 }
231 }
232}
233
234#[cfg(test)]
235mod tests {
236 use super::{ColorMode, OutputFormat, RenderMode, UnicodeMode};
237
238 #[test]
239 fn output_modes_round_trip_known_values_aliases_and_variants_unit() {
240 assert_eq!(OutputFormat::Auto.as_str(), "auto");
241 assert_eq!(OutputFormat::Guide.as_str(), "guide");
242 assert_eq!(OutputFormat::Json.as_str(), "json");
243 assert_eq!(OutputFormat::Table.as_str(), "table");
244 assert_eq!(OutputFormat::Markdown.as_str(), "md");
245 assert_eq!(OutputFormat::Mreg.as_str(), "mreg");
246 assert_eq!(OutputFormat::Value.as_str(), "value");
247 assert_eq!(OutputFormat::parse("guide"), Some(OutputFormat::Guide));
248 assert_eq!(OutputFormat::parse(" json "), Some(OutputFormat::Json));
249 assert_eq!(OutputFormat::parse("auto"), Some(OutputFormat::Auto));
250 assert_eq!(
251 OutputFormat::parse("markdown"),
252 Some(OutputFormat::Markdown)
253 );
254 assert_eq!(OutputFormat::parse("md"), Some(OutputFormat::Markdown));
255 assert_eq!(OutputFormat::parse("mreg"), Some(OutputFormat::Mreg));
256 assert_eq!(OutputFormat::parse(" value "), Some(OutputFormat::Value));
257 assert_eq!(OutputFormat::parse("wat"), None);
258
259 assert_eq!(RenderMode::Auto.as_str(), "auto");
260 assert_eq!(RenderMode::Plain.as_str(), "plain");
261 assert_eq!(RenderMode::Rich.as_str(), "rich");
262 assert_eq!(RenderMode::parse("plain"), Some(RenderMode::Plain));
263 assert_eq!(RenderMode::parse("RICH"), Some(RenderMode::Rich));
264 assert_eq!(RenderMode::parse("wat"), None);
265
266 assert_eq!(ColorMode::Auto.as_str(), "auto");
267 assert_eq!(ColorMode::Always.as_str(), "always");
268 assert_eq!(ColorMode::parse("always"), Some(ColorMode::Always));
269 assert_eq!(ColorMode::parse(" never "), Some(ColorMode::Never));
270 assert_eq!(ColorMode::parse("wat"), None);
271
272 assert_eq!(UnicodeMode::Auto.as_str(), "auto");
273 assert_eq!(UnicodeMode::Always.as_str(), "always");
274 assert_eq!(UnicodeMode::Never.as_str(), "never");
275 assert_eq!(UnicodeMode::parse("AUTO"), Some(UnicodeMode::Auto));
276 assert_eq!(UnicodeMode::parse("never"), Some(UnicodeMode::Never));
277 assert_eq!(UnicodeMode::parse("AUTO"), Some(UnicodeMode::Auto));
278 assert_eq!(UnicodeMode::parse("wat"), None);
279 }
280}