1#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum MetaCommand {
9 Quit,
11 Help,
13 Reset,
15 Model(Option<String>),
17 Persona(Option<String>),
19 Clear,
21}
22
23impl MetaCommand {
24 pub fn parse(line: &str) -> Option<Self> {
29 let trimmed = line.trim();
30 if !trimmed.starts_with('.') {
31 return None;
32 }
33
34 let parts: Vec<&str> = trimmed.splitn(2, whitespace_or_end).collect();
35 let cmd = parts[0];
36 let arg = parts
37 .get(1)
38 .map(|s| s.trim().to_string())
39 .filter(|s| !s.is_empty());
40
41 match cmd {
42 ".quit" | ".exit" | ".q" => Some(Self::Quit),
43 ".help" | ".h" | ".?" => Some(Self::Help),
44 ".reset" | ".r" => Some(Self::Reset),
45 ".model" | ".m" => Some(Self::Model(arg)),
46 ".persona" | ".p" => Some(Self::Persona(arg)),
47 ".clear" | ".cls" => Some(Self::Clear),
48 _ => None,
49 }
50 }
51
52 pub fn help_text() -> &'static str {
54 r#"Oxios CLI — Meta-commands:
55 .quit, .exit, .q Exit the session
56 .help, .h, .? Show this help
57 .reset, .r Reset the current session
58 .model, .m [NAME] Show or switch the active model
59 .persona, .p [NAME] Show or switch the active persona
60 .clear, .cls Clear the terminal screen
61"#
62 }
63}
64
65fn whitespace_or_end(c: char) -> bool {
67 c.is_whitespace()
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn parse_quit() {
76 assert_eq!(MetaCommand::parse(".quit"), Some(MetaCommand::Quit));
77 assert_eq!(MetaCommand::parse(".exit"), Some(MetaCommand::Quit));
78 assert_eq!(MetaCommand::parse(".q"), Some(MetaCommand::Quit));
79 }
80
81 #[test]
82 fn parse_help() {
83 assert_eq!(MetaCommand::parse(".help"), Some(MetaCommand::Help));
84 assert_eq!(MetaCommand::parse(".h"), Some(MetaCommand::Help));
85 }
86
87 #[test]
88 fn parse_model_with_arg() {
89 assert_eq!(
90 MetaCommand::parse(".model gpt-4o"),
91 Some(MetaCommand::Model(Some("gpt-4o".into())))
92 );
93 }
94
95 #[test]
96 fn parse_model_no_arg() {
97 assert_eq!(MetaCommand::parse(".model"), Some(MetaCommand::Model(None)));
98 }
99
100 #[test]
101 fn parse_persona_with_arg() {
102 assert_eq!(
103 MetaCommand::parse(".persona coder"),
104 Some(MetaCommand::Persona(Some("coder".into())))
105 );
106 }
107
108 #[test]
109 fn not_a_command() {
110 assert_eq!(MetaCommand::parse("hello world"), None);
111 assert_eq!(MetaCommand::parse("exit"), None); assert_eq!(MetaCommand::parse("quit"), None);
113 }
114}