mdvault_core/domain/behaviors/
zettel.rs1use std::path::PathBuf;
8use std::sync::Arc;
9
10use crate::types::TypeDefinition;
11
12use super::super::context::{CreationContext, FieldPrompt, PromptContext};
13use super::super::traits::{
14 DomainResult, NoteBehavior, NoteIdentity, NoteLifecycle, NotePrompts,
15};
16
17pub struct ZettelBehavior {
19 typedef: Option<Arc<TypeDefinition>>,
20}
21
22impl ZettelBehavior {
23 pub fn new(typedef: Option<Arc<TypeDefinition>>) -> Self {
25 Self { typedef }
26 }
27}
28
29impl NoteIdentity for ZettelBehavior {
30 fn generate_id(&self, _ctx: &CreationContext) -> DomainResult<Option<String>> {
31 Ok(None)
33 }
34
35 fn output_path(&self, ctx: &CreationContext) -> DomainResult<PathBuf> {
36 if let Some(ref td) = self.typedef
38 && let Some(ref output) = td.output
39 {
40 return super::render_output_template(output, ctx);
41 }
42
43 let slug = slugify(&ctx.title);
45 Ok(ctx.config.vault_root.join(format!("zettels/{}.md", slug)))
46 }
47
48 fn core_fields(&self) -> Vec<&'static str> {
49 vec!["type", "title"]
50 }
51}
52
53impl NoteLifecycle for ZettelBehavior {
54 fn before_create(&self, _ctx: &mut CreationContext) -> DomainResult<()> {
55 Ok(())
57 }
58
59 fn after_create(&self, _ctx: &CreationContext, _content: &str) -> DomainResult<()> {
60 Ok(())
62 }
63}
64
65impl NotePrompts for ZettelBehavior {
66 fn type_prompts(&self, _ctx: &PromptContext) -> Vec<FieldPrompt> {
67 vec![] }
69}
70
71impl NoteBehavior for ZettelBehavior {
72 fn type_name(&self) -> &'static str {
73 "zettel"
74 }
75}
76
77fn slugify(s: &str) -> String {
79 let mut result = String::with_capacity(s.len());
80
81 for c in s.chars() {
82 if c.is_ascii_alphanumeric() {
83 result.push(c.to_ascii_lowercase());
84 } else if (c == ' ' || c == '_' || c == '-') && !result.ends_with('-') {
85 result.push('-');
86 }
87 }
88
89 result.trim_matches('-').to_string()
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn test_slugify() {
98 assert_eq!(slugify("Hello World"), "hello-world");
99 assert_eq!(slugify("My Cool Note!"), "my-cool-note");
100 assert_eq!(slugify(" spaced out "), "spaced-out");
101 assert_eq!(slugify("under_score"), "under-score");
102 }
103}