Skip to main content

vault_tasks_core/
vault_data.rs

1use std::{fmt::Display, path::PathBuf};
2
3use format_utils::{write_indent, write_underline_with_indent};
4
5use super::task::Task;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8/// A node in the vault data structure, representing either a vault, directory, or file.
9pub enum VaultNode {
10    Vault {
11        name: String,
12        path: PathBuf,
13        content: Vec<VaultNode>,
14    },
15    Directory {
16        name: String,
17        path: PathBuf,
18        content: Vec<VaultNode>,
19    },
20    File {
21        name: String,
22        path: PathBuf,
23        content: Vec<FileEntryNode>,
24    },
25}
26impl Display for VaultNode {
27    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28        fn fmt_node_rec(
29            node: &VaultNode,
30            f: &mut std::fmt::Formatter,
31            depth: usize,
32        ) -> std::fmt::Result {
33            match node {
34                VaultNode::Vault { name, content, .. }
35                | VaultNode::Directory { name, content, .. } => {
36                    write_underline_with_indent(&name.to_string(), depth, f)?;
37                    for entry in content {
38                        fmt_node_rec(entry, f, depth + 1)?;
39                    }
40                }
41                VaultNode::File { name, content, .. } => {
42                    write_underline_with_indent(&name.to_string(), depth, f)?;
43                    for entry in content {
44                        // Use NewFileEntry's fmt_with_depth to format with proper indentation
45                        entry.fmt_with_depth(f, depth + 1)?;
46                    }
47                }
48            }
49            Ok(())
50        }
51        fmt_node_rec(self, f, 0)
52    }
53}
54
55#[derive(Debug, Clone, PartialEq, Eq)]
56/// An entry in a file, representing either a header or task.
57pub enum FileEntryNode {
58    Header {
59        /// Content of the header
60        name: String,
61        /// Path to the file it belongs to
62        path: PathBuf,
63        /// Heading levels (###)
64        heading_level: usize,
65        /// Children
66        content: Vec<FileEntryNode>,
67    },
68    Task(Task),
69}
70
71impl FileEntryNode {
72    pub(crate) fn fmt_with_depth(
73        &self,
74        f: &mut std::fmt::Formatter,
75        depth: usize,
76    ) -> std::fmt::Result {
77        match self {
78            FileEntryNode::Header {
79                name,
80                heading_level: _,
81                path: _,
82                content,
83            } => {
84                write_underline_with_indent(name, depth, f)?;
85                for entry in content {
86                    entry.fmt_with_depth(f, depth + 1)?;
87                }
88            }
89            FileEntryNode::Task(task) => {
90                for line in task.to_string().replace('\r', "").split('\n') {
91                    write_indent(depth, f)?;
92                    writeln!(f, "{line}")?;
93                }
94                for subtask in &task.subtasks {
95                    for line in (FileEntryNode::Task(subtask.clone()))
96                        .to_string()
97                        .split('\n')
98                    {
99                        write_indent(depth + 1, f)?;
100                        writeln!(f, "{line}")?;
101                    }
102                }
103            }
104        }
105        Ok(())
106    }
107}
108
109impl Display for FileEntryNode {
110    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111        self.fmt_with_depth(f, 0)
112    }
113}
114#[derive(Debug, Clone, PartialEq, Eq)]
115pub struct Vaults {
116    pub root: Vec<VaultNode>,
117}
118
119impl Vaults {
120    #[must_use]
121    pub fn new(root: Vec<VaultNode>) -> Self {
122        Self { root }
123    }
124    #[must_use]
125    pub fn empty() -> Self {
126        Self { root: vec![] }
127    }
128}
129
130impl Display for Vaults {
131    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132        for vault in &self.root {
133            writeln!(f, "{vault}")?;
134        }
135        Ok(())
136    }
137}
138mod format_utils {
139    pub fn write_indent(indent_length: usize, f: &mut std::fmt::Formatter) -> std::fmt::Result {
140        (1..=indent_length).try_for_each(|_| write!(f, "\t"))?;
141        Ok(())
142    }
143    pub fn write_underline_with_indent(
144        text: &str,
145        indent_length: usize,
146        f: &mut std::fmt::Formatter,
147    ) -> std::fmt::Result {
148        write_indent(indent_length, f)?;
149        writeln!(f, "{text}")?;
150        write_indent(indent_length, f)?;
151        for _i in 0..(text.len()) {
152            write!(f, "‾")?;
153        }
154        writeln!(f)?;
155        Ok(())
156    }
157}