#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MetaCommand {
Quit,
Help,
Reset,
Model(Option<String>),
Persona(Option<String>),
Space(Option<String>),
Spaces,
Clear,
}
impl MetaCommand {
pub fn parse(line: &str) -> Option<Self> {
let trimmed = line.trim();
if !trimmed.starts_with('.') {
return None;
}
let parts: Vec<&str> = trimmed.splitn(2, whitespace_or_end).collect();
let cmd = parts[0];
let arg = parts
.get(1)
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty());
match cmd {
".quit" | ".exit" | ".q" => Some(Self::Quit),
".help" | ".h" | ".?" => Some(Self::Help),
".reset" | ".r" => Some(Self::Reset),
".model" | ".m" => Some(Self::Model(arg)),
".persona" | ".p" => Some(Self::Persona(arg)),
".space" | ".sp" => Some(Self::Space(arg)),
".spaces" => Some(Self::Spaces),
".clear" | ".cls" => Some(Self::Clear),
_ => None,
}
}
pub fn help_text() -> &'static str {
r#"Oxios CLI — Meta-commands:
.quit, .exit, .q Exit the session
.help, .h, .? Show this help
.reset, .r Reset the current session
.model, .m [NAME] Show or switch the active model
.persona, .p [NAME] Show or switch the active persona
.space, .sp [ID|NAME] Show or switch the active Space
.spaces List all Spaces
.clear, .cls Clear the terminal screen
"#
}
}
fn whitespace_or_end(c: char) -> bool {
c.is_whitespace()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_quit() {
assert_eq!(MetaCommand::parse(".quit"), Some(MetaCommand::Quit));
assert_eq!(MetaCommand::parse(".exit"), Some(MetaCommand::Quit));
assert_eq!(MetaCommand::parse(".q"), Some(MetaCommand::Quit));
}
#[test]
fn parse_help() {
assert_eq!(MetaCommand::parse(".help"), Some(MetaCommand::Help));
assert_eq!(MetaCommand::parse(".h"), Some(MetaCommand::Help));
}
#[test]
fn parse_model_with_arg() {
assert_eq!(
MetaCommand::parse(".model gpt-4o"),
Some(MetaCommand::Model(Some("gpt-4o".into())))
);
}
#[test]
fn parse_model_no_arg() {
assert_eq!(MetaCommand::parse(".model"), Some(MetaCommand::Model(None)));
}
#[test]
fn parse_persona_with_arg() {
assert_eq!(
MetaCommand::parse(".persona coder"),
Some(MetaCommand::Persona(Some("coder".into())))
);
}
#[test]
fn parse_space_no_arg() {
assert_eq!(MetaCommand::parse(".space"), Some(MetaCommand::Space(None)));
assert_eq!(MetaCommand::parse(".sp"), Some(MetaCommand::Space(None)));
}
#[test]
fn parse_space_with_arg() {
assert_eq!(
MetaCommand::parse(".space my-space"),
Some(MetaCommand::Space(Some("my-space".into())))
);
assert_eq!(
MetaCommand::parse(".sp 550e8400-e29b-41d4-a716-446655440000"),
Some(MetaCommand::Space(Some(
"550e8400-e29b-41d4-a716-446655440000".into()
)))
);
}
#[test]
fn parse_spaces() {
assert_eq!(MetaCommand::parse(".spaces"), Some(MetaCommand::Spaces));
}
#[test]
fn not_a_command() {
assert_eq!(MetaCommand::parse("hello world"), None);
assert_eq!(MetaCommand::parse("exit"), None); assert_eq!(MetaCommand::parse("quit"), None);
}
}