krz/orgo

Lightning fast org-mode static site generator.

clone: git clone https://gitbay.org/krz/orgo.git

f274b516569365d352ed75206f6678f862cfd7f7

signed_unknown_key

author: Christian Cleberg <hello@cleberg.net> · 2026-08-23T05:05:05Z
committer: <noreply@github.com>

Point scope references at the org-support guide (#29)

Ten comments cited `README §"v1 scope"` or `README §OUT`. README.md has no
such section — that content now lives in `docs/guide/05-org-support.org`, which
README links to from the docs table. The citations now name that file, and the
"v1" phrasing goes with them, since nothing defines a v1 scope line any more.

Two claims in `parser.rs`'s header were stale as of #27 and #28: unknown block
types do not "keep their content verbatim as example blocks" — they render as
special blocks holding parsed org — and `#+TBLFM:` is no longer described as
out of scope.

Adding the section back to README instead would put the supported/unsupported
list in two places, which is how these drifted apart to begin with.
 fixtures/outofscope.org                            |  5 ++--
 src/audit.rs                                       | 15 +++++------
 src/main.rs                                        |  4 +--
 src/parser.rs                                      | 29 ++++++++++++----------
 src/render.rs                                      | 15 +++++------
 tests/constructs.rs                                | 12 ++++-----
 tests/snapshots/constructs__out_of_scope_html.snap |  2 +-
 7 files changed, 44 insertions(+), 38 deletions(-)

diff --git a/fixtures/outofscope.org b/fixtures/outofscope.org
index 5bbc01d..b8c2bee 100644
--- a/fixtures/outofscope.org
+++ b/fixtures/outofscope.org
@@ -1,8 +1,9 @@
 #+TITLE: Out of Scope
 #+INCLUDE: "other.org"
 
-Every construct here is on the README's explicit OUT list. The contract is not that we
-handle them — it is that they degrade predictably and never crash the build.
+Every construct here is on the explicit "Not supported" list in the org-support guide.
+The contract is not that we handle them — it is that they degrade predictably and never
+crash the build.
 
 * Babel
 
diff --git a/src/audit.rs b/src/audit.rs
index e0a3b0d..9981e35 100644
--- a/src/audit.rs
+++ b/src/audit.rs
@@ -1,9 +1,9 @@
 //! Corpus audit (spec §5, Phase 0): measure which org constructs a real corpus actually
-//! uses, and classify each against the v1 IN/OUT line.
+//! uses, and classify each against the supported/unsupported line.
 //!
-//! This exists because the v1 scope was, on the README's own admission, *recommended*
-//! rather than measured — a guess about which slice of org matters. A guess about a
-//! corpus is a hypothesis, and this is the experiment. It answers two questions:
+//! This exists because the scope was recommended rather than measured — a guess about
+//! which slice of org matters. A guess about a corpus is a hypothesis, and this is the
+//! experiment. It answers two questions:
 //!
 //! 1. **Coverage** — of the constructs this corpus uses, which do we handle? A construct
 //!    that is common here and out of scope is a scope bug, not a corpus quirk.
@@ -24,12 +24,13 @@ use anyhow::{Context, Result};
 use camino::{Utf8Path, Utf8PathBuf};
 use walkdir::WalkDir;
 
-/// Where a construct sits relative to the v1 scope line (README §"v1 scope").
+/// Where a construct sits relative to the supported set, which
+/// `docs/guide/05-org-support.org` defines.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 pub enum Scope {
-    /// v1 handles this.
+    /// orgo handles this.
     In,
-    /// v1 deliberately excludes this; it degrades predictably.
+    /// orgo deliberately excludes this; it degrades predictably.
     Out,
 }
 
diff --git a/src/main.rs b/src/main.rs
index 5c75981..7d28b5d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -90,8 +90,8 @@ enum Command {
         /// Output directory to remove.
         output: Utf8PathBuf,
     },
-    /// Audit a corpus: report which org constructs it uses and how they land against
-    /// the v1 scope line. Reports names, counts and locations — never document text.
+    /// Audit a corpus: report which org constructs it uses and how each one lands.
+    /// Reports names, counts and locations — never document text.
     Audit {
         /// Source directory (or single `.org` file) to audit.
         input: Utf8PathBuf,
diff --git a/src/parser.rs b/src/parser.rs
index 1679d19..807ccbf 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -9,16 +9,19 @@
 //! PARSE is a pure function of a single file's bytes (spec §2.1): it never depends on
 //! another file, which is what makes content-hash caching sound.
 //!
-//! Scope is the v1 IN list (README §"v1 scope"): headings with nesting, TODO keywords,
-//! priorities, tags and property drawers; paragraphs; plain lists (unordered, ordered,
-//! description) with checkboxes and nesting; tables; source/example/quote/center/export
-//! blocks; footnotes; `#+` keywords; inline markup, links, timestamps; images with
-//! `#+CAPTION`/`#+ATTR_HTML`.
+//! Scope is `docs/guide/05-org-support.org` §Supported: headings with nesting, TODO
+//! keywords, priorities, tags and property drawers; paragraphs; plain lists (unordered,
+//! ordered, description) with checkboxes and nesting; tables; footnotes; `#+` keywords;
+//! source, example, quote, center and export blocks; inline markup, links, timestamps;
+//! images with `#+CAPTION`/`#+ATTR_HTML`.
 //!
-//! Out-of-scope constructs are parsed-and-ignored, never fatal: babel `:results` and
-//! `#+TBLFM:` are inert keywords, unknown block types keep their content verbatim as
-//! example blocks, generic drawers are captured and dropped at render, and LaTeX,
-//! macros and radio targets survive as literal text.
+//! A block name with no dedicated handling is a special block: a div carrying the name,
+//! holding parsed org, which is what org's exporter emits for it.
+//!
+//! Out-of-scope constructs are parsed-and-ignored, never fatal: babel `:results` is an
+//! inert keyword, generic drawers are captured and dropped at render, and LaTeX, macros
+//! and radio targets survive as literal text. `#+TBLFM:` is inert for the same reason
+//! org's exporter leaves it alone: it does not recalculate on export either.
 
 use camino::Utf8Path;
 use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
@@ -408,7 +411,7 @@ fn parse_elements(lines: &[&str], base: usize, diags: &mut Vec<Diagnostic>) -> V
         }
         if let Some((key, value)) = keyword_kv(line) {
             if key.eq_ignore_ascii_case("INCLUDE") {
-                // Never expanded (README §OUT). Expanding it means resolving paths,
+                // Never expanded (§"Not supported"). Expanding it means resolving paths,
                 // recursion and `:lines`/`:only-contents`; dropping it silently means a
                 // page missing content nobody was told about. Saying so is the honest
                 // middle, and `--strict` turns it into a failure.
@@ -422,7 +425,7 @@ fn parse_elements(lines: &[&str], base: usize, diags: &mut Vec<Diagnostic>) -> V
                 });
             }
             if key.eq_ignore_ascii_case("RESULTS") {
-                // Babel is never executed (README §OUT), so a checked-in `#+RESULTS:`
+                // Babel is never executed (§"Not supported"), so a checked-in `#+RESULTS:`
                 // block is output from someone else's Emacs session at some other time.
                 // Emitting it would put unverifiable content on the page dressed as
                 // real content, so the block it labels is dropped.
@@ -617,7 +620,7 @@ fn unescape_block_line(line: &str) -> String {
 
 /// `:NAME:` … `:END:` at block level. A PROPERTIES drawer directly under a heading is
 /// consumed by [`parse_section_body`]; anything reaching here is a generic drawer,
-/// which the renderer drops (README §OUT).
+/// which the renderer drops (§"Not supported").
 fn parse_drawer(
     lines: &[&str],
     start: usize,
@@ -1353,7 +1356,7 @@ fn try_timestamp(chars: &[char], i: usize) -> Option<(Object, usize)> {
 
 /// One bracketed stamp → `(start, same-day end, has_time, index past the bracket)`.
 /// Day names (`Mon`) and repeater/warning cookies (`+1w`, `-2d`) are recognized and
-/// discarded — they carry no export meaning (README §OUT: agenda semantics).
+/// discarded — they carry no export meaning (§"Not supported": agenda semantics).
 fn parse_stamp(
     chars: &[char],
     i: usize,
diff --git a/src/render.rs b/src/render.rs
index e675ba7..43ebb83 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -8,12 +8,13 @@
 //!    and its cost must be cache-skippable (spec §4.2). Emit CSS classes, not inline
 //!    styles, so themes live in the stylesheet (spec §3.2).
 //!
-//! Renders the v1 IN set: headings (always anchored, with TODO keyword, priority and
-//! tags), paragraphs, plain lists (unordered/ordered/description, nested, with
-//! checkboxes), tables, source blocks (syntect-highlighted), example/quote/center
-//! blocks, HTML export blocks, horizontal rules, images and captioned figures,
-//! footnotes, timestamps, and inline markup. Out-of-scope elements (generic drawers,
-//! comments, stray keywords, non-HTML export blocks) render to nothing.
+//! Renders the supported set (`docs/guide/05-org-support.org`): headings (always
+//! anchored, with TODO keyword, priority and tags), paragraphs, plain lists
+//! (unordered/ordered/description, nested, with checkboxes), tables, source blocks
+//! (syntect-highlighted), example/quote/center blocks, HTML export blocks, horizontal
+//! rules, images and captioned figures, footnotes, timestamps, and inline markup.
+//! Out-of-scope elements (generic drawers, comments, stray keywords, non-HTML export
+//! blocks) render to nothing.
 
 use std::collections::HashMap;
 use std::sync::OnceLock;
@@ -463,7 +464,7 @@ impl Renderer<'_> {
                 out.push_str("</div>\n");
             }
             // An `html` export block is verbatim output by definition; every other
-            // backend is out of scope and drops (README §OUT).
+            // backend is out of scope and drops (§"Not supported").
             Element::ExportBlock { backend, raw } => {
                 if backend.eq_ignore_ascii_case("html") {
                     out.push_str(raw);
diff --git a/tests/constructs.rs b/tests/constructs.rs
index 3ec0978..93bb1c8 100644
--- a/tests/constructs.rs
+++ b/tests/constructs.rs
@@ -1,10 +1,10 @@
-//! Golden-file coverage of the v1 scope line (README §"v1 scope").
+//! Golden-file coverage of the scope line `docs/guide/05-org-support.org` draws.
 //!
 //! Two halves, and the second is the point:
 //!
-//! - **IN** — every construct the v1 scope claims gets an element-tree snapshot (parser
+//! - **IN** — every construct the guide claims gets an element-tree snapshot (parser
 //!   correctness) and a rendered-HTML snapshot (renderer correctness).
-//! - **OUT** — every construct the v1 scope explicitly excludes gets an assertion that it
+//! - **OUT** — every construct the guide explicitly excludes gets an assertion that it
 //!   *degrades predictably*: parsed and ignored, content preserved where that is the
 //!   honest fallback, never a crash and never a half-rendered artifact.
 //!
@@ -34,7 +34,7 @@ fn render_fixture(name: &str) -> String {
 }
 
 // ---------------------------------------------------------------------------
-// IN: the constructs v1 promises to handle
+// IN: the constructs the guide promises to handle
 // ---------------------------------------------------------------------------
 
 #[test]
@@ -180,7 +180,7 @@ fn unknown_source_language_falls_back_to_plain_code() {
 }
 
 // ---------------------------------------------------------------------------
-// OUT: the constructs v1 explicitly excludes must degrade, not explode
+// OUT: the constructs the guide explicitly excludes must degrade, not explode
 // ---------------------------------------------------------------------------
 
 /// The whole OUT fixture parses and renders. This is the crash gate.
@@ -222,7 +222,7 @@ fn table_formulas_are_inert() {
     );
 }
 
-/// LaTeX, macros and radio targets have no v1 semantics, so they survive as the literal
+/// LaTeX, macros and radio targets have no orgo semantics, so they survive as the literal
 /// text the author typed — lossless, and obviously unhandled to a reader.
 #[test]
 fn latex_macros_and_radio_targets_stay_literal() {
diff --git a/tests/snapshots/constructs__out_of_scope_html.snap b/tests/snapshots/constructs__out_of_scope_html.snap
index a12b181..3674cd9 100644
--- a/tests/snapshots/constructs__out_of_scope_html.snap
+++ b/tests/snapshots/constructs__out_of_scope_html.snap
@@ -2,7 +2,7 @@
 source: tests/constructs.rs
 expression: "render_fixture(\"outofscope.org\")"
 ---
-<p>Every construct here is on the README's explicit OUT list. The contract is not that we handle them — it is that they degrade predictably and never crash the build.</p>
+<p>Every construct here is on the explicit "Not supported" list in the org-support guide. The contract is not that we handle them — it is that they degrade predictably and never crash the build.</p>
 <h2 id="babel">Babel</h2>
 <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="support function echo shell">echo</span></span><span class="meta function-call arguments shell"> <span class="string quoted double shell"><span class="punctuation definition string begin shell">&quot;</span>the block renders; :results is never executed<span class="punctuation definition string end shell">&quot;</span></span></span></span></code></pre>
 <h2 id="table-formulas">Table formulas</h2>