use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use anyhow::Result;
use std::collections::HashMap;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Entry {
pub id: String,
pub title: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub source: Option<String>,
pub tags: Vec<String>,
pub content_type: ContentType,
#[serde(default)]
pub metadata: HashMap<String, String>,
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub enum ContentType {
Code,
Text,
Script,
Other(String),
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Backpack {
pub name: String,
pub description: Option<String>,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Workflow {
pub name: String,
pub commands: Vec<WorkflowCommand>,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct WorkflowCommand {
pub command: String,
pub args: Vec<String>,
}
impl Entry {
pub fn new(title: String, content_type: ContentType, source: Option<String>, tags: Vec<String>) -> Self {
let now = Utc::now();
Self {
id: Uuid::new_v4().to_string(),
title,
created_at: now,
updated_at: now,
source,
tags,
content_type,
metadata: HashMap::new(),
}
}
pub fn add_metadata(&mut self, key: &str, value: &str) {
self.metadata.insert(key.to_string(), value.to_string());
}
pub fn get_metadata(&self, key: &str) -> Option<&str> {
self.metadata.get(key).map(|s| s.as_str())
}
}
impl Backpack {
pub fn new(name: String, description: Option<String>) -> Self {
Self {
name,
description,
created_at: Utc::now(),
}
}
}
impl Workflow {
pub fn new(name: String, commands: Vec<WorkflowCommand>) -> Self {
Self {
name,
commands,
created_at: Utc::now(),
}
}
}
impl WorkflowCommand {
pub fn parse(command_str: &str) -> Result<Self> {
let command_str = command_str.trim();
if command_str.is_empty() {
return Err(anyhow::anyhow!("Empty command"));
}
let parts: Vec<&str> = command_str.split_whitespace().collect();
Ok(Self {
command: parts[0].to_string(),
args: parts[1..].iter().map(|s| s.to_string()).collect(),
})
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
pub user: UserConfig,
pub display: DisplayConfig,
pub search: SearchConfig,
pub extensions: ExtensionConfig,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct UserConfig {
pub editor: String,
pub default_backpack: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DisplayConfig {
pub color: bool,
pub tree_style: TreeStyle,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SearchConfig {
pub algorithm: SearchAlgorithm,
pub max_results: usize,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ExtensionConfig {
pub auto_reload: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub enum TreeStyle {
Unicode,
Ascii,
Minimal,
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub enum SearchAlgorithm {
Semantic,
Literal,
}
impl Default for Config {
fn default() -> Self {
Self {
user: UserConfig {
editor: "vim".to_string(),
default_backpack: "general".to_string(),
},
display: DisplayConfig {
color: true,
tree_style: TreeStyle::Unicode,
},
search: SearchConfig {
algorithm: SearchAlgorithm::Semantic,
max_results: 10,
},
extensions: ExtensionConfig {
auto_reload: true,
},
}
}
}