Keep Blocks¶
Keep blocks are where the pattern-writing ends. The tail-capture regex kept reappearing everywhere — "everything past this point is mine" — and the realization followed: it would be better to just name the blocks that should not be touched. A keep block is exactly that: visible marker lines declaring a developer-owned region inside a provider-rendered file. The intention is self-documenting, and there is no regex to write.
The template ships a default between the markers for fresh projects. If your file already has the marker pair, what's between them survives every apply — the markers themselves stay in the output (visible contract), only the directive line is stripped.
Syntax¶
## repolish:keep-block[notes] start="<!-- notes-start -->" end="<!-- notes-end -->"
<!-- notes-start -->
Default content for new projects.
<!-- notes-end -->
start/endare literal marker strings — use whatever comment style fits the file (they are ordinary lines, and they remain in the output).- If your project file has no matching marker pair, the template default is kept.
- Supports the
|after-renderphase — required when the blocks are generated by Jinja (see end-regex).
!!! warning "Placement" A keep-block directive governs the region(s) that follow it, up to the next keep directive line. Place each directive directly above the block(s) it manages — stacking several directive lines together at the top of the file leaves the earlier regions unmanaged (the first directive's section ends where the next directive begins). Supporting stacked directives is a possible non-breaking change for a later version.
Worked example¶
repolish/README.md.jinja:
README.md — you already filled the block:
Save this as scratch.yaml:
template: |
# My Project
## repolish:keep-block[custom] start="<!-- custom-start -->" end="<!-- custom-end -->"
<!-- custom-start -->
Default content for new projects.
<!-- custom-end -->
target: |
# My Project
<!-- custom-start -->
Our setup notes: run `make bootstrap` first.
<!-- custom-end -->
and run:
Repeated regions¶
One directive covers many blocks that share the same markers — repolish matches them in encounter order, first block to first block, second to second:
## repolish:keep-block[notes] start="<!-- notes-start -->" end="<!-- notes-end -->"
## Installation
<!-- notes-start -->
_No notes yet._
<!-- notes-end -->
## Usage
<!-- notes-start -->
_No notes yet._
<!-- notes-end -->
If your README already has both marker pairs filled in (say install instructions
under Installation, an example under Usage), each block is preserved in its own
position — no notes-2 variant needed. Blocks without a matching pair in your
file keep the template default.
(To see the pairing, extend the Try-it scratch file above with a second marked section.)
In Python files¶
Comment style is free-form, so keep blocks work in code too — e.g. a provider-managed registry whose lists only developers can fill. Note the interleaved placement: each directive sits directly above its own region (per the placement rule):
"""Plugin registry — managed by repolish, lists owned by the project."""
# repolish:keep-block[plugins] start="# -- plugins-start" end="# -- plugins-end"
# -- plugins-start
PLUGINS = []
# -- plugins-end
# repolish:keep-block[envs] start="# -- envs-start" end="# -- envs-end"
# -- envs-start
ALLOWED_ENVIRONMENTS = ["development"]
# -- envs-end
Once developers add entries, both lists survive every apply; the provider can still change imports, docstrings, and methods around them.
end-regex¶
end-regex closes each kept region dynamically, at the first following line
matching a pattern — the piece that made keep blocks usable inside Jinja loops,
where a literal end marker is awkward and every repetition is identical:
## repolish:keep-block[provider-additional|after-render] start="# additional-paths" end-regex="^provider[0-9]+:$"
{% for idx in providers %}
provider{{ idx }}:
- static{{ idx }}
# additional-paths
- default{{ idx }}
{% endfor %}
Two things do the work here:
|after-render— the blocks don't exist until Jinja renders the loop, so the directive waits for the second phase.end-regex="^provider[0-9]+:$"— each region closes at the next loop item (or at the end of the directive's section), so N rendered blocks pair first-to-first with N blocks in your file.
If no match is found before the section ends, the region closes at the section boundary.
Trying end-regex in preview
repolish preview runs the pre-render phase only. To
simulate after-render behavior, paste the rendered content into the scratch
file as template and drop the |after-render suffix — the reconciliation
machinery is identical.
When to use¶
Keep blocks when a region is yours, not just a value. For single lines or structured key/value sections, regex and multiregex are enough; for the inverse — a provider filling blocks inside a file you own — see Insertions.