krz/orgo

Lightning fast org-mode static site generator. fast go org-mode static-site-generator

Commit c8890b8d94

c8890b8d94eed450f4f906b95a19447ea3cbc87c

parent: e1ffd4eb2d

Verified · cmc ci/pages: success ci/test: success

cmc <hello@cleberg.net> · 2026-10-21 05:58 UTC

Resolve links inside special blocks and captions

The resolver skipped SpecialBlock content and figure/table captions, so
file: links there kept their source paths and broken ones were not
reported.

Closes #5

Layout: unified · split

src/resolve.rs +3
@@ -106,6 +106,7 @@ impl Cx<'_> {
106106 }
107107 }
108108 Element::Table(table) => {
109 self.objects(&mut table.caption);
109110 for row in &mut table.rows {
110111 if let TableRow::Cells(cells) = row {
111112 for cell in cells {
@@ -114,8 +115,10 @@ impl Cx<'_> {
114115 }
115116 }
116117 }
118 Element::Figure { caption, .. } => self.objects(caption),
117119 Element::QuoteBlock(inner)
118120 | Element::CenterBlock(inner)
121 | Element::SpecialBlock { content: inner, .. }
119122 | Element::Drawer { content: inner, .. }
120123 | Element::FootnoteDefinition { content: inner, .. } => {
121124 for e in inner {
tests/site.rs +36
@@ -205,3 +205,39 @@ fn colliding_slugs_are_a_build_error() {
205205 );
206206 std::fs::remove_dir_all(&dir).unwrap();
207207}
208
209/// Links nested in a block are resolved and checked like links in a paragraph.
210#[test]
211fn links_inside_blocks_resolve_and_are_checked() {
212 let dir = std::env::temp_dir().join(format!("orgo-blocks-{}", std::process::id()));
213 let dir = Utf8PathBuf::from_path_buf(dir).expect("utf-8 temp dir");
214 let _ = std::fs::remove_dir_all(&dir);
215 std::fs::create_dir_all(&dir).unwrap();
216 std::fs::write(dir.join("target.org"), "#+TITLE: T\n#+SLUG: slugged\n").unwrap();
217 std::fs::write(
218 dir.join("index.org"),
219 "#+TITLE: I\n\n\
220 #+begin_seealso\n[[file:target.org][special]]\n#+end_seealso\n\n\
221 #+begin_quote\n[[file:target.org][quote]]\n#+end_quote\n\n\
222 #+begin_center\n[[file:target.org][center]]\n#+end_center\n\n\
223 #+CAPTION: [[file:target.org][figure]]\n[[file:pic.png]]\n\n\
224 #+CAPTION: [[file:target.org][table]]\n| a |\n\n\
225 #+begin_note\n[[file:missing.org][gone]]\n#+end_note\n",
226 )
227 .unwrap();
228
229 let (pages, broken) = render_site(&dir).expect("build site");
230 let index = &page(&pages, "index.org").html;
231 for label in ["special", "quote", "center", "figure", "table"] {
232 assert!(
233 index.contains(&format!("href=\"slugged.html\">{label}</a>")),
234 "{label} link must resolve to the slugged page:\n{index}"
235 );
236 }
237 assert_eq!(
238 broken.iter().map(|(_, t)| t.clone()).collect::<Vec<_>>(),
239 vec![TargetId::File("missing.org".into())],
240 "a broken link inside a special block must be reported"
241 );
242 std::fs::remove_dir_all(&dir).unwrap();
243}