mdvault_core/context/
manager.rs1use std::fs;
4use std::path::{Path, PathBuf};
5
6use crate::context::types::{ContextState, FocusContext};
7
8#[derive(Debug, thiserror::Error)]
10pub enum ContextError {
11 #[error("Failed to read context state: {0}")]
12 Read(#[from] std::io::Error),
13
14 #[error("Failed to parse context state: {0}")]
15 Parse(#[from] toml::de::Error),
16
17 #[error("Failed to serialize context state: {0}")]
18 Serialize(#[from] toml::ser::Error),
19}
20
21type Result<T> = std::result::Result<T, ContextError>;
22
23#[derive(Debug)]
27pub struct ContextManager {
28 state_path: PathBuf,
30
31 state: ContextState,
33}
34
35impl ContextManager {
36 const STATE_DIR: &'static str = ".mdvault/state";
38 const STATE_FILE: &'static str = "context.toml";
39
40 pub fn load(vault_root: &Path) -> Result<Self> {
44 let state_dir = vault_root.join(Self::STATE_DIR);
45 let state_path = state_dir.join(Self::STATE_FILE);
46
47 let state = if state_path.exists() {
48 let content = fs::read_to_string(&state_path)?;
49 toml::from_str(&content)?
50 } else {
51 ContextState::default()
52 };
53
54 Ok(Self { state_path, state })
55 }
56
57 pub fn save(&self) -> Result<()> {
59 if let Some(parent) = self.state_path.parent() {
61 fs::create_dir_all(parent)?;
62 }
63
64 let content = toml::to_string_pretty(&self.state)?;
65 fs::write(&self.state_path, content)?;
66 Ok(())
67 }
68
69 pub fn set_focus(&mut self, project: &str) -> Result<()> {
73 self.state.focus = Some(FocusContext::new(project));
74 self.save()
75 }
76
77 pub fn set_focus_with_note(&mut self, project: &str, note: &str) -> Result<()> {
79 self.state.focus = Some(FocusContext::with_note(project, note));
80 self.save()
81 }
82
83 pub fn clear_focus(&mut self) -> Result<()> {
85 self.state.focus = None;
86 self.save()
87 }
88
89 pub fn active_project(&self) -> Option<&str> {
91 self.state.focus.as_ref().map(|f| f.project.as_str())
92 }
93
94 pub fn focus(&self) -> Option<&FocusContext> {
96 self.state.focus.as_ref()
97 }
98
99 pub fn state(&self) -> &ContextState {
101 &self.state
102 }
103
104 pub fn has_focus(&self) -> bool {
106 self.state.focus.is_some()
107 }
108}