krz/orgo
Lightning fast org-mode static site generator.
clone: git clone https://gitbay.org/krz/orgo.git
809ac9d720951c3f1ded537571e832c7fb349960
signed_unknown_key
author: Christian Cleberg <hello@cleberg.net> · 2026-08-23T03:52:32Z
committer: <noreply@github.com>
docs/guide/05-org-support.org | 2 +- docs/guide/09-auditing.org | 28 ++++++++++++++++------------ fixtures/tblfm.org | 10 ++++++++++ src/audit.rs | 6 +++++- tests/constructs.rs | 16 ++++++++++++++++ tests/oracle.rs | 1 + 6 files changed, 49 insertions(+), 14 deletions(-) @@ -167,6 +167,7 @@ broken. | =#+TEMPLATE:= | The layout this page renders through. | | =#+OPTIONS:= | Per-file export switches. | | =#+CAPTION:=, =#+ATTR_HTML:= | Attach to the image *directly* below them — a blank line in between attaches to nothing, as in org. A captioned image is numbered =Figure N:=. | +| =#+TBLFM:= | Kept inert, and that matches org: the HTML exporter does not recalculate formulas either, so both emit the cells as written. Recalculate in Emacs (=C-c C-c=) to change them. | Every other =#+KEYWORD:= is available to templates as ={{ page.keywords.that_keyword }}=, so metadata orgo has never heard of still reaches @@ -180,7 +181,6 @@ a build. | Construct | What happens | |-----------+--------------| | Babel execution, =:results= | The source block renders as code. A checked-in =#+RESULTS:= block is *dropped*. | -| =#+TBLFM:= | Inert. The table renders with the values as written. | | =#+INCLUDE:= | Never expanded, and *reported*: the build prints =file:line: `#+INCLUDE: …` is not expanded=, so a page is never quietly missing content. =--strict= makes it a failure. | | LaTeX, MathJax | Survives as the literal text you typed. | | Macros ={{{name}}}=, radio targets | Literal text. | @@ -17,31 +17,35 @@ The audit answers two questions about a body of org files: * Reading the output #+BEGIN_EXAMPLE -corpus: 179 file(s), 29258 line(s) +corpus: 180 file(s), 29742 line(s) CONSTRUCTS (by frequency) construct uses files first seen -IN list item 1282 109 blog/2018-11-28-aes-encryption.org:53 -IN heading 1128 174 blog/2018-11-28-aes-encryption.org:7 -IN source block 932 121 blog/2018-11-28-cpp-compiler.org:17 +IN list item 1309 111 blog/2018-11-28-aes-encryption.org:53 +IN heading 1148 176 blog/2018-11-28-aes-encryption.org:7 +IN verbatim 1048 130 blog/2018-11-28-aes-encryption.org:79 ... -OUT table formula (#+TBLFM:) 4 1 blog/2024-08-11-org-mode-features.org:191 -OUT entity (\name) 3 3 blog/2024-04-06-convert-onenote.org:37 +IN table formula (#+TBLFM:) 4 1 blog/2024-08-11-org-mode-features.org:191 +OUT unmodelled block type 1 1 blog/2026-03-03-auditing-aws-s3.org:50 -coverage: 8854 in-scope use(s) (99.9%), 8 out-of-scope (0.1%) +coverage: 9001 in-scope use(s) (100.0%), 1 out-of-scope (0.0%) KEYWORDS - TITLE 179 179 blog/2018-11-28-aes-encryption.org:2 -??? SLUG 178 178 blog/2018-11-28-aes-encryption.org:4 - DESCRIPTION 176 176 blog/2018-11-28-aes-encryption.org:3 + SLUG 180 180 blog/2018-11-28-aes-encryption.org:4 + TITLE 180 180 blog/2018-11-28-aes-encryption.org:2 ... + +BLOCK TYPES + SRC 941 123 blog/2018-11-28-cpp-compiler.org:17 + QUOTE 115 48 blog/2018-11-28-aes-encryption.org:21 +??? NOTE 1 1 blog/2026-03-03-auditing-aws-s3.org:50 #+END_EXAMPLE - =IN= is supported; =OUT= is excluded by design and degrades as described in [[file:05-org-support.org][Org support]]. - The *coverage* line is the number to look at first. -- =???= marks a name orgo does not recognise at all — in this example =#+SLUG:=, from - a run made before it was supported. +- =???= marks a name orgo does not recognise at all — here =#+begin_note=, which one + post uses once. That is the blind-spot signal: not "known unsupported", but unknown. Four censuses follow the construct table: every distinct =#+KEYWORD:=, block type, drawer name and link scheme in the corpus. A =???= in any of them is worth a look. new file mode 100644 @@ -0,0 +1,10 @@ +#+TITLE: Table Formula + +The cells deliberately contradict the formula: org's HTML exporter does not +recalculate on export, so both exporters must emit the values as written. + +| N | N^2 | +|---+-----| +| 2 | 999 | +| 3 | 888 | +#+TBLFM: $2=$1^2 @@ -258,7 +258,11 @@ impl Audit { "CAPTION" | "NAME" | "ATTR_HTML" => { self.count(Scope::In, "affiliated keyword", at) } - "TBLFM" => self.count(Scope::Out, "table formula (#+TBLFM:)", at), + // Not a gap: org's HTML exporter does not recalculate `#+TBLFM:` + // either, so the cells as written are what both exporters emit. + // `fixtures/tblfm.org` holds the oracle to that (`tests/oracle.rs`). + // Unlike `#+INCLUDE:`, nothing is lost by leaving it inert. + "TBLFM" => self.count(Scope::In, "table formula (#+TBLFM:)", at), "INCLUDE" => self.count(Scope::Out, "#+INCLUDE:", at), "RESULTS" => self.count(Scope::Out, "babel results block", at), "TODO" => self.count(Scope::Out, "#+TODO: keyword sequence", at), @@ -387,6 +387,7 @@ fn well_formed_fixtures_produce_no_diagnostics() { "blocks.org", "timestamps.org", "images.org", + "tblfm.org", ] { let document = parse_fixture(name); assert!( @@ -800,3 +801,18 @@ fn audit_counts_real_entities() { "a real entity was not counted:\n{report}" ); } + +/// `#+TBLFM:` is in scope, not a gap: org's exporter does not recalculate it either, so +/// the page orgo produces is the page Emacs produces. `fixtures/tblfm.org` is the oracle. +#[test] +fn audit_counts_table_formulas_as_in_scope() { + let report = audit_fixture("tblfm.org"); + let line = report + .lines() + .find(|l| l.contains("table formula")) + .expect("the formula is counted at all"); + assert!( + line.starts_with("IN "), + "a #+TBLFM: table orgo renders exactly as Emacs does must not read as a gap:\n{line}" + ); +} @@ -628,6 +628,7 @@ fn every_divergence_from_emacs_is_deliberate() { "timestamps.org", "images.org", "elements.org", + "tblfm.org", ]; let mut offenders = Vec::new(); for fixture in fixtures {