0.124 → 0.125 — regions come from what a plate declares, one decline code, and a typed set reports its drops¶
Each section below is one concern, those whose breaks no type checker reports first, and the table closing the guide lists every break.
A plate's own print of a value surfaces no region¶
#data.subject, #upper(data.subject), a let alias's read and every other
value the plate prints itself render as before but surface no region and
answer no click. 0.124 scanned the plate's syntax for data reads and
windowed each one; that scan is gone. Regions come from three producers, each
one the plate declares:
- ink the helper generates: a
richtextorplaintextvalue, and any field printed throughqm.ink; - a
qm.regionclaim on ink the plate composes; - a form widget bound with
field:.
Print a field through qm.ink to keep its click target, or claim composed ink
with qm.region. quillmark check --regions ./my-quill doc.md lists the
filled fields no click reaches, and session.coverage() returns the same list.
A claim takes the text it brackets, and no page chrome, footnote or float¶
A qm.region claim takes the text between its markers that Typst draws with
no source position of its own, such as a string cast to content inside a
function argument (text(size: 9pt, "LIT")) and a list's bullets, where 0.124
left them unclaimed. An underline or strike stroke stays with the content it
decorates. A claim open across a page break takes none of the header, footer
or background it crosses, where it claimed them, and not the page number. A
claim takes no footnote or float, wherever it is anchored, where one open
across a page break took the notes and floats the page laid out around its
text. A claim placed inside a header, a footer, a footnote or a float still
takes that ink. A foreground is still taken by a claim open across its
page's break; wrap it in pdf.artifact to keep it out.
$ink is gone, and $path is on every typed dictionary¶
No dictionary carries $ink; qm.ink(dict, key) reads ink by address.
data, every card and every typed dictionary or table row carry $path,
where a dictionary carried it only beside an $ink or a matrix. A plate
comparing two dictionaries, walking keys() or spreading a row into a call
sees $path on dictionaries that had no $ key in 0.124; skip $-prefixed
keys there. A matrix's own dictionary still carries none.
The unclosed-claim warning is renamed¶
A claim whose close never reaches a frame warns typst::unclosed_region,
where it warned typst::unclosed_field_region. Route on the new code.
The helper is a module imported as qm¶
A plate imports the helper as a module, at version 0.2.0:
Every other form fails the render with typst::helper_import at the import
line: : *, : data, ink, a bare #import, and the 0.1.0 version. The name
is the plate's to choose; qm is the convention. Every member is read through
it, and two are renamed:
| 0.124 | 0.125 |
|---|---|
data |
qm.data |
ink(x).f, ink(x).at(k) |
qm.ink(x, "f"), qm.ink(x, k) |
display("addr", ..args) |
qm.ink(qm.data, "addr", ..args) |
display(x, "f", ..args) |
qm.ink(x, "f", ..args) |
display(card.at("$path") + "f", ..) |
qm.ink(card, "f", ..) |
field-region(f, body) |
qm.region(f, body) |
roster, form-field, signature-field, elements, tasks |
the same name under qm. |
A plate that wants the bare name binds it: #let data = qm.data.
qm.ink is total over the schema: an address the schema does not have fails
the render, a disabled card $body and a roster member's title included, so
read a title as if row.held and "title" in row.value { qm.ink(row.value,
"title") } else { row.title }, an unheld row's value being none. Blank
content, a blank date, a typed dictionary and a matrix give none, and a
display pattern on an address that is not a date's fails the render.
A downstream quiver migrates each plate in four steps:
- The import line becomes
#import "@local/quillmark-helper:0.2.0" as qm. ink(x).fbecomesqm.ink(x, "f"),display(..)becomesqm.ink(..), andfield-regionbecomesqm.region.databecomesqm.data, and every other helper name takes theqm.prefix.- A bare print of a
datavalue that should stay clickable,#data.subject, becomes#qm.ink(qm.data, "subject").
A declined construct warns under one code¶
quill.validate(doc) warns backend::declined_construct, the render's own
diagnostic, where it warned validation::declined_construct; that code is
gone. The two lists are equal, message, hint and args included, so a host
that routed the validate code apart from the render's routes one code. A host
collecting validate's own findings by the validation:: prefix no longer
collects the declines.
validate reads the plate a render compiles, so a document that does not
compile, one holding a value its field's type refuses, draws no decline until
it compiles; 0.124 read the authored values instead.
A render's declines stand after its backend's other warnings, after
typst::unregistered_element under Typst, where they stood before it.
Sections replace ui.group¶
A card puts fields in titled panels under sections:, and a card spelling
the legacy ui.groups registry or a field's ui.group warns
quill::deprecated_groups. schema() still emits ui.groups and
ui.group, so an editor reading them needs no change. A legacy card loads
exactly as its sections: rewrite does, which differs from 0.124 in three
places:
schema()lists the card's fields in display order, ungrouped first, then each group's in registry order, where it listed them as declared, and seeding writes a new card's keys in that order. A quill declaring its fields in display order sees no change.- An object alone in its group carries
ui.layout: flat, so an editor draws the group's panel as its frame. - A registry entry no field names leaves
ui.groups.
To rewrite a card, move each grouped field under sections.<group>.fields in
registry order, carry each registry title: to its section, and drop
ui.group and ui.groups; 0.126 refuses sections:, and its guide rewrites
each group as a top-level object (0.125 → 0.126).
A typed set reports what its markdown drops¶
writer.set and setAll in WASM, set and set_all in Python and
TypedWriter::set / set_all in Rust return a parse::dropped_construct
per construct a richtext markdown string drops, at the string's path, such
as main.subject or main.tags[0], where the drop was silent. addCard
returns its fields' warnings ahead of its body's. A string the render floor
wraps into an array, a bare string on an array of richtext, reports at
[0], from a set, a conform and validate alike, and a conform reports a
string in a variant cell the discriminant does not select.
A table knob outside its set rests as written¶
A stored table's align, widths or headless holding a value outside
its set stays as written and reads as absent, where normalization removed
it. align: "middle", headless: "true" and "align": null render as the
quill's default, as before, but now ride the stored bytes, so the content
hashes over them. A cell's align and valign already rode this way. Write
null nowhere a key means its default; leave the key out.
A whole-document revise names each dropped anchor with its line¶
writer.reviseDocument's droppedAnchors holds DocumentAnchors, { id,
path, line }, the shape doc.toAnnotatedMarkdown() lists, where an entry
held path and id. A card's anchors list fields first, then its body,
and an anchor is matched at its exact address, so one dropped from
items[1] is named though items[2] holds the same id.
Markdown¶
A line opening with three or more backticks whose info string holds a
backtick opens no code fence, as CommonMark reads it, so a ~~~ card block
under it opens its card. 0.124's card scanner read such a line as a fence
and kept the cards below it in the body.
A raw tag inside a footnote definition no longer warns on its own: the
definition's one footnote warning covers everything in it.
A newline beside a hard break imports as nothing, so line one<br> above
line two stores "line one\nline two", where 0.124 stored a space at the
start of the second line and rendered it as an indent. A paragraph or
continuation line whose content all drops, such as [](u) under another
paragraph, imports as no line. Content stored by 0.124 keeps its space;
importing the same markdown again stores none.
U+0000 reads as U+FFFD wherever it enters, as CommonMark reads it: an
� in a qm-* attribute and U+0000 in an Op::Insert included, where
those stored U+0000.
A placed table aligns its cells as an unplaced one does¶
A table placed by <qm-table align=…> aligns its cells as it would
unplaced under the plate's #set table(align: …) and a vertical
#show table.cell: set align(…). 0.124 gave a cell the placement's
horizontal alignment under a vertical table.align such as horizon, and
top under a vertical table.cell rule. A horizontal alignment set by a
table.cell show rule still yields to the alignment around a placed table, as
in 0.124; set it by #set table(align: …) instead.
Every break¶
| Break | Surface | Action |
|---|---|---|
A value the plate prints itself, #data.subject and every scanned read, surfaces no region |
session.regions(), fieldAt, RenderResult.regions |
Print through qm.ink, or claim with qm.region; quillmark check --regions lists what no click reaches |
| A claim takes the detached text between its markers, list bullets included, and no marginal it crosses, page number included, and no footnote or float | session.regions(), fieldAt |
Claim a note or float inside it |
No dictionary carries $ink; data, every card and every typed dictionary carry $path |
the plate's data |
Print with qm.ink; skip $-prefixed keys in a key walk or a comparison |
typst::unclosed_field_region is typst::unclosed_region |
session warnings, RenderResult.warnings |
Route on typst::unclosed_region |
The helper is version 0.2.0, imported as qm; any other import fails as typst::helper_import |
every Typst plate | Import as qm and read members through it |
field-region is qm.region, and ink(x).f and display(..) are qm.ink(x, "f", ..) |
every Typst plate | Rename per the table above |
Quill::validate warns backend::declined_construct, equal to the render's, where it warned validation::declined_construct, which is gone |
Quill::validate, WASM and Python validate, quillmark check, quillmark validate |
Route on backend::declined_construct |
A document whose value fails to compile draws no decline from validate |
Quill::validate |
Fix the value; the declines follow |
A render's declines follow typst::unregistered_element |
session warnings, RenderResult.warnings |
None |
A typed set returns its richtext strings' parse::dropped_construct, at each string's path; addCard returns its fields' ahead of its body's |
WASM set / setAll / addCard, Python set / set_all / add_card, Rust TypedWriter, CardWriter |
Read the returned list |
A string the floor wraps into an array reports its drops at [0], and a conform reports a string in an unselected variant cell |
Quill::conform, quill.parse, Quill::validate |
None |
A table align, widths or headless outside its set, null included, rests as written and reads as absent |
stored documents, overwrite, the op wire |
Leave a default key out |
droppedAnchors entries are DocumentAnchor { id, path, line }, a card's fields ahead of its body, matched at the exact address |
WASM reviseDocument, Rust DocumentRevised |
Read line; DroppedAnchor is DocumentAnchor |
| A backtick line whose info string holds a backtick opens no fence for the card scanner | Document::parse, Document.fromMarkdown, quill.parse |
None |
A raw tag inside a footnote definition warns nothing beside the footnote |
Parsed.warnings, doc.warnings |
None |
| A newline beside a hard break imports as no space, and a line whose content all drops as no line | Document::parse, Document.fromMarkdown, quill.parse, reviseDocument |
None |
� in a qm-* attribute and U+0000 in an Op::Insert read as U+FFFD |
Document::parse, the op wire |
None |
A placed table aligns its cells as an unplaced one does under the plate's table.align and a vertical table.cell show rule |
Typst rendered output | None |
A card spelling ui.group or ui.groups warns quill::deprecated_groups |
Quill::warnings, every render's warnings, quillmark validate |
Move the fields under sections:, or for 0.126 under a top-level object (0.125 → 0.126) |
A grouped card lists its fields in display order, an object alone in its group carries ui.layout: flat, and a registry entry no field names is dropped |
QuillConfig::schema, WASM and Python schema, quillmark schema, seeding |
None |
ImportWarning is { construct, count }; Dropped::Table / TableAttr are Element("table") / ElementAttr { element: "table", .. } |
quillmark_content |
Destructure the struct |
Container::Element { element, instance }, element a carrier::Element that Element::new builds, refusing a name outside the grammar or reserved; Invariant::BadElement and carrier::modeled are gone |
quillmark_content |
Build through Element::new; read name() and attrs() |
TypedWriter::set / set_all and CardWriter::set / set_all return Vec<Diagnostic> |
Rust | Read or bind the warnings |
A config built with QuillConfig::new prints its blueprint in declaration order, whatever its ui.groups |
Rust | Declare the fields in display order |
DocumentRevised.dropped_anchors is Vec<DocumentAnchor>; DroppedAnchor is gone |
Rust | Read .path, .id, .line |
QuillConfig::declined_in_plate reads the backend off the config; backend::declined_in is gone; BlockConstruct::count_in is tally |
Rust | Drop the backend argument |
SessionHandle::update takes the session's &QuillConfig, and LiveSession::new the plate data it opens on; a backend's session no longer mints backend::declined_construct |
backend implementations | Take the config; drop the decline |