Skip to main content

romm_cli/commands/
mod.rs

1//! Top-level CLI command handling.
2//!
3//! The `Cli` type (derived from `clap`) describes the public command-line
4//! interface. Each subcommand lives in its own module and is free to use
5//! `RommClient` directly. The TUI is just another subcommand.
6
7use anyhow::Result;
8use clap::{Parser, Subcommand};
9
10use crate::client::RommClient;
11use crate::config::Config;
12
13pub mod api;
14pub mod download;
15pub mod init;
16pub mod platforms;
17pub mod print;
18pub mod roms;
19pub mod update;
20
21/// How a command should format its output.
22#[derive(Clone, Copy, Debug)]
23pub enum OutputFormat {
24    /// Human-readable text (tables, aligned columns, etc.).
25    Text,
26    /// Machine-friendly JSON (pretty-printed by default).
27    Json,
28}
29
30impl OutputFormat {
31    /// Resolve the effective output format from global and per-command flags.
32    pub fn from_flags(global_json: bool, local_json: bool) -> Self {
33        if global_json || local_json {
34            OutputFormat::Json
35        } else {
36            OutputFormat::Text
37        }
38    }
39}
40
41/// Top-level CLI entrypoint for `romm-cli`.
42///
43/// This binary can be used both as:
44/// - a **TUI launcher** (`romm-cli tui`), and
45/// - a **scripting-friendly CLI** for platforms/ROMs/API calls.
46#[derive(Parser, Debug)]
47#[command(
48    name = "romm-cli",
49    version,
50    about = "Rust CLI and TUI for the ROMM API",
51    infer_subcommands = true,
52    arg_required_else_help = true
53)]
54pub struct Cli {
55    /// Increase output verbosity
56    #[arg(short, long, global = true)]
57    pub verbose: bool,
58
59    /// Output JSON instead of human-readable text where supported.
60    #[arg(long, global = true)]
61    pub json: bool,
62
63    #[command(subcommand)]
64    pub command: Commands,
65}
66
67/// All top-level commands supported by the CLI.
68#[derive(Subcommand, Debug)]
69pub enum Commands {
70    /// Create or update user config (~/.config/romm-cli/.env or %APPDATA%\\romm-cli\\.env)
71    #[command(visible_alias = "setup")]
72    Init(init::InitCommand),
73    /// Launch interactive TUI for exploring API endpoints
74    #[cfg(feature = "tui")]
75    Tui,
76    /// Launch interactive TUI (stub for disabled feature)
77    #[cfg(not(feature = "tui"))]
78    Tui,
79    /// Low-level access to any ROMM API endpoint
80    #[command(visible_alias = "call")]
81    Api(api::ApiCommand),
82    /// Platform-related commands
83    #[command(visible_aliases = ["platform", "p", "plats"])]
84    Platforms(platforms::PlatformsCommand),
85    /// ROM-related commands
86    #[command(visible_aliases = ["rom", "r"])]
87    Roms(roms::RomsCommand),
88    /// Download a ROM
89    #[command(visible_aliases = ["dl", "get"])]
90    Download(download::DownloadCommand),
91    /// Check for and install updates for romm-cli
92    Update,
93}
94
95pub async fn run(cli: Cli, config: Config) -> Result<()> {
96    let client = RommClient::new(&config, cli.verbose)?;
97
98    match cli.command {
99        Commands::Init(_) => {
100            anyhow::bail!("internal error: init must be handled before load_config");
101        }
102        #[cfg(feature = "tui")]
103        Commands::Tui => {
104            anyhow::bail!("internal error: TUI must be started via run_interactive from main");
105        }
106        #[cfg(not(feature = "tui"))]
107        Commands::Tui => anyhow::bail!("this feature requires the tui"),
108        command => crate::frontend::cli::run(command, &client, cli.json).await?,
109    }
110
111    Ok(())
112}