1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4use anyhow::Result;
5use std::collections::HashMap;
6
7#[derive(Debug, Serialize, Deserialize, Clone)]
9pub struct Entry {
10 pub id: String,
12
13 pub title: String,
15
16 pub created_at: DateTime<Utc>,
18
19 pub updated_at: DateTime<Utc>,
21
22 pub source: Option<String>,
24
25 pub tags: Vec<String>,
27
28 pub content_type: ContentType,
30
31 #[serde(default)]
33 pub metadata: HashMap<String, String>,
34}
35
36#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
38pub enum ContentType {
39 Code,
40 Text,
41 Script,
42 Other(String),
43}
44
45#[derive(Debug, Serialize, Deserialize, Clone)]
47pub struct Backpack {
48 pub name: String,
50
51 pub description: Option<String>,
53
54 pub created_at: DateTime<Utc>,
56}
57
58#[derive(Debug, Serialize, Deserialize, Clone)]
60pub struct Workflow {
61 pub name: String,
63
64 pub commands: Vec<WorkflowCommand>,
66
67 pub created_at: DateTime<Utc>,
69}
70
71#[derive(Debug, Serialize, Deserialize, Clone)]
73pub struct WorkflowCommand {
74 pub command: String,
76
77 pub args: Vec<String>,
79}
80
81impl Entry {
82 pub fn new(title: String, content_type: ContentType, source: Option<String>, tags: Vec<String>) -> Self {
84 let now = Utc::now();
85 Self {
86 id: Uuid::new_v4().to_string(),
87 title,
88 created_at: now,
89 updated_at: now,
90 source,
91 tags,
92 content_type,
93 metadata: HashMap::new(),
94 }
95 }
96
97 pub fn add_metadata(&mut self, key: &str, value: &str) {
99 self.metadata.insert(key.to_string(), value.to_string());
100 }
101
102 pub fn get_metadata(&self, key: &str) -> Option<&str> {
104 self.metadata.get(key).map(|s| s.as_str())
105 }
106}
107
108impl Backpack {
109 pub fn new(name: String, description: Option<String>) -> Self {
111 Self {
112 name,
113 description,
114 created_at: Utc::now(),
115 }
116 }
117}
118
119impl Workflow {
120 pub fn new(name: String, commands: Vec<WorkflowCommand>) -> Self {
122 Self {
123 name,
124 commands,
125 created_at: Utc::now(),
126 }
127 }
128}
129
130impl WorkflowCommand {
131 pub fn parse(command_str: &str) -> Result<Self> {
133 let command_str = command_str.trim();
134 if command_str.is_empty() {
135 return Err(anyhow::anyhow!("Empty command"));
136 }
137
138 let parts: Vec<&str> = command_str.split_whitespace().collect();
139
140 Ok(Self {
141 command: parts[0].to_string(),
142 args: parts[1..].iter().map(|s| s.to_string()).collect(),
143 })
144 }
145}
146
147#[derive(Debug, Serialize, Deserialize)]
149pub struct Config {
150 pub user: UserConfig,
152
153 pub display: DisplayConfig,
155
156 pub search: SearchConfig,
158
159 pub extensions: ExtensionConfig,
161}
162
163#[derive(Debug, Serialize, Deserialize)]
165pub struct UserConfig {
166 pub editor: String,
168
169 pub default_backpack: String,
171}
172
173#[derive(Debug, Serialize, Deserialize)]
175pub struct DisplayConfig {
176 pub color: bool,
178
179 pub tree_style: TreeStyle,
181}
182
183#[derive(Debug, Serialize, Deserialize)]
185pub struct SearchConfig {
186 pub algorithm: SearchAlgorithm,
188
189 pub max_results: usize,
191}
192
193#[derive(Debug, Serialize, Deserialize)]
195pub struct ExtensionConfig {
196 pub auto_reload: bool,
198}
199
200#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
202pub enum TreeStyle {
203 Unicode,
204 Ascii,
205 Minimal,
206}
207
208#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
210pub enum SearchAlgorithm {
211 Semantic,
212 Literal,
213}
214
215impl Default for Config {
216 fn default() -> Self {
217 Self {
218 user: UserConfig {
219 editor: "vim".to_string(),
220 default_backpack: "general".to_string(),
221 },
222 display: DisplayConfig {
223 color: true,
224 tree_style: TreeStyle::Unicode,
225 },
226 search: SearchConfig {
227 algorithm: SearchAlgorithm::Semantic,
228 max_results: 10,
229 },
230 extensions: ExtensionConfig {
231 auto_reload: true,
232 },
233 }
234 }
235}