use super::{
ISSUE_STATUS_ARGUMENT_NEXT_STEP, move_leading_json_to_tail, take_required_position,
unknown_command,
};
use crate::flags::{FlagScope, normalize_status, parse_flags};
use crate::{CliError, Command, SetTarget};
pub(super) fn parse_issue_status_shortcut(
action: &str,
args: &[String],
) -> Result<Command, CliError> {
let (id, tail) =
take_required_position(args, "issue_id", issue_status_missing_id_next_step(action))?;
let Some((status, scope)) = issue_status_action(action) else {
return Err(unknown_command(action));
};
let flags = parse_flags(tail.as_slice(), scope)?;
Ok(Command::Set {
target: SetTarget::IssueStatus {
id,
status: status.to_owned(),
},
json: flags.is_json(),
})
}
pub(super) fn parse_status_first_issue_id_shortcut(
status: &str,
args: &[String],
) -> Result<Command, CliError> {
let (id, tail) = take_required_position(args, "issue_id", "provide an issue id")?;
let scope = status_first_issue_scope(status);
let status = normalize_status(status)?;
let flags = parse_flags(tail.as_slice(), scope)?;
Ok(Command::Set {
target: SetTarget::IssueStatus { id, status },
json: flags.is_json(),
})
}
pub(super) fn parse_bare_issue_status_shortcut(
status: &str,
args: &[String],
) -> Result<Command, CliError> {
let scope = status_first_issue_scope(status);
let _flags = parse_flags(args, scope)?;
Err(CliError::MissingArgument {
argument: "issue_id_or_issues",
next: bare_issue_status_next_step(status),
})
}
pub(super) fn has_issue_status_action(args: &[String]) -> bool {
move_leading_json_to_tail(args)
.first()
.is_some_and(|action| issue_status_mutation_alias(action).is_some())
}
pub(super) fn parse_issue_first_status_shortcut(
id: String,
args: &[String],
) -> Result<Command, CliError> {
let (action, tail) = take_required_position(args, "status", ISSUE_STATUS_ARGUMENT_NEXT_STEP)?;
let Some((status, scope)) = issue_status_mutation(action.as_str()) else {
return Err(unknown_command(action.as_str()));
};
let flags = parse_flags(tail.as_slice(), scope)?;
Ok(Command::Set {
target: SetTarget::IssueStatus { id, status },
json: flags.is_json(),
})
}
pub(super) fn is_issue_status_action_alias(action: &str) -> bool {
issue_status_mutation_alias(action).is_some()
}
fn issue_status_action(action: &str) -> Option<(&'static str, FlagScope)> {
let value = match action {
"resolve" => ("resolved", FlagScope::Resolve),
"close" => ("resolved", FlagScope::Close),
"ignore" => ("ignored", FlagScope::Ignore),
"reopen" => ("unresolved", FlagScope::Reopen),
_ => return None,
};
Some(value)
}
fn issue_status_missing_id_next_step(action: &str) -> &'static str {
match action {
"resolve" => "use logbrew resolve <issue_id>",
"close" => "use logbrew close <issue_id>",
"ignore" => "use logbrew ignore <issue_id>",
"reopen" => "use logbrew reopen <issue_id>",
_ => "provide an issue id",
}
}
fn status_first_issue_scope(status: &str) -> FlagScope {
match status.to_ascii_lowercase().as_str() {
"resolved" => FlagScope::StatusResolved,
"closed" => FlagScope::StatusClosed,
"ignored" => FlagScope::StatusIgnored,
"open" => FlagScope::StatusOpen,
"unresolved" => FlagScope::StatusUnresolved,
_ => FlagScope::Set,
}
}
fn bare_issue_status_next_step(status: &str) -> &'static str {
match status.to_ascii_lowercase().as_str() {
"resolved" => "use logbrew resolved <issue_id> or logbrew resolved issues",
"closed" => "use logbrew closed <issue_id> or logbrew closed issues",
"ignored" => "use logbrew ignored <issue_id> or logbrew ignored issues",
"open" => "use logbrew open <issue_id> or logbrew open issues",
"unresolved" => "use logbrew unresolved <issue_id> or logbrew unresolved issues",
_ => "use logbrew <status> <issue_id> or logbrew <status> issues",
}
}
fn issue_status_mutation(action: &str) -> Option<(String, FlagScope)> {
issue_status_action(action)
.map(|(status, scope)| (status.to_owned(), scope))
.or_else(|| {
normalize_status(action)
.ok()
.map(|status| (status, status_first_issue_scope(action)))
})
}
fn issue_status_mutation_alias(action: &str) -> Option<String> {
issue_status_mutation(action).map(|(status, _scope)| status)
}