prompts_cli/core/
mod.rs

1use anyhow::Result;
2use fuzzy_matcher::skim::SkimMatcherV2;
3use fuzzy_matcher::FuzzyMatcher;
4
5pub struct Prompts {
6    storage: Box<dyn crate::storage::Storage + Send + Sync>,
7}
8
9impl Prompts {
10    pub fn new(storage: Box<dyn crate::storage::Storage + Send + Sync>) -> Self {
11        Self { storage }
12    }
13
14    pub async fn add_prompt(&self, prompt: &mut crate::storage::Prompt) -> Result<()> {
15        self.storage.save_prompt(prompt)
16    }
17
18    pub async fn list_prompts(&self) -> Result<Vec<crate::storage::Prompt>> {
19        self.storage.load_prompts()
20    }
21
22    pub async fn show_prompt(&self, query: &str) -> Result<Vec<crate::storage::Prompt>> {
23        let prompts = self.storage.load_prompts()?;
24        let search_results = search_prompts(&prompts, query, &[], &[]);
25        Ok(search_results)
26    }
27
28    pub async fn edit_prompt(&self, hash: &str, new_prompt: &mut crate::storage::Prompt) -> Result<()> {
29        self.storage.delete_prompt(hash)?;
30        self.storage.save_prompt(new_prompt)
31    }
32
33    pub async fn delete_prompt(&self, hash: &str) -> Result<()> {
34        self.storage.delete_prompt(hash)
35    }
36}
37
38pub fn search_prompts(prompts: &[crate::storage::Prompt], query: &str, tags: &[String], categories: &[String]) -> Vec<crate::storage::Prompt> {
39    let matcher = SkimMatcherV2::default();
40    prompts.iter().filter(|p| {
41        let content_match = query.is_empty() || matcher.fuzzy_match(&p.content, query).is_some();
42        let tags_match = tags.is_empty() || p.tags.as_ref().map_or(false, |ptags| {
43            tags.iter().all(|tag| ptags.contains(tag))
44        });
45        let categories_match = categories.is_empty() || p.categories.as_ref().map_or(false, |pcats| {
46            categories.iter().all(|cat| pcats.contains(cat))
47        });
48        content_match && tags_match && categories_match
49    }).cloned().collect()
50}