use std::io::IsTerminal;
use crate::errors::{CliError, CliResult};
use crate::store_open;
#[derive(clap::Args)]
pub struct FffArgs {
query: Option<String>,
#[arg(long)]
project: Option<String>,
#[arg(long)]
label: Option<String>,
#[arg(long)]
milestone: Option<String>,
#[arg(long)]
status: Option<String>,
#[arg(long)]
priority: Option<String>,
#[arg(long)]
parent: Option<String>,
#[arg(long)]
archived: bool,
#[arg(long = "no-subs")]
no_subs: bool,
#[arg(long, hide = true)]
show: bool,
#[arg(long, hide = true)]
edit: bool,
#[arg(long, hide = true)]
json: bool,
}
pub async fn run(db: &Option<String>, a: FffArgs) -> CliResult<()> {
let modes = [a.show, a.edit, a.json].iter().filter(|b| **b).count();
if modes > 1 {
return Err(CliError::validation(
"--show, --edit, and --json are mutually exclusive",
));
}
let query = a.query.clone().unwrap_or_default();
if std::io::stdin().is_terminal() {
return Err(CliError::other("fff interactive picker not yet wired"));
}
if query.trim().is_empty() {
return Err(CliError::validation(
"cliban fff in non-interactive mode requires a QUERY",
));
}
let store = store_open::open(db).await?;
let opts = crate::search::Options {
query,
project: a.project.as_deref().map(str::to_uppercase),
label: a.label.clone().into_iter().collect(),
milestone: a.milestone.clone(),
status: a.status.clone(),
priority: a.priority.clone(),
parent: a.parent.clone(),
include_archived: a.archived,
exclude_subs: a.no_subs,
limit: 50,
};
let matches = crate::search::search(&store, opts).await?;
for m in &matches {
let inputs = crate::cmd::issue::issue_json_inputs(&store, &m.issue).await?;
println!(
"{}",
serde_json::to_string(&crate::output::build_search_match_json(
inputs,
m.score,
crate::output::Detail::Brief
))
.unwrap()
);
}
Ok(())
}