#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParsedSlashCommand {
pub command_name: String,
pub args: String,
pub is_mcp: bool,
}
pub fn parse_slash_command(input: &str) -> Option<ParsedSlashCommand> {
let trimmed_input = input.trim();
if !trimmed_input.starts_with('/') {
return None;
}
let without_slash = &trimmed_input[1..];
let words: Vec<&str> = without_slash.splitn(2, ' ').collect();
if words.is_empty() || words[0].is_empty() {
return None;
}
let command_name;
let is_mcp;
let args;
if let Some(rest) = words.get(1) {
let parts: Vec<&str> = rest.splitn(2, ' ').collect();
if parts.first() == Some(&"(MCP)") {
command_name = format!("{} (MCP)", words[0]);
is_mcp = true;
args = parts.get(1).unwrap_or(&"").to_string();
} else {
command_name = words[0].to_string();
is_mcp = false;
args = rest.to_string();
}
} else {
command_name = words[0].to_string();
is_mcp = false;
args = String::new();
}
Some(ParsedSlashCommand {
command_name,
args,
is_mcp,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_simple_command() {
let result = parse_slash_command("/search foo bar").unwrap();
assert_eq!(result.command_name, "search");
assert_eq!(result.args, "foo bar");
assert!(!result.is_mcp);
}
#[test]
fn test_parse_mcp_command() {
let result = parse_slash_command("/mcp:tool (MCP) arg1 arg2").unwrap();
assert_eq!(result.command_name, "mcp:tool (MCP)");
assert_eq!(result.args, "arg1 arg2");
assert!(result.is_mcp);
}
#[test]
fn test_parse_no_leading_slash() {
assert!(parse_slash_command("search foo").is_none());
}
#[test]
fn test_parse_empty_command() {
assert!(parse_slash_command("/").is_none());
assert!(parse_slash_command("/ ").is_none());
}
#[test]
fn test_parse_command_no_args() {
let result = parse_slash_command("/search").unwrap();
assert_eq!(result.command_name, "search");
assert_eq!(result.args, "");
}
}