Skip to main content

llmwiki_tooling/
page.rs

1use std::fmt;
2use std::ops::Range;
3use std::path::Path;
4
5/// Filename stem identifying a wiki page, normalized to lowercase for O(1) lookups.
6#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
7pub struct PageId(String);
8
9impl PageId {
10    pub fn from_path(path: &Path) -> Option<Self> {
11        path.file_stem()
12            .and_then(|s| s.to_str())
13            .map(|s| Self(s.to_ascii_lowercase()))
14    }
15
16    pub fn as_str(&self) -> &str {
17        &self.0
18    }
19}
20
21impl fmt::Display for PageId {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        f.write_str(&self.0)
24    }
25}
26
27impl From<&str> for PageId {
28    fn from(s: &str) -> Self {
29        Self(s.to_ascii_lowercase())
30    }
31}
32
33/// A block identifier without the `^` prefix, e.g. `"method-comparison"`.
34#[derive(Debug, Clone, PartialEq, Eq, Hash)]
35pub struct BlockId(String);
36
37impl BlockId {
38    pub fn as_str(&self) -> &str {
39        &self.0
40    }
41}
42
43impl From<&str> for BlockId {
44    fn from(s: &str) -> Self {
45        Self(s.to_owned())
46    }
47}
48
49/// Fragment part of a wikilink after `#`.
50#[derive(Debug, Clone, PartialEq, Eq)]
51pub enum WikilinkFragment {
52    /// `#heading-text`
53    Heading(String),
54    /// `#^block-id`
55    Block(BlockId),
56}
57
58/// A parsed wikilink occurrence with its source location.
59#[derive(Debug, Clone)]
60pub struct WikilinkOccurrence {
61    pub page: PageId,
62    pub fragment: Option<WikilinkFragment>,
63    pub is_embed: bool,
64    pub byte_range: Range<usize>,
65}
66
67/// A parsed heading from a markdown file.
68#[derive(Debug, Clone)]
69pub struct Heading {
70    pub level: u8,
71    pub text: String,
72    pub byte_range: Range<usize>,
73}