Skip to main content

DocumentView

Struct DocumentView 

Source
pub struct DocumentView<'a> { /* private fields */ }
Expand description

A Document borrowed from an Editor (see Editor::document): the editor’s live tree behind the whole document read surface, without a parse.

It holds the editor mutably borrowed for as long as it lives, so the tree — and every node id and span read out of it — cannot change underneath it. Dropping it frees nothing; the editor owns the tree.

Document::render_html and Document::serialize are the two methods it cannot serve (Error::UnsupportedFormat — they need a real parse’s language tag and side tables). Parse Editor::source for those.

Methods from Deref<Target = Document>§

Source

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.

Source

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.

Source

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.

Source

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).

Source

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.

Source

pub fn span(&mut self, node: NodeId) -> Result<Range<usize>, Error>

Return the whole source span of node without running a selector query.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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:

  1. 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_at ends up guessing at contrived offsets (the content start, caret - 1, a marker byte) to find the block it was plainly inside of.

  2. 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 as para through Djot and doc through 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.

Source

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.

Trait Implementations§

Source§

impl<'a> Debug for DocumentView<'a>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Deref for DocumentView<'_>

Source§

type Target = Document

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Document

Dereferences the value.
Source§

impl DerefMut for DocumentView<'_>

Source§

fn deref_mut(&mut self) -> &mut Document

Mutably dereferences the value.

Auto Trait Implementations§

§

impl<'a> !Send for DocumentView<'a>

§

impl<'a> !Sync for DocumentView<'a>

§

impl<'a> !UnwindSafe for DocumentView<'a>

§

impl<'a> Freeze for DocumentView<'a>

§

impl<'a> RefUnwindSafe for DocumentView<'a>

§

impl<'a> Unpin for DocumentView<'a>

§

impl<'a> UnsafeUnpin for DocumentView<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.