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