use camino::Utf8PathBuf;
use clap::builder::{TypedValueParser, ValueParser};
use clap::error::ErrorKind;
use clap::{ArgMatches, CommandFactory};
use ortho_config::{LocalizationArgs, Localizer, parse_localized_command};
use std::ffi::{OsStr, OsString};
use std::sync::Arc;
use super::command::Cli;
use super::parsing::{
parse_accessibility_policy, parse_color_policy, parse_emoji_policy, parse_host_pattern,
parse_jobs, parse_locale, parse_progress_policy, parse_scheme, parse_utf8_path,
};
use super::policy_values::{
accessibility_policy_possible_values, colour_policy_possible_values,
emoji_policy_possible_values, progress_policy_possible_values,
};
use super::value_parser::LocalizedValueParser;
use crate::cli_l10n::localize_command;
pub use crate::cli_l10n::{json_hint_from_args, locale_hint_from_args};
use crate::cli_localization::build_localizer;
use crate::localization::keys;
#[derive(Clone)]
struct LocalizedUtf8PathParser {
localizer: Arc<dyn Localizer>,
key: &'static str,
fallback: &'static str,
}
impl LocalizedUtf8PathParser {
fn new(localizer: Arc<dyn Localizer>, key: &'static str, fallback: &'static str) -> Self {
Self {
localizer,
key,
fallback,
}
}
}
impl TypedValueParser for LocalizedUtf8PathParser {
type Value = Utf8PathBuf;
fn parse_ref(
&self,
cmd: &clap::Command,
_arg: Option<&clap::Arg>,
value: &OsStr,
) -> Result<Self::Value, clap::Error> {
let mut command = cmd.clone();
parse_utf8_path(self.localizer.as_ref(), value, self.key, self.fallback)
.map_err(|error| command.error(ErrorKind::ValueValidation, error))
}
}
pub(super) fn validation_message(
localizer: &dyn Localizer,
key: &'static str,
args: Option<&LocalizationArgs<'_>>,
fallback: &str,
) -> String {
localizer.message(key, args, fallback)
}
pub fn parse_with_localizer_from<I, T>(
iter: I,
localizer: &Arc<dyn Localizer>,
) -> Result<(Cli, ArgMatches), clap::Error>
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
let command = configured_command(Some(localizer));
parse_localized_command(command, iter, localizer.as_ref())
}
pub(crate) fn configured_command(localizer: Option<&Arc<dyn Localizer>>) -> clap::Command {
let parser_localizer = localizer
.cloned()
.unwrap_or_else(|| Arc::from(build_localizer(None)));
let command = localizer.map_or_else(Cli::command, |active_localizer| {
localize_command(Cli::command(), active_localizer.as_ref())
});
configure_validation_parsers(command, &parser_localizer)
}
fn configure_utf8_path_parsers(
mut command: clap::Command,
localizer: &Arc<dyn Localizer>,
) -> clap::Command {
let file_parser = LocalizedUtf8PathParser::new(
Arc::clone(localizer),
keys::CLI_FILE_NON_UTF8,
"Manifest path is not valid UTF-8.",
);
let directory_parser = LocalizedUtf8PathParser::new(
Arc::clone(localizer),
keys::CLI_DIRECTORY_NON_UTF8,
"Working directory path is not valid UTF-8.",
);
command = command.mut_arg("file", |arg| {
arg.value_parser(ValueParser::new(file_parser))
});
command.mut_arg("directory", |arg| {
arg.value_parser(ValueParser::new(directory_parser))
})
}
fn configure_validation_parsers(
initial_command: clap::Command,
localizer: &Arc<dyn Localizer>,
) -> clap::Command {
let mut command = configure_utf8_path_parsers(initial_command, localizer);
let jobs_parser = LocalizedValueParser::new(Arc::clone(localizer), parse_jobs);
let locale_parser = LocalizedValueParser::new(Arc::clone(localizer), parse_locale);
let scheme_parser = LocalizedValueParser::new(Arc::clone(localizer), parse_scheme);
let host_parser = LocalizedValueParser::new(Arc::clone(localizer), parse_host_pattern);
let color_policy_parser = LocalizedValueParser::with_possible_values(
Arc::clone(localizer),
parse_color_policy,
colour_policy_possible_values(),
);
let emoji_policy_parser = LocalizedValueParser::with_possible_values(
Arc::clone(localizer),
parse_emoji_policy,
emoji_policy_possible_values(),
);
let progress_policy_parser = LocalizedValueParser::with_possible_values(
Arc::clone(localizer),
parse_progress_policy,
progress_policy_possible_values(),
);
let accessibility_policy_parser = LocalizedValueParser::with_possible_values(
Arc::clone(localizer),
parse_accessibility_policy,
accessibility_policy_possible_values(),
);
command = command.mut_arg("jobs", |arg| {
arg.value_parser(ValueParser::new(jobs_parser))
});
command = command.mut_arg("locale", |arg| {
arg.value_parser(ValueParser::new(locale_parser))
});
command = command.mut_arg("fetch_allow_scheme", |arg| {
arg.value_parser(ValueParser::new(scheme_parser.clone()))
});
command = command.mut_arg("fetch_allow_host", |arg| {
arg.value_parser(ValueParser::new(host_parser.clone()))
});
command = command.mut_arg("fetch_block_host", |arg| {
arg.value_parser(ValueParser::new(host_parser))
});
command = command.mut_arg("color", |arg| {
arg.value_parser(ValueParser::new(color_policy_parser))
});
command = command.mut_arg("emoji", |arg| {
arg.value_parser(ValueParser::new(emoji_policy_parser))
});
command = command.mut_arg("progress", |arg| {
arg.value_parser(ValueParser::new(progress_policy_parser))
});
command = command.mut_arg("accessibility", |arg| {
arg.value_parser(ValueParser::new(accessibility_policy_parser))
});
command
}
#[cfg(test)]
#[path = "parser_tests.rs"]
mod tests;