c6o_obsidian_export/context.rs
1use crate::Frontmatter;
2use std::path::{Path, PathBuf};
3
4#[derive(Debug, Clone)]
5/// Context holds metadata about a note which is being parsed.
6///
7/// This is used internally to keep track of nesting and help with constructing proper references
8/// to other notes.
9///
10/// It is also passed to [postprocessors][crate::Postprocessor] to provide contextual information
11/// and allow modification of a note's frontmatter.
12pub struct Context {
13 file_tree: Vec<PathBuf>,
14
15 /// The path where this note will be written to when exported.
16 ///
17 /// Changing this path will result in the note being written to that new path instead, but
18 /// beware: links will not be updated automatically. If this is changed by a
19 /// [postprocessor][crate::Postprocessor], it's up to that postprocessor to rewrite any
20 /// existing links to this new path.
21 pub destination: PathBuf,
22
23 /// The [Frontmatter] for this note. Frontmatter may be modified in-place (see
24 /// [serde_yaml::Mapping] for available methods) or replaced entirely.
25 ///
26 /// # Example
27 ///
28 /// Insert `foo: bar` into a note's frontmatter:
29 ///
30 /// ```
31 /// # use obsidian_export::Frontmatter;
32 /// # use obsidian_export::Context;
33 /// # use std::path::PathBuf;
34 /// use obsidian_export::serde_yaml::Value;
35 ///
36 /// # let mut context = Context::new(PathBuf::from("source"), PathBuf::from("destination"));
37 /// let key = Value::String("foo".to_string());
38 ///
39 /// context.frontmatter.insert(
40 /// key.clone(),
41 /// Value::String("bar".to_string()),
42 /// );
43 /// ```
44 pub frontmatter: Frontmatter,
45}
46
47impl Context {
48 /// Create a new `Context`
49 pub fn new(src: PathBuf, dest: PathBuf) -> Context {
50 Context {
51 file_tree: vec![src],
52 destination: dest,
53 frontmatter: Frontmatter::new(),
54 }
55 }
56
57 /// Create a new `Context` which inherits from a parent Context.
58 pub fn from_parent(context: &Context, child: &Path) -> Context {
59 let mut context = context.clone();
60 context.file_tree.push(child.to_path_buf());
61 context
62 }
63
64 /// Return the path of the file currently being parsed.
65 pub fn current_file(&self) -> &PathBuf {
66 self.file_tree
67 .last()
68 .expect("Context not initialized properly, file_tree is empty")
69 }
70
71 /// Return the path of the root file.
72 ///
73 /// Typically this will yield the same element as `current_file`, but when a note is embedded
74 /// within another note, this will return the outer-most note.
75 pub fn root_file(&self) -> &PathBuf {
76 self.file_tree
77 .first()
78 .expect("Context not initialized properly, file_tree is empty")
79 }
80
81 /// Return the note depth (nesting level) for this context.
82 pub fn note_depth(&self) -> usize {
83 self.file_tree.len()
84 }
85
86 /// Return the list of files associated with this context.
87 ///
88 /// The first element corresponds to the root file, the final element corresponds to the file
89 /// which is currently being processed (see also `current_file`).
90 pub fn file_tree(&self) -> Vec<PathBuf> {
91 self.file_tree.clone()
92 }
93}