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.

Search Document