use crate::boundary::codec::prepared_from_value;
use crate::boundary::line::Context;
use std::path::PathBuf;
pub(super) struct Invocation {
pub(super) context: Context,
pub(super) payload: String,
}
pub(super) fn read(args: &[String]) -> Result<Invocation, String> {
let mut context = Context::default();
let mut payload: Option<String> = None;
let mut asked_help = false;
let mut rest = args.iter();
while let Some(arg) = rest.next() {
if arg == "--help" || arg == "-h" {
asked_help = true;
continue;
}
let Some(flag) = arg.strip_prefix("--") else {
if payload.replace(arg.clone()).is_some() {
return Err(format!("expected one gesture, got another: {arg:?}"));
}
continue;
};
let value = rest
.next()
.ok_or_else(|| format!("--{flag} needs a value"))?
.clone();
match flag {
"ws" => context.workspace = Some(PathBuf::from(value)),
"agent" => context.agent = Some(value),
"project" => context.project = Some(PathBuf::from(value)),
"as" => context.name = Some(value),
"prepared" => {
let v = serde_json::from_str(&value)
.map_err(|e| format!("--prepared: not JSON: {e}"))?;
context.prepared = Some(prepared_from_value(&v)?);
}
other => return Err(format!("unknown flag --{other}; {USAGE}")),
}
}
if asked_help {
let about = payload.unwrap_or_default();
let about = about.trim().trim_start_matches('/');
return Ok(Invocation {
context,
payload: format!("/help {about}").trim_end().to_owned(),
});
}
let payload = payload.ok_or_else(|| format!("nothing to do; {USAGE}"))?;
Ok(Invocation { context, payload })
}
pub(super) const USAGE: &str = "usage: yog gesture [--ws PATH] [--agent ID] [--project PATH] \
[--as NAME] [--prepared JSON] '<json>' | '/line'\n yog gesture --help [command] — every \
gesture, or one command's page";