basalt_core/obsidian.rs
1//! This module provides functionality operating with Obsidian. It lets you read and manipulate
2//! Obsidian's configuration, vaults, and notes.
3//!
4//! Currently supports reading vaults and notes within the vault.
5//!
6//! # Example
7//!
8//! ```
9//! use basalt_core::obsidian::{ObsidianConfig, Error, Vault};
10//!
11//! let config = ObsidianConfig::from([
12//! ("Obsidian", Vault::default()),
13//! ("My Vault", Vault::default()),
14//! ]);
15//! ```
16use std::{io, path::PathBuf, result};
17
18pub mod config;
19pub mod note;
20pub mod vault;
21mod vault_entry;
22
23pub use config::ObsidianConfig;
24pub use note::Note;
25pub use vault::*;
26pub use vault_entry::FindNote;
27pub use vault_entry::VaultEntry;
28
29/// A [`std::result::Result`] type for fallible operations in [`crate::obsidian`].
30///
31/// For convenience of use and to avoid writing [`Error`] directly.
32/// All fallible operations return [`Error`] as the error variant.
33///
34/// # Examples
35///
36/// ```
37/// use std::path::Path;
38/// use basalt_core::obsidian;
39///
40/// let config_result = obsidian::config::load_from(Path::new("./nonexistent"));
41/// assert_eq!(config_result.is_err(), true);
42/// ```
43pub type Result<T> = result::Result<T, Error>;
44
45/// Error type for fallible operations in this [`crate`].
46///
47/// Implements [`std::error::Error`] via [thiserror](https://docs.rs/thiserror).
48#[derive(thiserror::Error, Debug)]
49pub enum Error {
50 /// Expected resource behind a path was not found.
51 #[error("Path not found: {0}")]
52 PathNotFound(String),
53
54 /// Filename was empty
55 #[error("Empty filename for path: {0}")]
56 EmptyFileName(PathBuf),
57
58 /// JSON (de)serialization error, from [`serde_json::Error`].
59 #[error("JSON (de)serialization error: {0}")]
60 Json(#[from] serde_json::Error),
61
62 /// I/O error, from [`std::io::Error`].
63 #[error("I/O error: {0}")]
64 Io(#[from] io::Error),
65
66 /// Exceeded maximum attempts while searching for an available note name.
67 ///
68 /// This occurs when creating a note with a name that already exists, and all
69 /// numbered variants (e.g., "Name 1", "Name 2", ..., "Name 999") also exist.
70 #[error("Failed to find available name for '{name}' after {max_attempts} attempts")]
71 MaxAttemptsExceeded {
72 /// The base name that was attempted
73 name: String,
74 /// The maximum number of attempts made
75 max_attempts: usize,
76 },
77}