On this page:
5.1 Core
current-metas
set-meta
?
5.1.1 Elements
default-element-function
define-element
5.2 Fetch
get-doc
get-meta
meta-ref
5.3 Parse
parse-markup-elements
5.4 Rendering
5.4.1 Rendering custom elements
5.4.2 HTML
doc->html
doc->html-xexpr
default-html-tag
punct-html-render%
5.4.3 Typst
doc->typst
default-typst-tag
escape-typst-text
escape-typst-string
punct-typst-render%
5.4.4 Plain text
doc->plaintext
make-plaintext-fallback
5.4.5 Base renderer
punct-abstract-render%
new
render-document
render-string
render-thematic-break
render-heading
render-code-block
render-html-block
render-paragraph
render-blockquote
render-itemization
render-item
render-line-break
render-bold
render-italic
render-code
render-link
render-image
render-html
render-footnote-reference
render-footnote-definition
9.0

5 Module Reference🔗

5.1 Core🔗

 (require punct/core) package: punct-lib

parameter

(current-metas)  (or/c hash-eq? #f)

(current-metas metas)  void?
  metas : (or/c hash-eq? #f)
A parameter that, during compilation of a Punct source, holds the metadata hash table for that file. The final value of this parameter becomes the value of document-metas for that file’s doc as well as its metas export.

The only key automatically defined in every metadata table is 'here-path, which holds the absolute path to the source file.

If no Punct file is currently being compiled, this parameter will hold #f by default. In particular, this parameter is not automatically set to a Punct file’s metas during the rendering phase (e.g., doc->html).

procedure

(set-meta key val)  void?

  key : symbol?
  val : (not/c procedure?)
Set the value of key in current-metas to val. If there are no current metas, an ugly exception is thrown.

syntax

(? key val-expr ...)

Within a Punct file, this macro can be used as shorthand for set-meta. Each key is given as a bare identifier (i.e., without using quote).

#lang punct
 
?[title "Example Title" author "Me"]
 
...

5.1.1 Elements🔗

 (require punct/element) package: punct-lib

The bindings provided by this module are also provided by punct/core.

procedure

(default-element-function tag 
  default-attr-kw 
  default-attr-val ...) 
  (->* () #:rest any/c xexpr?)
  tag : symbol?
  default-attr-kw : keyword?
  default-attr-val : string?
Returns a function which produces a tag custom element. This function takes any number of keyword arguments (which are converted to attributes) and non-keyword arguments (which become the child elements of this returned element).

You can also give keyword/value arguments to default-element-function itself; these will be set as default attributes/values in the custom element returned by the resulting function.

Examples:
> (define aside (default-element-function 'aside))
> (aside "Hello")

'(aside "Hello")

> (define kbd (default-element-function 'kbd #:alt "foo"))
> (kbd "CTRL")

'(kbd ((alt "foo")) "CTRL")

> (kbd "CTRL" #:data-code "1")

'(kbd ((alt "foo") (data-code "1")) "CTRL")

On Mac OS, type ALT+6 to produce § and ALT+7 to produce .

If tag ends in either § or , the resulting function will add a default block attribute of "root" or "single" respectively:

Examples:
> (define info (default-element-function 'info§))
> (info "Note!")

'(info ((block "root")) "Note!")

> (define mypar (default-element-function 'mypar¶))
> (mypar "Walnuts")

'(mypar ((block "single")) "Walnuts")

If tag has a suffix of the form .foo, the resulting function will add a default 'class attribute whose value is set to "foo". Multiple such suffixes will add additional values to the 'class attribute.

Examples:
> (define carton (default-element-function 'carton.xyz.abc))
> (carton "Cashews")

'(carton ((class "xyz abc")) "Cashews")

> (define crate (default-element-function 'crate¶.foo))
> (crate "Pecans")

'(crate ((block "single") (class "foo")) "Pecans")

Added in version 1.3 of package punct-lib.

syntax

(define-element id [default-attr-kw default-attr-val ...])

(define-element id tag [default-attr-kw default-attr-val ...])
 
  default-attr-kw : keyword?
  default-attr-val : string?
Shorthand macro for default-element-function.

If tag is supplied, it is used as the tag for the X-expressions generated by the resulting function:

> (define-element bowl container.bowl)
> (bowl "Corn nuts")

'(container ((class "bowl")) "Corn nuts")

> (define-element jar vessel¶ #:type "Glass")
> (jar "Chestnuts")

'(vessel ((type "Glass") (block "single")) "Chestnuts")

If tag is not supplied, the first argument is used both as the identifier for the function and for the tag in generated X-expressions:

> (define-element bag.xyz.abc)
> (bag "Sunflower seeds")

'(bag ((class "xyz abc")) "Sunflower seeds")

> (define-element packet¶.foo)
> (packet "Raisins")

'(packet ((block "single") (class "foo")) "Raisins")

Added in version 1.3 of package punct-lib.

5.2 Fetch🔗

 (require punct/fetch) package: punct-lib

procedure

(get-doc src)  document?

  src : path-string?
Returns the doc binding from src. No caching is used; this function is basically a thin wrapper around dynamic-require. If src does not exist, you will get a friendly error message. If any other kind of problem arises, you will get an ugly error.

procedure

(get-meta doc key [default])  any/c

  doc : document?
  key : symbol?
  default : failure-result/c
   = (lambda () (raise (make-exn:fail ....)))
Returns the value of key in the document-metas of doc. The value of default is used if the key does not exist: if it is a value, that value will be returned instead; if it is a thunk, the thunk will be called.

Changed in version 1.1 of package punct-lib: Removed get-doc-ref and replaced with get-meta

procedure

(meta-ref doc key)  any/c

  doc : document?
  key : symbol?
Equivalent to (get-meta doc key #f). Provided for compatibility.

5.3 Parse🔗

 (require punct/parse) package: punct-lib

procedure

(parse-markup-elements metas 
  elements 
  #:extract-inline? extract? 
  #:parse-footnotes? parse-fn?) 
  (or/c document? (listof xexpr?))
  metas : hash-eq?
  elements : list
  extract? : #t
  parse-fn? : #f
Parses elements into a Punct AST by serializing everything as strings, sending the string through the commonmark parser, and then converting the result into a Punct document, reconstituting any custom elements in the process.

If #:extract-inline? is #true, and if the parsed document contains only a single paragraph element at the root level, then the elements inside the paragraph are returned as a list (the paragraph is "shucked"). Otherwise, the entire result is returned as a document.

The #:parse-footnotes? argument determines whether the commonmark parser will parse Markdown-style footnote references and definitions in elements.

Examples:
> (define elems
    '("# Title\n\nA paragraph with *italic* text, and "
      1
      (custom "custom element")))
> (parse-markup-elements (hasheq) elems)

(document

 '#hasheq()

 '((heading ((level "1")) "Title")

   (paragraph

    "A paragraph with "

    (italic "italic")

    " text, and 1"

    (custom "custom element")))

 '())

5.4 Rendering🔗

Punct currently includes renderers for HTML, Typst, and plain-text. These are based on a "base" renderer class that you can extend to customize the rendering process or to target new output formats.

5.4.1 Rendering custom elements🔗

When rendering your document to a specific output format (such as HTML) Punct has to decide how to render any custom elements introduced by your code. When Punct encounters a custom element, it passes it to a fallback function: the fallback function receives three arguments: the custom element’s tag, its attributes, and a list of sub-elements found inside the element. The sub-elements will already have been fully processed by Punct.

A separate fallback function is needed for each output format you want to target. Punct provides default fallback functions the target output format it supports natively. For example, when targeting HTML, Punct defaults to default-html-tag, which simply converts custom elements to HTML elements. If you want more customized behavior, you’ll need to provide your own fallback procedure to the renderer.

Here’s an example pair of functions for rendering documents containing the custom abbreviation element (from the examples above) into HTML:

(define (custom-html tag attrs elems)
  (match (list tag attrs)
    [`(abbreviation [[term ,term]]) `(abbr [[title ,term]] ,@elems)]))
 
(define (my-html-renderer source-path)
  (doc->html (get-doc source-path) custom-html))

5.4.2 HTML🔗

 (require punct/render/html) package: punct-lib

procedure

(doc->html pdoc [fallback])  string?

  pdoc : document?
  fallback : 
(-> symbol?
    (listof (list/c symbol? string?))
    (listof xexpr?)
    xexpr?)
   = default-html-tag
Renders pdoc into a string containing HTML markup. Each custom element is passed to fallback, which must return an X-expression.

This function uses xexpr->string to generate the HTML string. This function will blindly escape characters inside <script> and <style> tags, which may introduce errors. For HTML output that is friendlier and more correct, consider using the html-printer package in concert with doc->html-xexpr.

For more information on using the fallback argument to render custom elements, see Rendering custom elements.

procedure

(doc->html-xexpr pdoc [fallback])  xexpr?

  pdoc : document?
  fallback : 
(-> symbol?
    (listof (list/c symbol? string?))
    (listof xexpr?)
    xexpr?)
   = default-html-tag
Renders pdoc into HTML, but in X-expression form rather than as a string. Each custom element is passed to fallback, which must itself return an X-expression.

For more information on using the fallback argument to render custom elements, see Rendering custom elements.

procedure

(default-html-tag tag attributes elements)  xexpr?

  tag : symbol?
  attributes : (listof (list/c symbol? string?))
  elements : (listof xexpr?)
Returns an X-expression comprised of tag, attributes and elements. Mainly used as the default fallback function for doc->html.

Examples:
> (require punct/render/html)
> (default-html-tag 'kbd '() '("Enter"))

'(kbd "Enter")

> (default-html-tag 'a '((href "http://example.com")) '("Link"))

'(a ((href "http://example.com")) "Link")

The HTML renderer class. Extends punct-abstract-render% to produce HTML output. You can extend this class to customize HTML rendering behavior.
See Extending the Renderer for examples of extending the HTML renderer.

5.4.3 Typst🔗

 (require punct/render/typst) package: punct-lib

Typst is a modern typesetting system designed as an alternative to LaTeX. This renderer produces Typst markup from Punct documents.

procedure

(doc->typst pdoc [fallback])  string?

  pdoc : document?
  fallback : (symbol? (listof (listof symbol? string?)) list? . -> . string?)
   = default-typst-tag
Renders pdoc into a string containing Typst markup. Any custom elements are passed to fallback, which must return a string.

Markdown/Punct elements are mapped to Typst syntax as follows:

Punct element

Typst output

Headings

= Heading (with levels as = count)

Bold

*text*

Italic

_text_

Inline code

`code`

Code blocks

```lang ... ```

Links

#link("url")[text]

Images

#image("path")

Bullet lists

- item

Numbered lists

+ item

Block quotes

#quote(block: true)[...]

Footnotes

#footnote[...] (inline)

Typst special characters (*, _, `, #, @, $, [, ]) in text content are automatically escaped, allowing the same Punct source to target both HTML and Typst without manual escaping. Content inside code blocks and inline code is not escaped, as Typst renders these literally.

For more information on using the fallback argument to render custom elements, see Rendering custom elements.

Added in version 1.4 of package punct-lib.

procedure

(default-typst-tag tag attributes elements)  string?

  tag : symbol?
  attributes : (listof (listof symbol? string?))
  elements : list?
Returns a Typst function call string using tag, attributes, and elements. Mainly used as the default fallback function for doc->typst.

The output format is #tag(attr: "val", ...)[content], where attributes become named arguments with string values, and elements become a trailing content block. When there are no attributes, the parentheses are omitted: #tag[content]. When there are no elements, the content block is omitted: #tag(attr: "val").

Hyphens in tag and attribute names are converted to underscores to produce valid Typst identifiers (e.g., 'my-element becomes my_element).

Note that elements are already escaped when passed to the fallback. Attribute values are automatically escaped and quoted as Typst strings.

Examples:
> (require punct/render/typst)
> (default-typst-tag 'note '() '("Important!"))

"#note[Important!]"

> (default-typst-tag 'note '((class "info")) '("Important!"))

"#note(class: \"info\")[Important!]"

> (default-typst-tag 'my-spacer '((line-height "2em")) '())

"#my_spacer(line_height: \"2em\")"

Added in version 1.4 of package punct-lib.

procedure

(escape-typst-text str)  string?

  str : string?
Escapes special Typst characters (*, _, `, #, @, $, [, ], \) in str by prefixing them with backslashes. Use this for text content in custom fallback procedures.

Added in version 1.4 of package punct-lib.

procedure

(escape-typst-string str)  string?

  str : string?
Escapes backslashes and double quotes in str for use within quoted Typst strings (e.g., URLs or file paths in function arguments like #link("...") or #image("...")).

Added in version 1.4 of package punct-lib.

The Typst renderer class. Extends punct-abstract-render% to produce Typst markup output. You can extend this class to customize Typst rendering behavior.

Added in version 1.4 of package punct-lib.

5.4.4 Plain text🔗

 (require punct/render/plaintext) package: punct-lib

Sometimes you want to convert a document into a text format that is even plainer than Markdown, such as when generating the plaintext version of an email newsletter.

procedure

(doc->plaintext pdoc line-width [fallback])  string?

  pdoc : document?
  line-width : exact-nonnegative-integer?
  fallback : 
(-> symbol?
    (listof (list/c symbol? string?))
    (listof xexpr?)
    xexpr?)
   = (make-plaintext-fallback line-width)
Renders pdoc into a string of plain text, hard-wrapped to line-width characters (except for block-quotes, which are hard-wrapped to a length approximately 75% as long as line-width). Any custom elements are passed to fallback, which must return a string.

The function applies very rudimentary text formatting which usually looks as you would expect, but which often discards information.

  • Level 1 headings are underlined with =, and all other headings are underlined with -.

  • Link destination URLs are given inside parentheses directly following the link text.

  • Code blocks are indented with four spaces, and the language name, if any, is discarded.

  • Images are replaced with their "alt" text, prefixed by "Image: " and wrapped in parentheses; the source URL and title are discarded.

For more information on using the fallback argument to render custom elements, see Rendering custom elements.

Examples:
> (require punct/render/plaintext)
> (define email (parse-markup-elements (hasheq) '("# Issue No. 1\n\nHowdy!")))
> (display (doc->plaintext email 72))

Issue No. 1

===========

Howdy!

Returns a function that accepts three arguments (the tag, attributes and elements of an X-expression). Mainly used to create the default fallback procedure for doc->plaintext.

Examples:
> (define foo (make-plaintext-fallback 72))
> (foo 'kbd '() '("Enter"))

"[kbd] Enter\n\n"

> (foo 'a '((href "http://example.com")) '("Link"))

"[a] Link\n\n"

5.4.5 Base renderer🔗

 (require punct/render/base) package: punct-lib

class

punct-abstract-render% : class?

  superclass: object%

The abstract base class for all Punct renderers. To create a custom renderer, extend this class and implement all abstract methods. The built-in HTML, Typst, and plaintext renderers all extend this class.

constructor

(new punct-abstract-render% 
    [doc doc] 
    [render-fallback render-fallback]) 
  (is-a?/c punct-abstract-render%)
  doc : document?
  render-fallback : 
(-> symbol?
    (listof (list/c symbol? string?))
    list?
    any/c)
Creates a new renderer instance. The doc argument is the Punct document to render. The render-fallback procedure is called for any custom elements encountered during rendering.

method

(send a-punct-abstract-render render-document)  any/c

The main entry point for rendering. Calls the appropriate rendering methods for each element in the document body and footnotes.

The default implementation returns two values: a list of rendered body elements and a list of rendered footnotes. Subclasses typically override this to combine these into a single output value (e.g., a string or X-expression).

method

(send a-punct-abstract-render render-string s)  any/c

  s : string?
Called for every string in the document. Override this to transform raw text (e.g., for escaping special characters in the target format). The default implementation returns the string unchanged.A

Added in version 1.4 of package punct-lib.

To create a custom renderer, extend this class and implement all of the abstract methods below.

See Extending the Renderer for examples of extending the base renderer.

method

(send a-punct-abstract-render render-thematic-break)  any/c

method

(send a-punct-abstract-render render-heading level 
  rendered-elems) 
  any/c
  level : string?
  rendered-elems : list?

method

(send a-punct-abstract-render render-code-block info-string 
  raw-elems) 
  any/c
  info-string : string?
  raw-elems : list?

method

(send a-punct-abstract-render render-html-block raw-content)

  any/c
  raw-content : any/c

method

(send a-punct-abstract-render render-paragraph rendered-elems)

  any/c
  rendered-elems : list?

method

(send a-punct-abstract-render render-blockquote rendered-elems)

  any/c
  rendered-elems : list?

method

(send a-punct-abstract-render render-itemization 
  style 
  start 
  rendered-items) 
  any/c
  style : string?
  start : string?
  rendered-items : list?

method

(send a-punct-abstract-render render-item rendered-elems)

  any/c
  rendered-elems : list?

method

(send a-punct-abstract-render render-line-break)  any/c

method

(send a-punct-abstract-render render-bold rendered-elems)

  any/c
  rendered-elems : list?

method

(send a-punct-abstract-render render-italic rendered-elems)

  any/c
  rendered-elems : list?

method

(send a-punct-abstract-render render-code raw-elems)  any/c

  raw-elems : list?

method

(send a-punct-abstract-render render-link dest 
  title 
  rendered-elems) 
  any/c
  dest : string?
  title : string?
  rendered-elems : list?

method

(send a-punct-abstract-render render-image src    
  title    
  desc    
  raw-elems)  any/c
  src : string?
  title : string?
  desc : string?
  raw-elems : list?

method

(send a-punct-abstract-render render-html raw-content)  any/c

  raw-content : any/c

method

(send a-punct-abstract-render render-footnote-reference 
  label 
  defn-num 
  ref-num) 
  any/c
  label : string?
  defn-num : string?
  ref-num : string?

method

(send a-punct-abstract-render render-footnote-definition 
  label 
  ref-count 
  rendered-elems) 
  any/c
  label : string?
  ref-count : string?
  rendered-elems : list?