pamphlet/lustre
Render djot documents to lustre elements.
The rendering follows jot.document_to_html as closely as possible —
the same function names, the same case order, the same footnote
bookkeeping — so the two targets stay easy to compare. Where jot appends
to an HTML string, this module appends Elements to a tree.
Like the markup renderer in pamphlet/djot, the special forms are
resolved in the continuation monad: each resolver takes what was written
in the source and returns a Cont(t, a). A pure lookup is continuation.return;
an effectful one can do whatever the answer type t allows before
calling the continuation — or never call it at all. Raw blocks and raw
inlines produce lustre elements directly, so the Renderer(msg, t) is
also polymorphic in the host application’s message type.
Types
How the special forms of a document are rendered to lustre elements.
resolve_url and resolve_symbol are lookups from what was written in
the source to what should appear in the output, as in the markup
renderer. Raw blocks (```=html) and raw inlines
(`…`{=html}) are payloads addressed directly to the output, so
their resolvers continue with Elements; msg is the message type of
those elements, and of everything the render produces.
Each resolver returns a Cont(t, a): a function that receives the rest
of the render as a continuation. t is the answer type of the whole
render — a resolver may perform effects before continuing, or finish the
render itself by returning a t without calling the continuation.
Start from default() and override individual forms with a record
update.
pub type Renderer(msg, t) {
Renderer(
resolve_url: fn(String) -> fn(fn(String) -> t) -> t,
resolve_raw_block: fn(String) -> fn(
fn(element.Element(msg)) -> t,
) -> t,
resolve_raw_inline: fn(String) -> fn(
fn(element.Element(msg)) -> t,
) -> t,
resolve_symbol: fn(String) -> fn(fn(String) -> t) -> t,
)
}
Constructors
-
Renderer( resolve_url: fn(String) -> fn(fn(String) -> t) -> t, resolve_raw_block: fn(String) -> fn( fn(element.Element(msg)) -> t, ) -> t, resolve_raw_inline: fn(String) -> fn( fn(element.Element(msg)) -> t, ) -> t, resolve_symbol: fn(String) -> fn(fn(String) -> t) -> t, )
Values
pub fn default() -> Renderer(msg, t)
A renderer that matches jot.document_to_html as closely as lustre
allows.
URLs pass through untouched and symbols render as written inside jot’s
<span class="symbol">. Raw content cannot be spliced into a lustre
tree without a wrapper element, so raw blocks render inside a <div>
and raw inlines inside a <span>, both via
element.unsafe_raw_html — as with jot.document_to_html, the content
is not escaped, so override these for untrusted documents.
pub fn to_lustre(
document: jot.Document,
renderer: Renderer(msg, t),
) -> fn(fn(element.Element(msg)) -> t) -> t
Render a document to a lustre element. Special forms are resolved through the given renderer.
The document’s containers (and the footnote section, when the document
uses footnotes) are returned as an element.fragment.
The result is a Cont(t, Element(msg)): apply it to a final
continuation to run the render. A pure renderer runs at any answer
type — to_lustre(document, default())(fn(element) { element }) — while
with t = Result(Element(msg), e) a resolver can halt the render by
returning an Error instead of continuing, and the final continuation
is Ok.