Interpolation & captures
Wit has two substitution mechanisms, and keeping them straight is the single
most common point of confusion. Captures — ::name:: and the body slot ... — carry rich markup, whole blocks of content. Interpolation — {{path}} — drops a scalar string into one narrow
context. This page shows what each becomes and, crucially, where each is live.
Captures carry rich content
A captured value is not just a string — it is re-parsed as a full document at substitution time. So a captured value that is a bulleted list becomes a real list:
#wrap ||body|| ::body:: wrap# @wrap body: @ul @li One li@ @li Two li@ ul@ wrap@
- One
- Two
That renders a genuine <ul> with two items. The same holds for a heading
(value-contains-heading becomes a real heading) and multiple paragraphs
(multi-paragraph-value). At an inline position a
single-paragraph value splices its inline content, while a multi-block value
lifts into blocks (value-at-inline-position); an inline-only value takes a fast
path (value-with-emphasis-only).
Interpolation is a scalar hole
{{path}} is a doubled-brace scalar hole. The path
is [A-Za-z0-9_.-]+ (inner spaces allowed), and it resolves against
iteration variables, data definitions, or a bare scalar def. A number, boolean,
or null coerces to a string; a record or collection is E_UNRESOLVED_REFERENCE — you can only interpolate a scalar.
Where interpolation is live: only inside raw nodes
This is the rule to memorise: {{…}} interpolates only
inside @@ raw-node bodies. It is perfect for CSS holes:
#theme: { accent - green } @@style .badge { color: {{theme.accent}}; } style@@
That renders .badge { color: green; }. In ordinary prose, { is record-arg syntax, so a brace pair renders literally:
#book: { title - The Keeper } The book {{book.title}} versus @book.title here.
The book {{book.title}} versus The Keeper here.
That outputs the literal text {{book.title}} next to the
resolved The Keeper. A frozen @@@ body
makes {{…}} inert too — see Literal & raw nodes.
Two outputs, one lookup
The same lookup feeds both mechanisms, but they emit different things:
{{name}}→ a scalar string, for class names, colours, CSS holes — live only in @@ bodies.::name::and...→ rich content, live only in a definition body.- Data into prose is
@name.field— never{{…}}.
Common mistakes
- Expecting
{{book.title}}to interpolate in a paragraph — it renders literally; use@book.title. - Writing
::loopvar.field::in prose — that is drift from older notes; use data access@loopvar.field.
See also
Defining nodes· Data access · Literal & raw nodes · Form-fill (rich values)