pub struct NoteVault { /* private fields */ }Expand description
Facade over a vault: a directory of Markdown notes plus its searchable index. Cheap to clone — clones share the index pool and per-note locks.
Implementations§
Source§impl NoteVault
impl NoteVault
Sourcepub async fn new(config: VaultConfig) -> Result<Self, VaultError>
pub async fn new(config: VaultConfig) -> Result<Self, VaultError>
Creates a new instance of the Note Vault.
Make sure you call NoteVault::validate_and_init(&self) to initialize the DB index if
needed.
Sourcepub fn workspace_path(&self) -> &Path
pub fn workspace_path(&self) -> &Path
OS path to the workspace root (filesystem root of this vault).
Sourcepub fn index_ready(&self) -> bool
pub fn index_ready(&self) -> bool
false when opening the vault self-healed the index schema (missing,
outdated, or invalid), meaning the index is valid but
empty until a sync pass (validate_and_init)
fills it. Fast paths use this to refuse to operate against an empty
index without paying for a sync.
Sourcepub async fn validate_and_init(&self) -> Result<IndexReport, VaultError>
pub async fn validate_and_init(&self) -> Result<IndexReport, VaultError>
Brings the index in step with the vault on disk. Opening the vault already self-healed the index schema, so all that remains is a sync pass: a quick existence scan when the index was already current, or a full scan when it was just healed (and is thus empty). This can be slow on large vaults.
Sourcepub async fn recreate_index(&self) -> Result<IndexReport, VaultError>
pub async fn recreate_index(&self) -> Result<IndexReport, VaultError>
Deletes all the cached data from the index by recreating its schema, then rebuilds it with a full sync pass.
Sourcepub async fn index_notes(
&self,
validation_mode: NotesValidation,
) -> Result<IndexReport, VaultError>
pub async fn index_notes( &self, validation_mode: NotesValidation, ) -> Result<IndexReport, VaultError>
Traverses the whole vault directory and verifies the notes to update the cached data in the DB. The validation is defined by the validation mode:
NotesValidation::Full Checks the content of the note by comparing a hash based on the text conatined in the file. NotesValidation::Fast Checks the size of the file to identify if the note has changed and then update the DB entry. NotesValidation::None Checks if the note exists or not.
Sourcepub async fn exists(&self, path: &VaultPath) -> bool
pub async fn exists(&self, path: &VaultPath) -> bool
Returns true if the path resolves to anything (note, directory, attachment) on disk. Cheaper than loading the full entry when only existence matters.
Sourcepub fn journal_path(&self) -> &VaultPath
pub fn journal_path(&self) -> &VaultPath
Directory under which journal entries are created.
Sourcepub fn inbox_path(&self) -> &VaultPath
pub fn inbox_path(&self) -> &VaultPath
Directory under which quick-capture notes are created.
Sourcepub fn set_inbox_path(&mut self, path: VaultPath)
pub fn set_inbox_path(&mut self, path: VaultPath)
Overrides the inbox directory used by Self::quick_note.
Sourcepub async fn quick_note(&self, text: &str) -> Result<NoteDetails, VaultError>
pub async fn quick_note(&self, text: &str) -> Result<NoteDetails, VaultError>
Creates a timestamped note under the inbox directory. On name collision
(including TOCTOU between the in-memory probe and the FS create), tries
the next suffix up to -99. The retry loop calls create_note
directly so each iteration’s existence check is the atomic
O_EXCL open inside nfs::create_note_exclusive.
Sourcepub async fn journal_entry(
&self,
) -> Result<(NoteDetails, String, bool), VaultError>
pub async fn journal_entry( &self, ) -> Result<(NoteDetails, String, bool), VaultError>
Loads today’s journal entry, creating it with a date heading if it does
not exist yet. Returns the note details, its content, and true when the
entry was freshly created.
Sourcepub fn journal_date(&self, note_path: &VaultPath) -> Option<NaiveDate>
pub fn journal_date(&self, note_path: &VaultPath) -> Option<NaiveDate>
Parses the date out of a journal note path, or None when note_path
is not a YYYY-MM-DD note directly under the journal directory.
Sourcepub async fn load_or_create_note(
&self,
path: &VaultPath,
default_text: Option<String>,
) -> Result<(String, bool), VaultError>
pub async fn load_or_create_note( &self, path: &VaultPath, default_text: Option<String>, ) -> Result<(String, bool), VaultError>
Loads the note at path if it exists; otherwise creates it with default_text
(or empty if None) and returns that text.
Returns the note’s text and true when the note had to be created (it
did not exist yet), so callers can react to a fresh note — e.g. refresh
a directory listing.
Sourcepub async fn get_note_text(
&self,
path: &VaultPath,
) -> Result<String, VaultError>
pub async fn get_note_text( &self, path: &VaultPath, ) -> Result<String, VaultError>
Loads the raw text of the note at path.
When the file doesn’t exist you get a VaultError::FSError wrapping
FSError::NotePathNotFound; you can branch on that to lazily create a
note, or use Self::load_or_create_note instead.
Sourcepub async fn load_note(
&self,
path: &VaultPath,
) -> Result<NoteDetails, VaultError>
pub async fn load_note( &self, path: &VaultPath, ) -> Result<NoteDetails, VaultError>
Loads a note as NoteDetails, carrying its path, raw text, and parsed
metadata.
Missing-file behaviour matches Self::get_note_text.
Sourcepub async fn get_note_chunks(
&self,
path: &VaultPath,
) -> Result<HashMap<VaultPath, Vec<ContentChunk>>, VaultError>
pub async fn get_note_chunks( &self, path: &VaultPath, ) -> Result<HashMap<VaultPath, Vec<ContentChunk>>, VaultError>
Returns the indexed content chunks for the note at path, keyed by the
note path they belong to.
Sourcepub async fn search_notes<S: AsRef<str>>(
&self,
search_query: S,
) -> Result<Vec<(NoteEntryData, NoteContentData)>, VaultError>
pub async fn search_notes<S: AsRef<str>>( &self, search_query: S, ) -> Result<Vec<(NoteEntryData, NoteContentData)>, VaultError>
Searches notes using the vault’s query syntax (see SearchTerms).
Returns each matching note’s entry and content data.
Sourcepub async fn list_labels(&self) -> Result<Vec<String>, VaultError>
pub async fn list_labels(&self) -> Result<Vec<String>, VaultError>
Returns every distinct label persisted in the vault, lowercased.
Sourcepub async fn suggest_notes_by_prefix(
&self,
prefix: &str,
limit: usize,
) -> Result<Vec<NoteSuggestion>, VaultError>
pub async fn suggest_notes_by_prefix( &self, prefix: &str, limit: usize, ) -> Result<Vec<NoteSuggestion>, VaultError>
Returns notes whose name (filename without extension) starts with
prefix, case-insensitive, capped at limit. Used to feed the
wikilink autocomplete popup — note that the inserted wikilink target
is the name field, not the path.
Returns tag labels matching prefix (case-insensitive) paired with
usage counts, capped at limit. Used to feed the hashtag autocomplete
popup in both the editor and the search box.
Sourcepub async fn label_counts(&self) -> Result<Vec<(String, usize)>, VaultError>
pub async fn label_counts(&self) -> Result<Vec<(String, usize)>, VaultError>
Returns every distinct label in the vault paired with the number of notes carrying it. Labels are returned sorted alphabetically.
Sourcepub async fn notes_with_label<S: AsRef<str>>(
&self,
name: S,
) -> Result<Vec<VaultPath>, VaultError>
pub async fn notes_with_label<S: AsRef<str>>( &self, name: S, ) -> Result<Vec<VaultPath>, VaultError>
Returns every note path that carries the given label. The label argument is lowercased before lookup, matching how labels are stored.
Sourcepub async fn get_notes(
&self,
path: &VaultPath,
recursive: bool,
) -> Result<Vec<(NoteEntryData, NoteContentData)>, VaultError>
pub async fn get_notes( &self, path: &VaultPath, recursive: bool, ) -> Result<Vec<(NoteEntryData, NoteContentData)>, VaultError>
Get notes under the given path. When recursive is false, only direct
children are returned.
Sourcepub async fn get_all_notes(
&self,
) -> Result<Vec<(NoteEntryData, NoteContentData)>, VaultError>
pub async fn get_all_notes( &self, ) -> Result<Vec<(NoteEntryData, NoteContentData)>, VaultError>
Returns every note in the vault with its entry and content data.
Sourcepub fn path_to_pathbuf(&self, path: &VaultPath) -> PathBuf
pub fn path_to_pathbuf(&self, path: &VaultPath) -> PathBuf
Resolves a vault path to its real OS filesystem location under the workspace root.
Sourcepub async fn browse_vault(
&self,
options: VaultBrowseOptions,
) -> Result<(), VaultError>
pub async fn browse_vault( &self, options: VaultBrowseOptions, ) -> Result<(), VaultError>
Walks the vault per options, streaming each entry as a
SearchResult through the channel set up by
VaultBrowseOptionsBuilder::build. A recursive browse from the root
doubles as a full index sync.
Sourcepub fn get_directories(
&self,
path: &VaultPath,
recursive: bool,
) -> Result<Vec<DirectoryDetails>, VaultError>
pub fn get_directories( &self, path: &VaultPath, recursive: bool, ) -> Result<Vec<DirectoryDetails>, VaultError>
Returns all subdirectories under path.
Non-recursive returns only the immediate children; recursive returns the full tree.
Sourcepub async fn get_markdown_and_links(
&self,
path: &VaultPath,
) -> Result<MarkdownNote, VaultError>
pub async fn get_markdown_and_links( &self, path: &VaultPath, ) -> Result<MarkdownNote, VaultError>
Converts a note’s raw Markdown into rendered Markdown and extracts all links.
- WikiLinks (
[[note]]) are converted to standard Markdown links. - Note links are resolved to vault-relative absolute paths.
- Hashtags become Markdown links (
[#tag](#tag)) and are added to the links list. - Image paths are resolved to absolute OS paths so renderers can load them directly. Relative image paths are resolved against the note’s location in the vault. External image URLs are kept as-is.
Sourcepub async fn get_backlinks(
&self,
path: &VaultPath,
) -> Result<Vec<(NoteEntryData, NoteContentData)>, VaultError>
pub async fn get_backlinks( &self, path: &VaultPath, ) -> Result<Vec<(NoteEntryData, NoteContentData)>, VaultError>
Returns all notes that contain a link pointing to path.
Matches both absolute vault paths and bare filename links (wikilinks).
Sourcepub async fn list_saved_searches(&self) -> Result<Vec<SavedSearch>, VaultError>
pub async fn list_saved_searches(&self) -> Result<Vec<SavedSearch>, VaultError>
List the vault’s saved searches (see SavedSearch). Empty if none.
Sourcepub async fn suggest_saved_searches_by_prefix(
&self,
prefix: &str,
limit: usize,
) -> Result<Vec<SavedSearch>, VaultError>
pub async fn suggest_saved_searches_by_prefix( &self, prefix: &str, limit: usize, ) -> Result<Vec<SavedSearch>, VaultError>
Saved searches whose name starts with prefix (case-insensitive,
ASCII folding to match Self::save_search/Self::delete_saved_search), in
stored order, capped at limit. Feeds the ?-prefix autocomplete in
the query input — mirrors Self::suggest_notes_by_prefix /
Self::suggest_tags_by_prefix so prefix matching stays in core. Saved
searches are file-backed (not indexed), so this reads the small TOML
file; it is the single place to add caching if it ever gets hot.
Sourcepub async fn save_search(
&self,
name: &str,
query: &str,
) -> Result<(), VaultError>
pub async fn save_search( &self, name: &str, query: &str, ) -> Result<(), VaultError>
Insert or replace a saved search by name (case-insensitive match, preserving the existing position on overwrite). Appends if new.
Sourcepub async fn delete_saved_search(&self, name: &str) -> Result<(), VaultError>
pub async fn delete_saved_search(&self, name: &str) -> Result<(), VaultError>
Delete a saved search by name (case-insensitive). No-op if absent.
Sourcepub async fn rename_saved_search(
&self,
old: &str,
new: &str,
) -> Result<(), VaultError>
pub async fn rename_saved_search( &self, old: &str, new: &str, ) -> Result<(), VaultError>
Rename a saved search, preserving its position and query. No-op if absent.
Sourcepub async fn create_note<S: AsRef<str>>(
&self,
path: &VaultPath,
text: S,
) -> Result<(NoteEntryData, NoteContentData), VaultError>
pub async fn create_note<S: AsRef<str>>( &self, path: &VaultPath, text: S, ) -> Result<(NoteEntryData, NoteContentData), VaultError>
Creates a new note at path with text, failing with
VaultError::NoteExists if a note is already there. The create is
exclusive (atomic O_EXCL), so it never clobbers an existing file.
The new note is indexed before returning.
Sourcepub async fn create_directory(
&self,
path: &VaultPath,
) -> Result<DirectoryEntryData, VaultError>
pub async fn create_directory( &self, path: &VaultPath, ) -> Result<DirectoryEntryData, VaultError>
Creates a directory at path, failing with
VaultError::DirectoryExists if one is already there.
Sourcepub async fn append_to_note(
&self,
path: &VaultPath,
text: &str,
default: Option<String>,
) -> Result<(), VaultError>
pub async fn append_to_note( &self, path: &VaultPath, text: &str, default: Option<String>, ) -> Result<(), VaultError>
Appends text to the note at path, creating it (with default
content) when absent. The read and the write run under the per-note lock
so concurrent appends to the same note can’t lose an update.
Sourcepub async fn save_note<S: AsRef<str>>(
&self,
path: &VaultPath,
text: S,
) -> Result<(NoteEntryData, NoteContentData), VaultError>
pub async fn save_note<S: AsRef<str>>( &self, path: &VaultPath, text: S, ) -> Result<(NoteEntryData, NoteContentData), VaultError>
Writes text to the note at path, overwriting any existing content
(backing it up first when backups are enabled), and re-indexes the note.
Serialized per note via the per-note write lock.
Sourcepub fn default_attachments_path(&self) -> VaultPath
pub fn default_attachments_path(&self) -> VaultPath
Default attachments directory (e.g. /assets) inside the workspace.
Sourcepub fn generate_attachment_path(&self, prefix: &str, ext: &str) -> VaultPath
pub fn generate_attachment_path(&self, prefix: &str, ext: &str) -> VaultPath
Builds a candidate path for a new attachment under
Self::default_attachments_path, using prefix and ext plus the current
unix-nanosecond timestamp for uniqueness. Nanoseconds (rather than
millis) make same-instant collisions vanishingly unlikely for
human-driven actions like clipboard paste.
Does not check for collisions; callers that need stronger uniqueness
guarantees should retry with Self::exists or use a different strategy.
Sourcepub async fn save_attachment(
&self,
path: &VaultPath,
bytes: &[u8],
) -> Result<(), VaultError>
pub async fn save_attachment( &self, path: &VaultPath, bytes: &[u8], ) -> Result<(), VaultError>
Writes an attachment (raw bytes — e.g. an encoded PNG) to path under
the workspace. Creates parent directories as needed. The attachment is
not added to the notes index.
Sourcepub async fn open_or_search(
&self,
path: &VaultPath,
) -> Result<Vec<(NoteEntryData, NoteContentData)>, VaultError>
pub async fn open_or_search( &self, path: &VaultPath, ) -> Result<Vec<(NoteEntryData, NoteContentData)>, VaultError>
If the path looks like a specific note (has the note extension), search by name; otherwise treat it as a directory/path query that may return many results.
Sourcepub async fn delete_note(&self, path: &VaultPath) -> Result<(), VaultError>
pub async fn delete_note(&self, path: &VaultPath) -> Result<(), VaultError>
Deletes the note at path (backing it up first when backups are
enabled). The index row is removed before the file, so the index never
points at a missing file.
Sourcepub async fn replace_in_note(
&self,
path: &VaultPath,
pattern: &str,
replacement: &str,
all: bool,
regex: bool,
) -> Result<usize, VaultError>
pub async fn replace_in_note( &self, path: &VaultPath, pattern: &str, replacement: &str, all: bool, regex: bool, ) -> Result<usize, VaultError>
Replaces occurrences of pattern with replacement in the note at
path, writing the result. See compute_replacement for the matching
rules (literal vs regex, unique-unless-all, capture references).
Returns the number of replacements made.
Sourcepub async fn preview_replace(
&self,
path: &VaultPath,
pattern: &str,
replacement: &str,
all: bool,
regex: bool,
) -> Result<ReplacePreview, VaultError>
pub async fn preview_replace( &self, path: &VaultPath, pattern: &str, replacement: &str, all: bool, regex: bool, ) -> Result<ReplacePreview, VaultError>
Dry-run of Self::replace_in_note: computes what the note would contain after
the replacement without writing (and without taking the write lock —
the result is advisory). Returns the same errors the real replace would
(not found / not unique / invalid regex).
Sourcepub async fn delete_directory(&self, path: &VaultPath) -> Result<(), VaultError>
pub async fn delete_directory(&self, path: &VaultPath) -> Result<(), VaultError>
Deletes the directory at path and its contents, removing the
corresponding index rows first.
Sourcepub async fn rename_note(
&self,
from: &VaultPath,
to: &VaultPath,
) -> Result<(), VaultError>
pub async fn rename_note( &self, from: &VaultPath, to: &VaultPath, ) -> Result<(), VaultError>
Renames the note from to to, rewriting links to it (wikilinks,
Markdown links, and the note’s own self-links) in every backlinking note
so they keep pointing at the renamed note. Fails if to already exists.
Source, destination, and all link victims are locked for the whole
operation so a concurrent in-process write can’t interleave.
Sourcepub async fn rename_directory(
&self,
from: &VaultPath,
to: &VaultPath,
) -> Result<(), VaultError>
pub async fn rename_directory( &self, from: &VaultPath, to: &VaultPath, ) -> Result<(), VaultError>
Renames the directory from to to, updating the index paths of all
notes beneath it. Fails if to already exists.
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for NoteVault
impl !UnwindSafe for NoteVault
impl Freeze for NoteVault
impl Send for NoteVault
impl Sync for NoteVault
impl Unpin for NoteVault
impl UnsafeUnpin for NoteVault
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more