pub struct Document { /* private fields */ }Implementations§
Source§impl Document
impl Document
pub fn parse(input: &[u8], format: Format) -> Result<Self, Error>
pub fn parse_str(input: &str, format: Format) -> Result<Self, Error>
Sourcepub fn parse_with(
input: &[u8],
format: Format,
extensions: MarkdownExtensions,
) -> Result<Self, Error>
pub fn parse_with( input: &[u8], format: Format, extensions: MarkdownExtensions, ) -> Result<Self, Error>
Like Document::parse, plus Markdown extensions to enable (ignored
for other formats) — the read-path counterpart of Editor::new_ext.
Enable MarkdownExtensions::html_elements here to make embedded HTML
(<img>, <picture>, …) queryable via Document::query instead of
arriving as opaque raw HTML.
Sourcepub fn parse_str_with(
input: &str,
format: Format,
extensions: MarkdownExtensions,
) -> Result<Self, Error>
pub fn parse_str_with( input: &str, format: Format, extensions: MarkdownExtensions, ) -> Result<Self, Error>
Document::parse_with for a &str.
Sourcepub fn render_html(&mut self) -> Result<Vec<u8>, Error>
pub fn render_html(&mut self) -> Result<Vec<u8>, Error>
Render the document to HTML. For Djot/Markdown this is the rich rendering path that resolves reference/footnote side tables.
Sourcepub fn serialize_to(&mut self, target: Target) -> Result<Vec<u8>, Error>
pub fn serialize_to(&mut self, target: Target) -> Result<Vec<u8>, Error>
Serialize the document to target’s own syntax: a round-trip when
target names the document’s own format, cross-format conversion
otherwise (e.g. parse Markdown, serialize as Djot). Returns
Error::UnsupportedFormat when the requested direction has no
serializer (today: converting into XML from another format).
Prefer this over Document::serialize: serializing is a question about
where the bytes are going, so it takes a Target. The older spelling
takes a Format and still works — every Format is a Target — but
it cannot name an export-only target, and this one can.
Sourcepub fn serialize(&mut self, format: Format) -> Result<Vec<u8>, Error>
pub fn serialize(&mut self, format: Format) -> Result<Vec<u8>, Error>
Serialize the document to format’s own source syntax.
The original spelling of Document::serialize_to, kept for
compatibility and defined in terms of it. It types the output axis as
Format, which is the input vocabulary; reach for serialize_to in
new code.
Sourcepub fn ast_json(&mut self) -> Result<Vec<u8>, Error>
pub fn ast_json(&mut self) -> Result<Vec<u8>, Error>
Encode the document’s AST as pretty-printed JSON (the same encoding as
twig convert -o ast).
Sourcepub fn query(&mut self, selector: &str) -> Result<Vec<QueryMatch>, Error>
pub fn query(&mut self, selector: &str) -> Result<Vec<QueryMatch>, Error>
Resolve a CSS-lite selector (e.g. heading[level=2],
link[dest^="http"], code, list > item) against the document,
returning one QueryMatch per matching node in document order. A
malformed selector yields Error::InvalidArgument.
This is the general replacement for scanning code spans by hand: a
verbatim / code_block / raw_inline / raw_block selector recovers
those, and every other node kind is reachable too.
Sourcepub fn span(&mut self, node: NodeId) -> Result<Range<usize>, Error>
pub fn span(&mut self, node: NodeId) -> Result<Range<usize>, Error>
Return the whole source span of node without running a selector query.
Sourcepub fn content_span(
&mut self,
node: NodeId,
) -> Result<Option<Range<usize>>, Error>
pub fn content_span( &mut self, node: NodeId, ) -> Result<Option<Range<usize>>, Error>
Return the interior span of node, or None when the node has no
recorded content span.
Sourcepub fn marker_span(
&mut self,
node: NodeId,
) -> Result<Option<Range<usize>>, Error>
pub fn marker_span( &mut self, node: NodeId, ) -> Result<Option<Range<usize>>, Error>
The span of node’s own leading MARKER — the leading bytes a rich view
HIDES on its opening line — or None when it has none. See
FlatNode::marker_span, which is the same answer inside a snapshot.
Sourcepub fn line_prefix(
&mut self,
offset: usize,
) -> Result<Option<Range<usize>>, Error>
pub fn line_prefix( &mut self, offset: usize, ) -> Result<Option<Range<usize>>, Error>
Everything HIDDEN before the content on the line byte offset sits on:
every marker a node OPENS that line with, and the indentation between
them, as one range running from the line start.
This is the assembled form of FlatNode::marker_span, which records
each node’s own marker alone. > 1. [ ] is four nodes’ markers plus
the spaces between them, and the union is contiguous from the line start
— so a caller gets one range to hide, or one width for a caret to step
over, rather than a chain to walk and stitch together itself.
None when nothing opens on this line — a CONTINUATION line, the second
line of a wrapped paragraph or of a block quote. That is a real answer
rather than a gap: what a continuation line repeats is a different
question (a quote re-emits > , a list item re-emits spaces) and is not
answerable from marker spans. Error::InvalidArgument if offset
exceeds the source length.
Sourcepub fn continuation_prefix(
&mut self,
offset: usize,
) -> Result<LinePrefix, Error>
pub fn continuation_prefix( &mut self, offset: usize, ) -> Result<LinePrefix, Error>
What a CONTINUATION LINE at offset must open with to stay inside every
container holding it.
The other half of Document::line_prefix, and not derivable from it.
That one reports the bytes ALREADY THERE on a line something opens, so it
hands back a range into the source. This one reports the bytes that WOULD
HAVE TO BE WRITTEN on a line nothing opens — a list item’s continuation
is spaces where its marker was, which is not source at all, so it is
built rather than pointed at.
A quote’s > is REPRODUCED (dropping it ends the quote); a list item’s
marker becomes its WIDTH IN SPACES (repeating it would open a second
item). Each container on the caret’s chain contributes the columns its
own marker occupies, on its own opening line — which may be a different
line for each of them, and is why this is a tree walk rather than a
re-read of one line:
> - a quote "> " + item "- " as width -> "> "
- a
- b outer item + inner item -> " "Empty at the top level, which is the correct prefix there: none.
Error::InvalidArgument if offset exceeds the source length.
Sourcepub fn blank_line_prefix(&mut self, offset: usize) -> Result<LinePrefix, Error>
pub fn blank_line_prefix(&mut self, offset: usize) -> Result<LinePrefix, Error>
What a BLANK line inside the containers at offset must carry.
A quote’s blank line still has to carry its > or the quote ENDS there;
a list item’s must carry nothing, because a blank line between two of an
item’s blocks is what makes its list loose and indenting it changes
nothing about that. So this is Document::continuation_prefix with its
trailing spaces cut back — which drops an item’s indent entirely and
leaves a quote marker standing.
The quote form is > and not > , because the space after the marker is
content indentation and a blank line has no content.
Sourcepub fn cell_extent(&mut self, node: NodeId) -> Result<Option<(u32, u32)>, Error>
pub fn cell_extent(&mut self, node: NodeId) -> Result<Option<(u32, u32)>, Error>
The grid extent of the cell at node — how many (columns, rows) it
occupies — or None when the node is not a cell. Both are at least 1,
and (1, 1) is the ordinary one-square cell; anything larger is a merged
cell from a format with a real grid (HTML’s colspan/rowspan, an rST
grid table). GFM and djot pipe tables always report (1, 1).
HTML’s rowspan="0" (“to the end of the row group”) is not a count and
reports 1; the source spelling survives on the node’s attributes.
This is an accessor rather than a FlatNode field because the C struct
it snapshots is ABI-frozen — see Document::span for the same shape.
Sourcepub fn nodes(&mut self) -> Result<Vec<FlatNode>, Error>
pub fn nodes(&mut self) -> Result<Vec<FlatNode>, Error>
Snapshot the whole tree as a flat FlatNode array (the JSON-free read
path for a renderer), indexed so nodes[i].id == NodeId(i). Walk it via
the parent/first_child/next_sibling links; the root is the node
whose parent is None.
Sourcepub fn definitions(&mut self) -> Result<Vec<QueryMatch>, Error>
pub fn definitions(&mut self) -> Result<Vec<QueryMatch>, Error>
The document-level definitions: every node that hangs off no parent and is not the document root, in arena order. Usually empty.
A parsed document is not one tree. Footnote definitions and
link-reference definitions are resolved by LABEL rather than by
position, so twig attaches them to nothing — walking from the root over
FlatNode::first_child never reaches them, and a renderer that wants
to resolve [^1] has to find the definition some other way. This is
that way, and it replaces scanning the whole Document::nodes array
for entries whose parent is None.
Not filtered to a kind list: WHICH kinds end up detached is a property
of how a format resolves its definitions (djot and Markdown detach
Kind::Footnote and Kind::Reference; rST adds Kind::Citation
and Kind::Substitution), not something a caller should enumerate.
Read the kind on each match.
Sourcepub fn diagnostics(&mut self, target: Target) -> Result<Vec<Warning>, Error>
pub fn diagnostics(&mut self, target: Target) -> Result<Vec<Warning>, Error>
What converting this document to target would silently lose: one
Warning per lossy node, in document order. An empty vec means the
conversion is lossless.
Twig’s serializers degrade or drop a node whenever the target has no
spelling for it — a djot {=mark=} written into Markdown comes back as
plain text, an HTML comment converted to djot vanishes entirely. None of
it is an error, so all of it happens quietly. This is the call that makes
it loud, and it replaces guessing from the outside: the answers are
measured against the serializers by a round-trip probe in the Zig
library, not asserted.
The answer belongs to the (document, target) PAIR, not to the document —
the same document has different answers for different targets, which is
why this takes one and why nothing is cached on Document itself.
Error::UnsupportedFormat for a target with no serializer at all
(Target::Xml, Target::Asciidoc): “this cannot be written” is a
capability answer, not a per-node diagnosis.
Sourcepub fn children(
&mut self,
node: Option<NodeId>,
) -> Result<Vec<QueryMatch>, Error>
pub fn children( &mut self, node: Option<NodeId>, ) -> Result<Vec<QueryMatch>, Error>
The direct children of node as QueryMatches (id, span, kind) —
None enumerates the document root’s children (the top-level blocks).
The cheap enumeration an incremental renderer walks to decide which
blocks to re-marshal with Document::subtree. A childless node yields
an empty vec.
Sourcepub fn subtree(&mut self, node: NodeId) -> Result<Vec<FlatNode>, Error>
pub fn subtree(&mut self, node: NodeId) -> Result<Vec<FlatNode>, Error>
Snapshot the subtree rooted at node as a self-contained FlatNode
array with local ids: array[0] is the root, every link is an index
into the returned vec (or None), and spans stay absolute. The root’s
parent and next_sibling are None, so a walk from index 0 stays
inside the subtree. Error::InvalidArgument if node is out of range.
Sourcepub fn node_at(&mut self, offset: usize) -> Result<Option<QueryMatch>, Error>
pub fn node_at(&mut self, offset: usize) -> Result<Option<QueryMatch>, Error>
The deepest node whose span contains byte offset (with offset equal
to the source length treated as inside the root) — hit-testing and
cursor context. Ok(None) if no node covers the offset;
Error::InvalidArgument if offset exceeds the source length.
Sourcepub fn ancestors_at(&mut self, offset: usize) -> Result<Vec<QueryMatch>, Error>
pub fn ancestors_at(&mut self, offset: usize) -> Result<Vec<QueryMatch>, Error>
The chain of nodes containing byte offset, root-first down to the
deepest (the node Document::node_at returns) — the ancestor path for
a breadcrumb. Empty if no node covers the offset.
Sourcepub fn node_at_caret(
&mut self,
offset: usize,
) -> Result<Option<QueryMatch>, Error>
pub fn node_at_caret( &mut self, offset: usize, ) -> Result<Option<QueryMatch>, Error>
Document::node_at under CARET containment — the same descent, under
the rule an editing caret needs rather than the one a byte range needs.
Two differences, both because a caret is a position BETWEEN bytes while a span is a range OF bytes:
-
A block’s end is inside it. A caret after the last character of a paragraph is in that paragraph — it is where you stand to type the rest of it. Half-open containment puts it outside, which is why a consumer probing
Document::ancestors_atends up guessing at contrived offsets (the content start,caret - 1, a marker byte) to find the block it was plainly inside of. -
A trailing newline is not part of the block, which is what makes the two authorable formats AGREE. Djot ends a paragraph’s span after its newline and Markdown before it, so on
"a\n\nb\n"the caret at offset 1 read asparathrough Djot anddocthrough Markdown — the same caret, two answers, decided by which parser produced the tree.
Never Ok(None) for a non-empty document: a caret in the gap between two
blocks reports the container holding the gap (usually the root) rather
than nothing at all.
Sourcepub fn ancestors_at_caret(
&mut self,
offset: usize,
) -> Result<Vec<QueryMatch>, Error>
pub fn ancestors_at_caret( &mut self, offset: usize, ) -> Result<Vec<QueryMatch>, Error>
Document::ancestors_at under caret containment — root-first down to
the node Document::node_at_caret returns. See that method for the
containment rule and why it differs.