How it works¶
A short mental model of what Pinfit does on every run. Read this once and the rest of the documentation will feel obvious.
The three kinds of file¶
| File | Who owns it | What it is |
|---|---|---|
pinfit.yaml |
You | Project root marker and generator-wide preferences. |
*.<kind>.yaml |
You | One spec per generated component: .interface.yaml, .module.yaml, .state-machine.yaml, .observer.yaml, .command-table.yaml, .status-codes.yaml, .adapter.yaml. |
*.h / *.c |
Pinfit, except inside user regions | The generated output. |
A spec file and its generated C always live in the same directory. There is no output folder and no path configuration: to move generated files, move the YAML.
What a generate run does¶
flowchart LR
A[Find pinfit.yaml<br/>at or above cwd] --> B[Scan the project tree<br/>for spec files]
B --> C[Resolve references<br/>across the project]
C --> D[Read existing output<br/>and lift user regions]
D --> E[Render fresh structure<br/>and paste regions back]
E --> F[Write files]
- Find the project root. Pinfit walks up from the directory you are in until it finds a
pinfit.yaml. That file'sformatanddocumentationsettings apply to everything generated in this run. - Scan the tree. Every spec file under the scanned directory is collected. A subdirectory
with its own
pinfit.yamlis a nested project and is skipped entirely. - Resolve references.
implements:, an observer'sinterface:, an adapter'sfrom:/to:are matched by name across the whole project, not by path, so specs can be laid out however suits you. - Lift the user regions. For each output file that already exists, Pinfit reads the text
between every
usercode+/usercode-pair and keeps it, keyed by region name. - Render and merge. The structure is rendered fresh from the spec, and each region's saved text is pasted back into the region with the same name.
- Write. An existing file is only overwritten when it carries Pinfit's generated-file marker
and nothing outside its user regions changed since the last run. Anything else is refused
rather than overwritten, unless you pass
--force.
The two kinds of marker¶
Generated files carry two visually distinct marker styles, and the difference matters:
/*@Pinfit(private-function:ra_iic_common_iic_write)*/ /* (1)! */
static common_iic_status_t ra_iic_common_iic_write(void *context, uint32_t length)
{
common_iic_status_t pinfit_result = COMMON_IIC_INVALID_PARAM;
/*@Pinfit usercode+ function.common_iic.write.body*/ /* (2)! */
/* yours */
/*@Pinfit usercode-*/
return pinfit_result;
}
- Structural marker —
/*@Pinfit(...)*/. Pinfit's bookkeeping. It tells the next run what the following block is. Do not edit it or the code it labels. - User region —
usercode+...usercode-. Yours. Everything between the two lines is preserved verbatim across every regeneration.
Region names are predictable and derived from the spec: function.<interface>.<function>.body,
state.<STATE>.entry, command.<NAME>.body, variable.<name>.get, and so on. Each generator
page lists the regions it produces.
What happens when the spec changes¶
| Change in YAML | Effect on the generated C |
|---|---|
| Add a function, state, command, … | A new empty user region appears; every existing region is untouched. |
| Rename an item | Treated as a removal plus an addition — the old region is kept as an orphan, so you can move the code across by hand. |
| Remove an item | Its structure disappears; its user region is retained as an orphan rather than silently deleted. |
| Change a parameter or return type | The signature is rewritten around your body. Your body is unchanged, so fix it up if it no longer compiles. |
Change format in pinfit.yaml |
Everything is re-rendered in the new style, regions carried across as usual. |
The rule behind all of it: Pinfit never deletes code you wrote. The worst it will do is leave it somewhere it no longer belongs, clearly marked, for you to deal with.
Regenerating is meant to be routine¶
There is no incremental mode and no cache to invalidate — pinfit generate is idempotent. Running
it twice in a row produces identical files the second time. Run it after any YAML edit, wire it
into a pre-build step if you like, and keep both the YAML and the generated C in version control
so reviewers see the real diff of what changed.
Leaving¶
Pinfit is a starting point, not a dependency. pinfit detach
removes every marker line, deletes the spec files and pinfit.yaml, and leaves ordinary C behind.
Nothing you have to keep running.