use crate::reply::start::Prepared;
use crate::ui::Model;
#[derive(Debug, Clone, PartialEq)]
pub struct Start {
pub address: String,
pub goal: String,
pub phase: Phase,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Phase {
Staging,
Firing,
Started(String),
}
impl Start {
pub fn line(&self) -> String {
match &self.phase {
Phase::Started(name) => format!("started «{name}» in {}", self.address),
Phase::Staging | Phase::Firing => {
format!("starting in {}: {}…", self.address, self.goal)
}
}
}
pub fn outstanding(&self) -> bool {
!matches!(self.phase, Phase::Started(_))
}
}
impl Model {
pub fn stage(&mut self, address: &str) {
if self.draft.trim().is_empty() {
return;
}
let goal = std::mem::take(&mut self.draft);
self.outbox.push(super::Posted::act(crate::verbs::prepare(
address.to_owned(),
)));
self.start = Some(Start {
address: address.to_owned(),
goal,
phase: Phase::Staging,
});
}
pub(super) fn fire(&mut self, prepared: &Prepared) {
let held = self
.start
.clone()
.filter(|start| matches!(start.phase, Phase::Staging));
let (address, goal) = held.map_or_else(
|| (prepared.workspace.clone(), prepared.goal.clone()),
|start| (start.address, start.goal),
);
if goal.trim().is_empty() {
self.start = None;
return;
}
self.outbox.push(super::Posted::act(crate::verbs::prompt(
prepared,
address.clone(),
goal.clone(),
)));
self.start = Some(Start {
address,
goal,
phase: Phase::Firing,
});
}
pub(super) fn started(&mut self, conversation: String) {
let mut start = self.start.clone().unwrap_or_else(|| Start {
address: self
.aim
.as_ref()
.map_or_else(String::new, |aim| aim.address.clone()),
goal: String::new(),
phase: Phase::Firing,
});
start.phase = Phase::Started(conversation.clone());
let here = self
.aim
.as_ref()
.is_some_and(|aim| aim.address == start.address);
self.start = Some(start);
if here {
self.select(&conversation);
}
}
}
#[cfg(test)]
mod tests;