use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
#[non_exhaustive]
pub enum Command {
Compact {
instructions: Option<String>,
},
Clear,
Other(String),
}
impl Command {
#[must_use]
pub fn wire(&self) -> String {
match self {
Command::Compact {
instructions: Some(how),
} => format!("/compact {how}"),
Command::Compact { instructions: None } => "/compact".to_string(),
Command::Clear => "/clear".to_string(),
Command::Other(name) => format!("/{}", name.trim_start_matches('/')),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Commands {
pub all: Vec<String>,
pub skills: Vec<String>,
}
impl Commands {
#[must_use]
pub fn utilities(&self) -> Vec<&str> {
self.all
.iter()
.filter(|name| !self.skills.iter().any(|skill| skill == *name))
.map(String::as_str)
.collect()
}
#[must_use]
pub fn has(&self, name: &str) -> bool {
let wanted = name.trim_start_matches('/');
self.all.iter().any(|known| known == wanted)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
#[non_exhaustive]
pub enum Compaction {
Started,
Finished {
ok: bool,
error: Option<String>,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compact_carries_its_instructions_and_nothing_more() {
assert_eq!(Command::Compact { instructions: None }.wire(), "/compact");
assert_eq!(
Command::Compact {
instructions: Some("keep the failing test".into())
}
.wire(),
"/compact keep the failing test"
);
}
#[test]
fn a_named_command_gets_exactly_one_slash() {
assert_eq!(Command::Other("context".into()).wire(), "/context");
assert_eq!(Command::Other("/context".into()).wire(), "/context");
}
#[test]
fn utilities_are_the_commands_that_are_not_skills() {
let commands = Commands {
all: vec![
"code-review".into(),
"compact".into(),
"context".into(),
"verify".into(),
],
skills: vec!["code-review".into(), "verify".into()],
};
assert_eq!(commands.utilities(), vec!["compact", "context"]);
assert!(commands.has("compact"));
assert!(commands.has("/compact"));
assert!(!commands.has("nonesuch"));
}
}