Skip to main content

wowlab_docgen_cli/context/
nav.rs

1use crate::RenderCtx;
2
3/// Build a breadcrumb navigation string from the context's relative directory.
4pub(super) fn build(ctx: &RenderCtx<'_>) -> String {
5    if ctx.is_root() {
6        return String::new();
7    }
8
9    let parts: Vec<&str> = ctx.rel_dir.split('/').filter(|s| !s.is_empty()).collect();
10
11    if parts.is_empty() {
12        return String::new();
13    }
14
15    let depth = parts.len();
16    let mut crumbs = vec![format!("[WoW Lab]({}README.md)", "../".repeat(depth))];
17
18    // #t(block: rust_unchecked_indexing) i is bounded by 0..depth-1 and parts.len() == depth
19    for i in 0..depth.saturating_sub(1) {
20        let readme_path = ctx.root.join(parts[..=i].join("/")).join("README.md");
21
22        if ctx.workspace.contains(&readme_path) {
23            let ups = "../".repeat(depth - i - 1);
24
25            // #t(rust_alloc_in_loop) each breadcrumb owns its rendered markdown link
26            crumbs.push(format!("[{}]({ups}README.md)", parts[i]));
27        }
28    }
29
30    crumbs.join(" \u{00b7} ")
31}
32
33#[cfg(test)]
34mod tests {
35    use googletest::prelude::*;
36    use wowlab_fs::path::Path;
37
38    use super::*;
39    use crate::{
40        WorkspaceFile, WorkspaceIndex,
41        infra::metadata::{Metadata, PackageKind},
42        test_helpers::workspace_at,
43    };
44
45    #[gtest]
46    fn root_returns_empty() -> Result<()> {
47        let meta = Metadata {
48            kind: PackageKind::Directory,
49            ..Default::default()
50        };
51        let ctx = RenderCtx {
52            workspace: workspace_at(Path::new("/ws")),
53            root: Path::new("/ws"),
54            dir: Path::new("/ws"),
55            rel_dir: ".",
56            metadata: &meta,
57            output_stem: "README",
58        };
59
60        verify_eq!(build(&ctx), "")
61    }
62
63    #[gtest]
64    fn depth_one_no_intermediate() -> Result<()> {
65        let meta = Metadata {
66            kind: PackageKind::Directory,
67            ..Default::default()
68        };
69        let ctx = RenderCtx {
70            workspace: workspace_at(Path::new("/nonexistent-ws")),
71            root: Path::new("/nonexistent-ws"),
72            dir: Path::new("/nonexistent-ws/deploy"),
73            rel_dir: "deploy",
74            metadata: &meta,
75            output_stem: "README",
76        };
77
78        verify_eq!(build(&ctx), "[WoW Lab](../README.md)")
79    }
80
81    #[gtest]
82    fn depth_two_with_intermediate() -> Result<()> {
83        let root = Path::new("/ws");
84        let dir = root.join("crates/sentinel");
85        let workspace = WorkspaceIndex::new(
86            root.to_path_buf(),
87            vec![WorkspaceFile {
88                path: root.join("crates/README.md"),
89                contents: Some(Box::from("# crates")),
90            }],
91        );
92        let meta = Metadata {
93            kind: PackageKind::Directory,
94            ..Default::default()
95        };
96        let ctx = RenderCtx {
97            workspace,
98            root,
99            dir: &dir,
100            rel_dir: "crates/sentinel",
101            metadata: &meta,
102            output_stem: "README",
103        };
104        let result = build(&ctx);
105
106        verify_that!(
107            result.as_str(),
108            contains_substring("[WoW Lab](../../README.md)")
109        )?;
110        verify_that!(
111            result.as_str(),
112            contains_substring("[crates](../README.md)")
113        )?;
114        verify_that!(result.as_str(), contains_substring("\u{00b7}"))?;
115
116        Ok(())
117    }
118
119    #[gtest]
120    fn depth_two_without_intermediate_readme() -> Result<()> {
121        let meta = Metadata {
122            kind: PackageKind::Directory,
123            ..Default::default()
124        };
125        let ctx = RenderCtx {
126            workspace: workspace_at(Path::new("/nonexistent-ws")),
127            root: Path::new("/nonexistent-ws"),
128            dir: Path::new("/nonexistent-ws/crates/sentinel"),
129            rel_dir: "crates/sentinel",
130            metadata: &meta,
131            output_stem: "README",
132        };
133
134        verify_eq!(build(&ctx), "[WoW Lab](../../README.md)")
135    }
136}