u8loc 1.1.1

Run child processes in a UTF-8-capable locale
// SPDX-FileCopyrightText: Peter Pentchev <roam@ringlet.net>
// SPDX-License-Identifier: BSD-2-Clause
//! Parse command-line options for the `u8loc` command-line tool.

use anyhow::{Context as _, Result, bail};
use clap::Parser as _;
use clap_derive::Parser;
use roundlet::cli_basic;

/// Run a command in a UTF-8-capable locale.
#[derive(Debug, Parser)]
#[clap(version)]
struct Cli {
    /// Use a locale specified in the LANG and LC_* variables if appropriate.
    #[clap(short)]
    preferred: bool,

    /// Output the value of an environment variable.
    #[clap(short)]
    query: Option<String>,

    /// Run the specified program in a UTF-8-friendly environment.
    #[clap(short)]
    run: bool,

    /// The program to run if the `-r` flag is specified.
    program: Vec<String>,
}

/// The action to take as specified by the command-line arguments.
#[derive(Debug)]
pub enum Mode {
    Handled,
    QueryEnv(String, bool),
    QueryList,
    QueryPreferred,
    Run(Vec<String>, bool),
}

/// Parse the command-line arguments, determine the operation mode.
///
/// # Errors
///
/// Propagate [`clap`] command-line parsing errors.
pub fn parse_args() -> Result<Mode> {
    {
        let prog = "u8loc";
        let ver = env!("CARGO_PKG_VERSION");
        if cli_basic::handle_basic_options(
            prog,
            ver,
            crate::FEATURES,
            "Usage:	u8loc [-p] -r program args...
	u8loc [-p] -q LC_ALL
	u8loc [-p] -q LANGUAGE
	u8loc -q preferred
	u8loc -q list
	u8loc --features

	-p	use a locale specified in the LANG and LC_* variables if appropriate
	-q	output the value of an environment variable
	-r	run the specified program in a UTF-8-friendly environment",
        ) {
            return Ok(Mode::Handled);
        }
    }
    let args = Cli::try_parse().context("Could not parse the command-line options")?;
    let preferred = args.preferred;
    if let Some(query) = args.query {
        if args.run {
            bail!("Exactly one of the -q and -r options must be specified");
        }
        match &*query {
            "list" => Ok(Mode::QueryList),
            "preferred" => Ok(Mode::QueryPreferred),
            var @ ("LC_ALL" | "LANGUAGE") => Ok(Mode::QueryEnv(var.to_owned(), preferred)),
            other => {
                bail!(format!("Invalid query name '{other}' specified"));
            }
        }
    } else if args.run {
        if args.program.is_empty() {
            bail!("No program specified to run");
        }
        Ok(Mode::Run(args.program, preferred))
    } else {
        bail!("Exactly one of the -q and -r options must be specified");
    }
}