use super::{Context, args};
use crate::boundary::{Action, Gesture};
use crate::monitor::Verb;
use crate::start::{BallSpec, Payload};
use std::path::PathBuf;
pub(super) fn seen(tail: &str, ctx: &Context, verb: &str) -> Result<Gesture, String> {
args::none(tail, verb)?;
Ok(act(Action::MarkSeen {
workspace: args::workspace(ctx, verb)?,
agent: args::agent(ctx, verb)?,
}))
}
pub(super) fn retarget(tail: &str, ctx: &Context, verb: &str) -> Result<Gesture, String> {
args::none(tail, verb)?;
Ok(act(Action::Retarget {
workspace: args::workspace(ctx, verb)?,
agent: args::agent(ctx, verb)?,
}))
}
pub(super) fn prompt(tail: &str, ctx: &Context, verb: &str) -> Result<Gesture, String> {
Ok(act(Action::Prompt {
prepared: ctx.prepared.clone().ok_or_else(|| {
format!("/{verb}: nothing is prepared — /prepare first, then say the goal")
})?,
goal: args::required(tail, verb, "the goal")?,
seed: None,
}))
}
pub(super) fn answer(tail: &str, ctx: &Context, verb: &str) -> Result<Gesture, String> {
let word = args::required(tail, verb, "pass, hold or refuse")?;
let ruling = crate::control::judge::Ruling::of(word.trim())
.ok_or_else(|| format!("/{verb}: unknown verdict {word:?}; usage: {ANSWER_USAGE}"))?;
Ok(act(Action::AnswerHold {
workspace: args::workspace(ctx, verb)?,
agent: args::agent(ctx, verb)?,
ruling,
}))
}
pub const ANSWER_USAGE: &str = "/answer pass | hold | refuse";
pub(super) fn floor(verb: &str, tail: &str, ctx: &Context) -> Result<Gesture, String> {
args::none(tail, verb)?;
Ok(act(Action::Floor {
workspace: args::workspace(ctx, verb)?,
agent: args::agent(ctx, verb)?,
raised: verb == "revoke",
}))
}
const OPS_DEFAULT: usize = 50;
fn act(action: Action) -> Gesture {
Gesture::Act(action)
}
pub(super) fn children(tail: &str) -> Result<bool, String> {
match tail.trim() {
"" => Ok(false),
"children" => Ok(true),
other => Err(format!(
"/stop: unexpected {other:?}; usage: /stop [children]"
)),
}
}
pub(super) fn payload(tail: &str, ctx: &Context, verb: &str) -> Result<Payload, String> {
let (rung, rest) = args::first_word(tail);
match rung.as_str() {
"" => Ok(Payload::Bare),
"dir" => Ok(Payload::Path {
dir: PathBuf::from(args::required(&rest, verb, "a work directory")?),
}),
"ball" => Ok(Payload::Ball {
project: args::project(ctx, verb)?,
ball: spec(&rest, ctx, verb)?,
}),
other => Err(format!(
"/{verb}: unknown rung {other:?}; usage: /prepare | /prepare dir <path> | /prepare ball [--new <title…>]"
)),
}
}
fn spec(rest: &str, ctx: &Context, verb: &str) -> Result<BallSpec, String> {
let (positional, flags) = args::split_flags(rest);
args::only(&flags, &["new", "body"], verb)?;
args::none(&positional, verb)?;
match args::flag(&flags, "new", verb)? {
Some(title) => Ok(BallSpec::New {
title,
body: args::flag(&flags, "body", verb)?.unwrap_or_default(),
}),
None => ctx.ball.clone().ok_or_else(|| {
format!("/{verb}: no ball is selected — select one, or say --new <title…>")
}),
}
}
pub(super) fn work_file(
tail: &str,
verb: &str,
) -> Result<Option<crate::workdiff::WorkFile>, String> {
match tail.split_whitespace().collect::<Vec<_>>().as_slice() {
[] => Ok(None),
[ball, path] => Ok(Some(crate::workdiff::WorkFile {
ball: (*ball).to_owned(),
handle: None,
path: (*path).to_owned(),
})),
[ball, handle, path] => Ok(Some(crate::workdiff::WorkFile {
ball: (*ball).to_owned(),
handle: Some((*handle).to_owned()),
path: (*path).to_owned(),
})),
_ => Err(format!(
"/{verb}: usage: /work-diff [<ball> [<handle>] <path>]"
)),
}
}
pub(super) fn max(tail: &str) -> Result<usize, String> {
match args::optional_word(tail, "ops")? {
None => Ok(OPS_DEFAULT),
Some(word) => word
.parse()
.map_err(|_| format!("/ops: {word:?} is not a row count")),
}
}
pub(super) fn monitor(verb: &str, tail: &str, ctx: &Context) -> Result<Gesture, String> {
let workspace = args::workspace(ctx, verb)?;
let gesture = match verb {
"arm" => Verb::Arm {
workspace,
model: args::required(tail, verb, "the model to check with")?,
},
"disarm" => {
args::none(tail, verb)?;
Verb::Disarm { workspace }
}
_ => Verb::Flag {
workspace,
agent: args::agent(ctx, verb)?,
reason: args::required(tail, verb, "why")?,
},
};
Ok(act(Action::Monitor(gesture)))
}
pub(super) fn fleet(verb: &str, tail: &str, ctx: &Context) -> Result<Gesture, String> {
let workspace = args::workspace(ctx, verb)?;
let gesture = if verb == crate::boundary::codec::FLEET_ARM {
let word = args::required(tail, verb, "the cap — how many balls at once")?;
crate::fleet::Verb::Arm {
workspace,
project: args::project(ctx, verb)?,
cap: word
.parse()
.map_err(|_| format!("/{verb}: {word:?} is not a cap"))?,
}
} else {
args::none(tail, verb)?;
crate::fleet::Verb::Disarm { workspace }
};
Ok(act(Action::Fleet(gesture)))
}