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        name: String,
60        heading_level: usize,
61        content: Vec<FileEntryNode>,
62    },
63    Task(Task),
64}
65
66impl FileEntryNode {
67    pub(crate) fn fmt_with_depth(
68        &self,
69        f: &mut std::fmt::Formatter,
70        depth: usize,
71    ) -> std::fmt::Result {
72        match self {
73            FileEntryNode::Header {
74                name,
75                heading_level: _,
76                content,
77            } => {
78                write_underline_with_indent(name, depth, f)?;
79                for entry in content {
80                    entry.fmt_with_depth(f, depth + 1)?;
81                }
82            }
83            FileEntryNode::Task(task) => {
84                for line in task.to_string().replace('\r', "").split('\n') {
85                    write_indent(depth, f)?;
86                    writeln!(f, "{line}")?;
87                }
88                for subtask in &task.subtasks {
89                    for line in (FileEntryNode::Task(subtask.clone()))
90                        .to_string()
91                        .split('\n')
92                    {
93                        write_indent(depth + 1, f)?;
94                        writeln!(f, "{line}")?;
95                    }
96                }
97            }
98        }
99        Ok(())
100    }
101}
102
103impl Display for FileEntryNode {
104    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105        self.fmt_with_depth(f, 0)
106    }
107}
108#[derive(Debug, Clone, PartialEq, Eq)]
109pub struct Vaults {
110    pub root: Vec<VaultNode>,
111}
112
113impl Vaults {
114    #[must_use]
115    pub fn new(root: Vec<VaultNode>) -> Self {
116        Self { root }
117    }
118    #[must_use]
119    pub fn empty() -> Self {
120        Self { root: vec![] }
121    }
122}
123
124impl Display for Vaults {
125    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126        for vault in &self.root {
127            writeln!(f, "{vault}")?;
128        }
129        Ok(())
130    }
131}
132mod format_utils {
133    pub fn write_indent(indent_length: usize, f: &mut std::fmt::Formatter) -> std::fmt::Result {
134        (1..=indent_length).try_for_each(|_| write!(f, "\t"))?;
135        Ok(())
136    }
137    pub fn write_underline_with_indent(
138        text: &str,
139        indent_length: usize,
140        f: &mut std::fmt::Formatter,
141    ) -> std::fmt::Result {
142        write_indent(indent_length, f)?;
143        writeln!(f, "{text}")?;
144        write_indent(indent_length, f)?;
145        for _i in 0..(text.len()) {
146            write!(f, "‾")?;
147        }
148        writeln!(f)?;
149        Ok(())
150    }
151}