Word counts
word-counts-by-section(body, level: 1, count-captions: false)- one row per heading at
level:(top-level by default), the words found under it.render-report(...)calls this for you — reach for it directly only if a project needs the numbers outside the usual report layout. extract-text(node, count-captions: false)- the structural walk underneath it — content in, plain text out, with every reference, citation, and label already stripped.
count-words(s)- splits on whitespace, nothing fancier.
Three exclusions are always in effect, none of them configurable off:
- Citations and cross-references. A resolved
@smith2020becomes a bracketed number once Typst lays a page out — real text, easy to miscount as prose.extract-textnever sees that: it walks the manuscript’s content before layout, captured byinstrument()(Quickstart) at the exact momentcontexture.bundlehands it totemplate:, where a citation is still a real, ignorableref/citenode rather than rendered text. - Table cells. A
table()‘s cells have no space/paragraph-break between them in the content tree the way a paragraph’s words do — concatenating them as if they were prose merges neighbouring cells into nonsense tokens ("A","B"becoming"AB", one word instead of two, or worse for multi-word cells). Never counted, in any mode — table data was never prose to begin with. - Figure captions, by default —
count-captions: trueopts them in, passed toreport(...).
Note
colophon reads through palimpsest’s own marks too —
add/del/rep/passage/touched all render their actual output wrapped in a context block, even in clean mode, which is structurally invisible to colophon’s pre-layout walk the same way a citation’s rendered bracket would be. Rather than trying to see through that opacity, colophon reads each function’s own plain, non-context metadata directly — the exact content clean mode shows, no more and no less.// Regression test for the Phase 4 fix documented in CLAUDE.md
// ("Phase 4" -> "Correction du 2026-09-13"): colophon's word count
// must reflect exactly what palimpsest's *clean* compile shows, even
// though passage()/add()/del()/rep() all render through a `context`
// block this package's pre-layout walk can't otherwise see into.
//
// Expected total: 6 + 7 + 7 + 1 = 21 words.
// - "This sentence has and stays short." (6) -- del()'d words gone.
// - "The old wording is now different today." (7) -- rep()'s `new`
// only, never `old`.
// - "Plain touched text with six words total." (7) -- an ordinary
// passage/touched(), no add/del/rep at all.
// - the figure's caption (1, "Caption.") -- proves the figure
// inventory (Phase 2, query()-based) already saw content nested
// inside a mark correctly, unaffected by this whole problem.
#import "../../lib.typ" as colophon
#import "/typst-palimpsest/lib.typ" as palimpsest
#import "../../../typst-contexture/lib.typ" as contexture
#let my-template(body) = {
set page(width: 16.6cm, height: auto, margin: 12pt)
set text(size: 10.5pt)
body
}
#show: contexture.bundle.with(
template: colophon.instrument(template: my-template),
documents: (colophon.report(count-captions: true),),
)
= Methods
#palimpsest.passage(none)[
This sentence has #palimpsest.del[four deleted words] and stays short.
]
#palimpsest.passage(none)[
The old wording #palimpsest.rep[was here before][is now different] today.
]
#palimpsest.touched(none)[
Plain touched text with six words total.
]
#palimpsest.passage(none)[
#palimpsest.add[
#figure(rect(), caption: [Caption.]) <fig-in-mark>
]
]
The count matches exactly what the clean, submitted manuscript would show: the deleted words gone, the replacement’s new wording only, the untouched passage counted normally, and — since this example passes count-captions: true — the figure’s own caption too:
Table cells versus captions, side by side
The same manuscript that introduces the figure/table inventory also makes the table-cell exclusion visible: its results table holds the literal text “A” and “B”, and the total word count is unaffected by them either way count-captions is set — worth keeping in mind when a word count seems low for a manuscript that’s mostly tables and figures:
| ← Quickstart | The abstract → |