Expand description
Syntax highlighting for the source view — the AST read as markup rather than as rendered text.
crate::View::Wysiwyg resolves the document’s markup away and styles what
is left; crate::View::Source shows the markup itself, and until now
showed it unstyled. This module is the missing half: a SourceMap of
styled byte ranges over Doc::source, so a frontend painting raw source can
tell a heading from its # , a link from its destination, and a fence from
the code inside it.
§Why this and not a syntax-highlighting library
leaf already has a parse of these exact bytes — twig’s, the one the caret rides. A second parser (syntect, tree-sitter) is a second opinion about what the document is, and the two disagreeing is visible: text painted as emphasis that the editor then refuses to treat as emphasis. Reading the styling off the same AST the editing model uses makes that class of bug unrepresentable.
It also costs nothing per format. twig normalizes Markdown, Djot, HTML and
XML into one Kind vocabulary, so <b>bold</b>, **bold** and *bold*
all arrive as Kind::Strong and are styled by the same line of code.
§The rule
Every node knows its whole extent (FlatNode::span) and, where it has
delimiters, the extent of what is inside them
(FlatNode::content_span). The difference between the two is exactly the
markup:
[link](https://example.dev)
^^^^^^^^^^^^^^^^^^^^^^^^^^^ span
^^^^ content_span
^ ^^^^^^^^^^^^^^^^^^^^^^ the gaps — the markupSo the whole highlighter is: style a node’s span by its kind, then restyle
the bytes its content doesn’t cover as Role::Delimiter. Children paint
over their parents, inheriting the parent’s style the same way
crate::wysiwyg threads a base down the tree — which is what keeps
*em* inside a heading both heading-colored and italic.
§What it does not do
The inner language of a fenced code block. ```rust gets
Role::Code over the whole body; twig knows the fence and the info string,
not Rust. Highlighting that is the one job an external highlighter is
actually right for, and it belongs in the frontends that can afford the
dependency — not in a core that also ships to wasm and iOS.
Bytes no node covers. A link-reference definition and a footnote
definition hang off no parent (see Editor::definitions), and twig leaves
some inter-element whitespace unparented; the walk starts at the root, so
those stay Role::Body. Unstyled is the correct failure here — the text is
still the text.
Structs§
- Source
Map - The source view’s styling, as non-overlapping runs in ascending order.
- Styled
Run - A run of source bytes that share one style. Ranges are source byte offsets,
like the caret and
crate::Highlight, so nothing has to be converted to paint one.
Functions§
- build
- Style the source of a parsed document.