use clap::{Arg, ArgMatches, Command};
use crate::infra::driving::cli::errors::{die1, CliError};
use crate::infra::driving::cli::output::OutputFormat;
use crate::infra::driving::cli::render_structured;
use crate::infra::driving::cli::theme;
pub(crate) fn subcommand(noun: &'static str, id_help: &'static str) -> Command {
let article = super::indefinite(noun);
Command::new("title")
.about(format!("Read or change the title of {article}"))
.subcommand_required(true)
.arg_required_else_help(true)
.subcommand(
Command::new("show")
.about(format!("Print the current title of {article}"))
.arg(id_arg(id_help)),
)
.subcommand(
Command::new("update")
.about(format!("Rewrite the title of {article}"))
.arg(id_arg(id_help))
.arg(
Arg::new("title")
.required(true)
.value_name("TITLE")
.help("New title (non-empty, leading/trailing whitespace stripped)"),
),
)
}
fn id_arg(help: &'static str) -> Arg {
Arg::new("id").required(true).value_name("ID").help(help)
}
pub(crate) fn required_title_arg(sub: &ArgMatches) -> &str {
crate::infra::driving::cli::helpers::required_str(sub, "title")
}
pub(crate) enum View {
NotFound,
Shown { title: String },
Updated,
NoOp,
}
pub(crate) fn render(
view: View,
display_id: &str,
canonical_id: &str,
noun: &str,
output_fmt: OutputFormat,
) {
match view {
View::NotFound => die1(
CliError::not_found(format!("{noun} '{display_id}'"), &format!("{noun} list")),
output_fmt,
),
view if output_fmt.is_structured() => {
render_structured_view(view, canonical_id, output_fmt)
}
View::Shown { title } => println!("{title}"),
View::Updated => println!("{}", theme::success(&format!("Updated {display_id}"))),
View::NoOp => println!(
"{}",
theme::noop(&format!(
"No change: {noun} {display_id} already has that title",
)),
),
}
}
fn render_structured_view(view: View, canonical_id: &str, output_fmt: OutputFormat) {
#[derive(serde::Serialize)]
#[serde(untagged)]
enum TitleResult<'a> {
Show { id: &'a str, title: &'a str },
Outcome { id: &'a str, outcome: &'a str },
}
let r = match &view {
View::Shown { title } => TitleResult::Show {
id: canonical_id,
title,
},
View::Updated => TitleResult::Outcome {
id: canonical_id,
outcome: "updated",
},
View::NoOp => TitleResult::Outcome {
id: canonical_id,
outcome: "noop",
},
View::NotFound => unreachable!(),
};
render_structured(&r, output_fmt);
}