Pamphlet

Package Version Hex Docs

Render djot documents with custom elements and url schemes.

Rendering links, images, raw HTML, and symbols often need knowledge the document does not have: asset fingerprints, CDN hosts, valid page routes, async manifests, or build-time reports. Pamphlet exposes those decisions as continuations.

Targets

Pamphlet supports rendering back to djot/markdown, useful for llm.txt and .md pages and lustre for web pages and web apps.

Front matter

Defines pages with frontmatter deliminated by ---. Currently parses frontmatter to string key and value list.

Rendering

All these examples use symbol but the renderer also provides hooks for urls and raw blocks. Building on continuations we can make custom renderers with their own control logic.

Pure renderer

This renderer always succeeds and transforms thumbs down to thumbs up.

import pamphlet
import pamphlet/djot

pub fn cheerful_symbol_render(text: String) -> String {
  let renderer =
    djot.Renderer(..djot.default(), resolve_symbol: fn(name) {
      fn(callback) {
        case name {
          "-1" -> ":+1:"
          name -> ":" <> name <> ":"
        }
        |> callback
      }
    })

  let #(_frontmatter, doc) = pamphlet.parse(text)
  djot.to_markup(doc, renderer)(fn(x) { x })
}

pub fn cheerful_render_test() {
  let out =
    ":-1: and :+1:"
    |> cheerful_symbol_render()
  assert ":+1: and :+1:" == out
}

Aborting renderer

This renderer will halt if anyone uses the turd symbol.

import pamphlet
import pamphlet/djot

pub fn check_turd_symbol_render(text: String) -> Result(String, Nil) {
  let renderer =
    djot.Renderer(..djot.default(), resolve_symbol: fn(name) {
      fn(callback) {
        case name {
          "turd" -> Error(Nil)
          name -> callback(":" <> name <> ":")
        }
      }
    })

  let #(_frontmatter, doc) = pamphlet.parse(text)
  djot.to_markup(doc, renderer)(Ok)
}

pub fn check_render_test() {
  let out =
    ":-1: and :+1:"
    |> check_turd_symbol_render()
  assert Ok(":-1: and :+1:") == out

  let out =
    ":turd: and :+1:"
    |> check_turd_symbol_render()
  assert Error(Nil) == out
}

Stateful renderer

This renderer collects the set of all symbols used.

import gleam/set
import pamphlet
import pamphlet/djot

pub fn list_symbols_render(text) {
  let renderer =
    djot.Renderer(..djot.default(), resolve_symbol: fn(name) {
      fn(callback) {
        let #(page, acc) = callback(":" <> name <> ":")
        #(page, set.insert(acc, name))
      }
    })

  let #(_frontmatter, doc) = pamphlet.parse(text)
  djot.to_markup(doc, renderer)(fn(page) { #(page, set.new()) })
}

pub fn list_symbols_render_test() {
  let #(page, symbols) =
    ":-1: and :+1:"
    |> list_symbols_render()
  assert ":-1: and :+1:" == page
  assert set.from_list(["-1", "+1"]) == symbols
}

Development

gleam run   # Run the project
gleam test  # Run the tests
Search Document