bin_efo/commands/generate.rs
1//! # Generation Sub-command
2//!
3//! This module implements the `gen` sub-command used to quickly produce
4//! sample data for the various generators in *lib_efo*. The command has no
5//! side-effects beyond printing the generated data; it is intended for
6//! interactive use or for embedding in scripts.
7//!
8//! ## Available sub-commands
9//!
10//! | Sub‑command | What it prints | Typical output |
11//! |-------------|----------------|----------------|
12//! | `character` | Character names (short or long) | `Eldric the Bold` |
13//! | `event` | Random event ideas | `A mysterious fog descends over the town` |
14//! | `town` | Town names | `Glimmerdale` |
15//! | `exotic` | Exotic character names | `Zar‑nith the Wanderer` |
16//! | `calamity` | Calamity names | `Great Plague of 1743` |
17//! | `blocker` | Blocker names | `Stone Wall of the North` |
18//!
19//! All sub‑commands share the same options:
20//!
21//! * `-n / --number` – how many items to generate (default = 1)
22//! * `--short` – print the short form when applicable (ignored for `event`, `exotic`,
23//! `calamity`, `blocker`)
24//! * `--name` – output only the name string, no extra formatting (good for scripting)
25//!
26//! # Usage
27//! ```bash
28//! # 3 long character names
29//! gen character -n 3
30//!
31//! # 1 short town name
32//! gen town -n 1 --short
33//!
34//! # 5 event ideas, only the names
35//! gen event -n 5 --name
36//!
37//! # A single exotic character name
38//! gen exotic -n 1
39//!
40//! # 2 calamity names
41//! gen calamity -n 2
42//!
43//! # 4 blocker names, short form
44//! gen blocker -n 4 --short
45//! ```
46//!
47//! > **Tip** – redirect or pipe the output:
48//! > `gen character -n 10 > chars.txt`
49//!
50//! ---
51//!
52//! # Summary
53//! | Sub‑command | Usage example | What it does |
54//! |-------------|---------------|-----------------|
55//! | `character` | `gen character -n 5 --short` | Prints 5 short (or long if `--short` omitted) character names |
56//! | `event` | `gen event -n 3 --name` | Prints 3 event names only |
57//! | `town` | `gen town -n 2` | Prints 2 town names (short form by default) |
58//! | `exotic` | `gen exotic -n 1` | Prints 1 exotic character name |
59//! | `calamity` | `gen calamity -n 2` | Prints 2 calamity names |
60//! | `blocker` | `gen blocker -n 4 --short` | Prints 4 blocker names (short form) |
61//!
62//! *All sub‑commands simply output the generated data; they do not alter any files or state.*
63
64use clap::{Args, Subcommand};
65use lib_efo::{Displayable, error::EpochError, naming::NAMING};
66
67use crate::error::AppError;
68/// The types of examples to generate.
69///
70/// Each variant maps directly to a public sub-command of the `gen` tool.
71#[derive(Subcommand, Debug)]
72pub enum GenCmd {
73 /// Generate a character
74 Character(Qty),
75 /// Events
76 Event(Qty),
77 /// Town
78 Town(Qty),
79 /// Exotic name
80 Exotic(Qty),
81 /// Calamity
82 Calamity(Qty),
83 /// Blocker
84 Blocker(Qty),
85}
86
87#[derive(Args, Debug)]
88/// Common arguments for the generation subcommands.
89///
90/// The fields are deliberately named to match the command-line flags
91/// produced by `clap`. The struct is used by all sub-commands to
92/// keep the CLI surface area minimal.
93pub struct Qty {
94 /// Amount of entities to generate.
95 #[arg(short, long, default_value_t = 1)]
96 number: usize,
97 /// Full print.
98 ///
99 /// If set to `false` the generator will produce a *short* representation
100 #[arg(long, action = clap::ArgAction::SetFalse, default_value_t = true)]
101 short: bool,
102 /// Generate only a name, no underlying structure.
103 ///
104 /// When this flag is present the generator prints only the name string
105 /// rather than any additional data or formatting.
106 #[arg(long="name", action = clap::ArgAction::SetTrue, default_value_t = false)]
107 name_only: bool,
108}
109
110/// Handles the subcommand for generating various kinds of entities.
111///
112/// Depending on the selected variant of [`GenCmd`], it delegates to the
113/// corresponding private handler function.
114///
115/// # Arguments
116/// * `cmd` - The parsed subcommand arguments.
117///
118/// # Errors
119/// Returns an [`AppError`] if any of the underlying handlers fail.
120pub fn gen_handler(cmd: &GenCmd) -> Result<(), AppError> {
121 match cmd {
122 GenCmd::Character(args) => handle_chr(args)?,
123 GenCmd::Event(args) => handle_event(args)?,
124 GenCmd::Town(args) => handle_town(args)?,
125 GenCmd::Exotic(args) => handle_exotic(args)?,
126 GenCmd::Calamity(args) => handle_calamity(args)?,
127 GenCmd::Blocker(args) => handle_blocker(args)?,
128 }
129 Ok(())
130}
131
132/// Print a calamity name
133fn handle_calamity(args: &Qty) -> Result<(), EpochError> {
134 for _ in 0..args.number {
135 let name = NAMING.generate_calamity_name();
136 if args.name_only {
137 println!("{}", name);
138 } else {
139 unimplemented!("DEPENS ON : CHARACTER CREATION")
140 }
141 }
142 Ok(())
143}
144
145/// Print a blocker name
146fn handle_blocker(args: &Qty) -> Result<(), EpochError> {
147 for _ in 0..args.number {
148 let name = NAMING.generate_blocker_name();
149 if args.name_only {
150 println!("{}", name);
151 } else {
152 unimplemented!("DEPENS ON : CHARACTER CREATION")
153 }
154 }
155 Ok(())
156}
157
158/// Prints exotic name
159fn handle_exotic(args: &Qty) -> Result<(), EpochError> {
160 for _ in 0..args.number {
161 let name = NAMING.generate_exotic_character_name();
162 if args.name_only {
163 println!("{}", name);
164 } else {
165 unimplemented!("DEPENS ON : CHARACTER CREATION")
166 }
167 }
168 Ok(())
169}
170
171/// Prints town
172fn handle_town(args: &Qty) -> Result<(), EpochError> {
173 for _ in 0..args.number {
174 let name = NAMING.generate_town_name();
175 if args.name_only {
176 println!("{}", name);
177 } else {
178 unimplemented!("DEPENS ON : TOWN CREATION")
179 }
180 }
181 Ok(())
182}
183
184/// Print events
185fn handle_event(args: &Qty) -> Result<(), EpochError> {
186 for _ in 0..args.number {
187 let event = NAMING.random_event_idea()?;
188 if args.name_only {
189 println!("{}", event.name);
190 } else {
191 println!("{}", event.oneline_display());
192 }
193 }
194 Ok(())
195}
196
197/// Print a character name
198fn handle_chr(args: &Qty) -> Result<(), EpochError> {
199 for _ in 0..args.number {
200 let name = if args.short {
201 NAMING.generate_long_character_name()
202 } else {
203 NAMING.generate_character_name()
204 };
205
206 if args.name_only {
207 println!("{}", name);
208 } else {
209 unimplemented!("DEPENS ON : CHARACTER CREATION")
210 }
211 }
212 Ok(())
213}