Inline Injection
The problem it solves
Section titled “The problem it solves”For rules that generate function implementations (.g.cpp), you typically also need the declaration in the original header. Without inline injection you must add the declaration manually, which defeats the purpose of generation and breaks whenever the generated signature changes.
Inline injection lets the rule emit both the implementation and the declaration, keeping them in sync automatically.
How it works
Section titled “How it works”The inline field in the handler return value is a list of objects:
return json.encode({ source = "std::string_view toString(Color e) { ... }", inline = { { source = "std::string_view toString(Color e);" } }})Each item supplies one chunk of source text. The engine looks for the anchor matching this entity’s <rule>::<qualifiedName> and writes one paired :begin]]/:end]] block per item at that site, in the order returned. N items ⇒ N consecutive blocks (see Multiple inline items below).
Anchor formats
Section titled “Anchor formats”Two on-disk forms are recognised. You can write either form by hand; the engine will rewrite to the paired form on first run.
Bare anchor (one line, write-by-hand)
Section titled “Bare anchor (one line, write-by-hand)”// [[codegen::generated::RuleName::qualifiedName]]enum class Color { Red, Green, Blue };The anchor must be on its own line, immediately above the declaration. After a successful run, the engine expands this single line into a paired block (see below) — bare anchors don’t survive the first regeneration.
Paired anchor (engine-managed)
Section titled “Paired anchor (engine-managed)”// [[codegen::generated::RuleName::qualifiedName:begin]]std::string_view toString(Color e);// [[codegen::generated::RuleName::qualifiedName:end]]enum class Color { Red, Green, Blue };Subsequent regenerations rewrite the whole contiguous run of :begin]]/:end]] blocks for this key, replacing it with one block per current inline item. Item count can grow or shrink between runs — the engine resizes the run accordingly.
Within each block, the markers stay; only the inner text moves. Diff noise is bounded to the run.
Multiple inline items per entity
Section titled “Multiple inline items per entity”When inline has N items, the engine emits N consecutive :begin]]/:end]] blocks at the anchor site, one block per item, in the order returned by the handler. For example:
inline = { { source = "void start();" }, { source = "void stop();" }, { source = "bool isRunning();" },}writes:
// [[codegen::generated::RuleName::qualifiedName:begin]]void start();// [[codegen::generated::RuleName::qualifiedName:end]]// [[codegen::generated::RuleName::qualifiedName:begin]]void stop();// [[codegen::generated::RuleName::qualifiedName:end]]// [[codegen::generated::RuleName::qualifiedName:begin]]bool isRunning();// [[codegen::generated::RuleName::qualifiedName:end]]On re-run with a different item count, the run is collapsed or expanded in place. Reordering items in the script reorders the blocks on disk.
If you need code at different sites in the source, use multiple anchors and multiple matching entities — one anchor per qualified name.
We’re considering an additive inline = { slotName = "..." } form that would let one entity target multiple distinct anchor sites — e.g. // [[codegen::generated::Rule::Qual::publicApi]] and // [[codegen::generated::Rule::Qual::implDetails]] — without forcing you to split the entity. If that fits your use case (or if it doesn’t), tell us in the feedback form.
What gets written
Section titled “What gets written”For an entity with N inline items, the engine writes N consecutive blocks of the form:
// [[codegen::generated::RuleName::qualifiedName:begin]]<item N source, blank lines stripped>// [[codegen::generated::RuleName::qualifiedName:end]]The C++ declaration the anchor sits above is left untouched — the engine only modifies the anchor block itself. Files are written via a .codegen_tmp rename for atomicity.
If an entity returns inline but no anchor exists in the source, the engine emits diagnostic W003 and skips the injection (the .g.cpp is still written).
The run between the first :begin]] and last :end]] for a given key is treated as engine-owned: do not write hand-edits between markers. Anything you put there will be overwritten on the next run.
When to omit inline
Section titled “When to omit inline”Rules that only emit .g.cpp content can omit the field or return an empty list:
return json.encode({ source = impl })-- orreturn json.encode({ source = impl, inline = {} })- Bare anchors are write-by-hand convenience; the engine rewrites them on first run into one paired block per
inlineitem. - N items ⇒ N consecutive
:begin]]/:end]]blocks. The contract is “ordered list of injected blocks”, not “concatenated single block”. - Re-runs grow or shrink the run in place to match the current item count and order.
- Missing anchors produce diagnostic
W003, not a fatal error.