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}