Skip to main content

archelon_core/
entry_ref.rs

1use std::path::PathBuf;
2
3use crate::{error::Result, journal::Journal};
4
5/// A reference to a journal entry — either a filesystem path or a CarettaId prefix.
6///
7/// This is the canonical input type for commands that operate on a single entry
8/// (show, fix, remove, etc.).  Parse raw user input with [`EntryRef::parse`], then
9/// resolve it to a concrete [`PathBuf`] with [`EntryRef::resolve`].
10#[derive(Debug, Clone)]
11pub enum EntryRef {
12    /// A filesystem path to the entry file.
13    Path(PathBuf),
14    /// A CarettaId prefix (1–7 characters).
15    Id(String),
16}
17
18impl EntryRef {
19    /// Classify a raw string as a path or an ID prefix.
20    ///
21    /// The string is treated as a **path** when it:
22    /// - contains a path separator (`/` or the platform separator), or
23    /// - starts with `.` or `~`, or
24    /// - ends with `.md`.
25    ///
26    /// Everything else is treated as a **CarettaId prefix**.
27    pub fn parse(s: &str) -> Self {
28        if s.contains('/')
29            || s.contains(std::path::MAIN_SEPARATOR)
30            || s.starts_with('.')
31            || s.ends_with(".md")
32        {
33            EntryRef::Path(PathBuf::from(s))
34        } else {
35            EntryRef::Id(s.to_owned())
36        }
37    }
38
39    /// Resolve this reference to a concrete file path.
40    ///
41    /// - `Path` variant: returns the stored path as-is.
42    /// - `Id` variant: delegates to [`Journal::find_entry_by_id`].
43    pub fn resolve(&self, journal: &Journal) -> Result<PathBuf> {
44        match self {
45            EntryRef::Path(p) => Ok(p.clone()),
46            EntryRef::Id(id) => journal.find_entry_by_id(id),
47        }
48    }
49}
50
51impl From<&str> for EntryRef {
52    fn from(s: &str) -> Self {
53        Self::parse(s)
54    }
55}
56
57impl From<String> for EntryRef {
58    fn from(s: String) -> Self {
59        Self::parse(&s)
60    }
61}