1use std::path::PathBuf;
2
3use anyhow::Result;
4use serde::{Deserialize, Serialize};
5use tracing::warn;
6
7use crate::config::Config;
8use crate::recipe::Recipe;
9
10const SLASH_COMMANDS_CONFIG_KEY: &str = "slash_commands";
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct SlashCommandMapping {
14 pub command: String,
15 pub recipe_path: String,
16}
17
18pub fn list_commands() -> Vec<SlashCommandMapping> {
19 Config::global()
20 .get_param(SLASH_COMMANDS_CONFIG_KEY)
21 .unwrap_or_else(|err| {
22 warn!(
23 "Failed to load {}: {}. Falling back to empty list.",
24 SLASH_COMMANDS_CONFIG_KEY, err
25 );
26 Vec::new()
27 })
28}
29
30fn save_slash_commands(commands: Vec<SlashCommandMapping>) -> Result<()> {
31 Config::global()
32 .set_param(SLASH_COMMANDS_CONFIG_KEY, &commands)
33 .map_err(|e| anyhow::anyhow!("Failed to save slash commands: {}", e))
34}
35
36pub fn set_recipe_slash_command(recipe_path: PathBuf, command: Option<String>) -> Result<()> {
37 let recipe_path_str = recipe_path.to_string_lossy().to_string();
38
39 let mut commands = list_commands();
40 commands.retain(|mapping| mapping.recipe_path != recipe_path_str);
41
42 if let Some(cmd) = command {
43 let normalized_cmd = cmd.trim_start_matches('/').to_lowercase();
44 if !normalized_cmd.is_empty() {
45 commands.push(SlashCommandMapping {
46 command: normalized_cmd,
47 recipe_path: recipe_path_str,
48 });
49 }
50 }
51
52 save_slash_commands(commands)
53}
54
55pub fn get_recipe_for_command(command: &str) -> Option<PathBuf> {
56 let normalized = command.trim_start_matches('/').to_lowercase();
57 let commands = list_commands();
58 commands
59 .into_iter()
60 .find(|mapping| mapping.command == normalized)
61 .map(|mapping| PathBuf::from(mapping.recipe_path))
62}
63
64pub fn resolve_slash_command(command: &str) -> Option<Recipe> {
65 let recipe_path = get_recipe_for_command(command)?;
66
67 if !recipe_path.exists() {
68 return None;
69 }
70 let recipe_content = std::fs::read_to_string(&recipe_path).ok()?;
71 let recipe = Recipe::from_content(&recipe_content).ok()?;
72
73 Some(recipe)
74}