#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Door {
pub word: &'static str,
pub takes: &'static str,
pub arity: (usize, usize),
pub summary: &'static str,
pub detail: &'static str,
}
impl Door {
pub fn usage(&self) -> String {
if self.takes.is_empty() {
format!("lernie {}", self.word)
} else {
format!("lernie {} {}", self.word, self.takes)
}
}
pub fn refused(&self, got: usize) -> String {
let (least, most) = self.arity;
let takes = if least == most {
format!("{least}")
} else {
format!("at most {most}")
};
format!(
"`lernie {}` takes {takes} argument(s) and got {got} — usage: {}",
self.word,
self.usage()
)
}
}
pub fn find(word: &str) -> Option<Door> {
TABLE.iter().find(|door| door.word == word).copied()
}
pub fn table() -> Vec<Door> {
TABLE.to_vec()
}
pub const START: Door = Door {
word: "start",
takes: "<workspace> <goal>",
arity: (2, 2),
summary: "begin a conversation on that workspace",
detail: "The start family's two acts (yog's REMOTE §8.1), staged and \
fired in one process. Not a gesture but both of them: a \
`prepare`, then a `prompt` carrying the body that answered it \
straight back. Both reply streams print; the exit code is the \
fire's. It is one word because the thing between the two acts is \
a local — the staged body, held while the second is composed — \
and a nested object is not a word an operator types, which is why \
it is a door here rather than a row of the gesture table.",
};
pub const ASK: Door = Door {
word: "ask",
takes: "<envelope>",
arity: (1, 1),
summary: "one gesture envelope, written out",
detail: "Any op — including one this build has never heard of — as the \
JSON object the boundary carries, with `op` the discriminant and \
every parameter a named field. This is not a fallback: it is the \
surface, and the typed verbs are its shorthand. Quote it as one \
argument. It goes down the channel its `workspace` names, exactly \
as a typed verb does, and an op the far end does not know refuses \
in band naming it.",
};
pub const ENTRIES: Door = Door {
word: "entries",
takes: "",
arity: (0, 0),
summary: "describe every channel this box holds, without dialling any",
detail: "This box's own engine first, then one row per workspace held \
elsewhere, each with its address or the reason it has none. It \
opens no socket, so it answers with every engine down — and a \
half-provisioned channel says which file is missing beside the \
ones that are fine. Material reaches these directories by the \
operator's hand, out of channel, always.",
};
pub const HELP: Door = Door {
word: "help",
takes: "[<verb>]",
arity: (0, 1),
summary: "what a word takes and what it answers with",
detail: "With no argument, the usage and every word this binary answers. \
With one, that word's own page — a gesture verb or one of the \
four doors alike, because a page an operator is offered has to be \
reachable for every word the list names. Its subject is this \
binary rather than a world, so it answers with no engine up and \
no channel provisioned. `--help` and `-h` are the same word.",
};
const TABLE: &[Door] = &[START, ASK, ENTRIES, HELP];
#[cfg(test)]
mod tests;