#![deny(missing_docs)]
use std::collections::HashMap;
use std::env;
use std::os::unix::process::CommandExt as _;
use std::process::Command;
use anyhow::{Context as _, Result, anyhow};
use utf8_locale::{LanguagesDetect, Utf8Detect};
use cli::Mode;
mod cli;
const FEATURES: [(&str, &str); 4] = [
("u8loc", env!("CARGO_PKG_VERSION")),
("query-env", "0.1"),
("query-preferred", "0.1"),
("run", "0.1"),
];
fn get_env(preferred: bool) -> Result<HashMap<String, String>> {
let det = if preferred {
let langs = LanguagesDetect::new()
.detect()
.context("Could not determine the list of preferred languages")?;
Utf8Detect::new().with_languages(langs)
} else {
Utf8Detect::new()
};
Ok(det.detect().context("Could not detect a UTF-8 locale")?.env)
}
fn query_env(name: &str, preferred: bool) -> Result<Vec<String>> {
let value = {
let mut env = get_env(preferred)?;
env.remove(name)
.ok_or_else(|| anyhow!("Internal error: {name:?} should be present in {env:?}"))?
};
Ok(vec![value])
}
fn query_list() -> Vec<String> {
vec![
"LANGUAGE - The LANGUAGE environment variable".to_owned(),
"LC_ALL - The LC_ALL environment variable".to_owned(),
"list - List the available query parameters".to_owned(),
"preferred - List the preferred languages as per the locale variables".to_owned(),
]
}
fn query_preferred() -> Result<Vec<String>> {
LanguagesDetect::new()
.detect()
.context("Could not determine the list of preferred languages")
}
fn run_program(prog: &[String], preferred: bool) -> Result<Vec<String>> {
let env = get_env(preferred)?;
let (prog_name, args) = prog
.split_first()
.ok_or_else(|| anyhow!("Not even a program name?"))?;
Err(Command::new(prog_name)
.args(args)
.env_clear()
.envs(env)
.exec())
.context(format!("Could not execute the {prog_name} program"))
}
fn run() -> Result<Option<Vec<String>>> {
match cli::parse_args()? {
Mode::Handled => Ok(None),
Mode::QueryEnv(ref name, ref preferred) => query_env(name, *preferred).map(Some),
Mode::QueryList => Ok(Some(query_list())),
Mode::QueryPreferred => query_preferred().map(Some),
Mode::Run(ref prog, ref preferred) => run_program(prog, *preferred).map(Some),
}
}
#[expect(clippy::print_stdout, reason = "this is the whole point")]
fn main() -> Result<()> {
if let Some(res) = run()? {
println!("{res}", res = res.join("\n"));
}
Ok(())
}