krz/orgo

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

Commit ef9a625b5d

ef9a625b5df9c4cc5e1c05853647c506c97b7e91

parent: f59c734997

Verified · cmc

cmc <hello@cleberg.net> · 2026-08-30 06:53 UTC

audit: a construct named inside verbatim is not a use of it (#1)

The entity check skipped `=verbatim=` and `~code~` spans; the other inline
checks did not, so any page documenting org syntax reported constructs it does
not use. `orgo audit docs` reported `OUT macro call` at
`guide/05-org-support.org:186` — the table row naming macros in order to say
they are unsupported, and the only non-zero out-of-scope count in orgo's own
audit.

`scan_inline` now blanks the literal spans once and runs the timestamp, macro
call, radio/internal target, LaTeX and entity checks against that. Emphasis
pairs still see the raw line: `=` and `~` are themselves markers being counted.

docs audits at 100.0% coverage, 0 out-of-scope.

Closes #1

Layout: unified · split

fixtures/audit-verbatim-constructs.org added +4
@@ -0,0 +1,4 @@
1#+TITLE: Verbatim mentions
2
3A doc explaining syntax, where every mention is inside verbatim:
4=${x^2}$=, ={{{name}}}=, =<<<radio>>>=, =[1/3]=, =CLOCK: [2024-01-01]=.
src/audit.rs +12 −10
@@ -330,21 +330,27 @@ impl Audit {
330 rest = &after[end..]; 330 rest = &after[end..];
331 } 331 }
332 332
333 if has_timestamp(line) { 333 // The rest read a line that has had its `=verbatim=` and `~code~` spans blanked:
334 // a construct shown inside verbatim is displayed rather than rendered, so a page
335 // documenting org syntax is not a use of the syntax it names. Emphasis pairs
336 // below deliberately still see the raw line — `=` is one of the markers scanned.
337 let bare = without_literal_spans(line);
338
339 if has_timestamp(&bare) {
334 self.count(Scope::In, "timestamp", at); 340 self.count(Scope::In, "timestamp", at);
335 } 341 }
336 if line.contains("{{{") { 342 if bare.contains("{{{") {
337 self.count(Scope::Out, "macro call", at); 343 self.count(Scope::Out, "macro call", at);
338 } 344 }
339 if line.contains("<<<") { 345 if bare.contains("<<<") {
340 self.count(Scope::Out, "radio target", at); 346 self.count(Scope::Out, "radio target", at);
341 } else if line.contains("<<") && line.contains(">>") { 347 } else if bare.contains("<<") && bare.contains(">>") {
342 self.count(Scope::Out, "internal target", at); 348 self.count(Scope::Out, "internal target", at);
343 } 349 }
344 if line.contains("\\begin{") || latex_inline(line) { 350 if bare.contains("\\begin{") || latex_inline(&bare) {
345 self.count(Scope::Out, "LaTeX fragment", at); 351 self.count(Scope::Out, "LaTeX fragment", at);
346 } 352 }
347 if entity_ref(line) { 353 if entity_ref(&bare) {
348 // Rendered, and rendered as org renders it: `\alpha` becomes `&alpha;` in 354 // Rendered, and rendered as org renders it: `\alpha` becomes `&alpha;` in
349 // both exporters. `fixtures/audit-entities.org` holds the oracle to that. 355 // both exporters. `fixtures/audit-entities.org` holds the oracle to that.
350 self.count(Scope::In, "entity (\\name)", at); 356 self.count(Scope::In, "entity (\\name)", at);
@@ -510,11 +516,7 @@ fn latex_inline(line: &str) -> bool {
510/// Only names org knows count, matching [`crate::parser`]'s rule for rendering one: a 516/// Only names org knows count, matching [`crate::parser`]'s rule for rendering one: a
511/// Windows path (`C:\Users\me`) and a namespaced identifier (`Tumblr\API\Client`) are not 517/// Windows path (`C:\Users\me`) and a namespaced identifier (`Tumblr\API\Client`) are not
512/// entity references. 518/// entity references.
513///
514/// Verbatim and code spans are skipped: `=\alpha=` shows the name rather than rendering
515/// the character, so it is not a use of the feature.
516fn entity_ref(line: &str) -> bool { 519fn entity_ref(line: &str) -> bool {
517 let line = without_literal_spans(line);
518 let chars: Vec<char> = line.chars().collect(); 520 let chars: Vec<char> = line.chars().collect();
519 for (i, c) in chars.iter().enumerate() { 521 for (i, c) in chars.iter().enumerate() {
520 if *c != '\\' { 522 if *c != '\\' {
tests/constructs.rs +15
@@ -844,3 +844,18 @@ fn audit_counts_special_blocks_as_in_scope() {
844 "no block name is unrecognised — every one renders: {flagged:?}" 844 "no block name is unrecognised — every one renders: {flagged:?}"
845 ); 845 );
846} 846}
847
848/// A page that documents org syntax names constructs inside `=verbatim=`; the names are
849/// displayed, not rendered, so none of them is a use of the construct. Counting them
850/// reported orgo's own guide as using macros it does not support.
851#[test]
852fn audit_ignores_constructs_inside_verbatim() {
853 let report = audit_fixture("audit-verbatim-constructs.org");
854 for construct in ["macro call", "radio target", "internal target", "timestamp", "LaTeX fragment"]
855 {
856 assert!(
857 !report.contains(construct),
858 "{construct} was counted from a verbatim mention:\n{report}"
859 );
860 }
861}