Files
typlisp/typst-mapping.md
2026-01-30 09:11:34 -10:00

7.1 KiB

Hiccup → Typst Mapping Reference

Audit of Current Tags

Valid - Direct Typst Functions

Hiccup Typst Notes
[:heading {:level 2} "Text"] #heading(level: 2)[Text] Works
[:strong "text"] #strong[text] Works
[:emph "text"] #emph[text] Works
[:link {:dest "url"} "text"] #link("url")[text] Works
[:image {:width "50%"} "path.png"] #image("path.png", width: 50%) Works
[:block {:inset "1em"} ...] #block(inset: 1em)[...] Works
[:bibliography "refs.bib"] #bibliography("refs.bib") Works

Invalid - Don't Exist in Typst

Bad Hiccup Problem Fix
[:p "text"] No paragraph function Just use strings, paragraphs are implicit
[:item "text"] Not a function Items are args to list()
[:cell "text"] Not a function Cells are args to table()
[:div ...] HTML, not Typst Use [:block ...]
[:span ...] HTML, not Typst Just inline content, or [:box ...]
[:aside ...] Doesn't exist Use [:block ...] with styling
[:section ...] Doesn't exist Just use headings
[:doc ...] Doesn't exist Top-level is just content
[:table-row ...] Doesn't exist Tables are flat

⚠️ Needs Adjustment

Current Problem Correct
[:linebreak] Function name [:linebreak]#linebreak() actually works
[:h-space "2em"] Wrong name [:h "2em"]#h(2em)
[:figure [:image ...] [:caption ...]] Caption isn't a child See below
[:math "x^2"] Need to distinguish inline/block $x^2$ vs $ x^2 $
[:code {:lang "py"} "..."] Function is raw #raw(lang: "python", "...")
[:ref :label] Takes label not string #ref(<label>)
[:cite :key] Takes label #cite(<key>)

Corrected Mappings

Lists

Typst list takes content blocks as positional args, not :item children:

;; OLD (wrong)
[:list
  [:item "First"]
  [:item "Second"]]

;; NEW (correct)
[:list "First" "Second"]
;; => #list([First], [Second])

;; With formatted items
[:list
  [:strong "Important"]
  "Regular item"]
;; => #list([#strong[Important]], [Regular item])

;; Nested
[:list
  "Top level"
  [:list "Nested 1" "Nested 2"]]

Typst output:

#list(
  [First],
  [Second],
)

Tables

Same pattern - cells are positional args:

;; OLD (wrong)
[:table {:columns 2}
  [:cell "A"] [:cell "B"]
  [:cell "1"] [:cell "2"]]

;; NEW (correct)
[:table {:columns 2}
  "A" "B"
  "1" "2"]
;; => #table(columns: 2, [A], [B], [1], [2])

;; With formatting
[:table {:columns 2}
  [:strong "Header 1"] [:strong "Header 2"]
  "Data 1" "Data 2"]

Typst output:

#table(
  columns: 2,
  [#strong[Header 1]], [#strong[Header 2]],
  [Data 1], [Data 2],
)

Figures

Caption is a named parameter, not a child element:

;; OLD (wrong)
[:figure
  [:image "arch.png"]
  [:caption "Architecture diagram"]]

;; NEW (correct)
[:figure {:caption "Architecture diagram"}
  [:image "arch.png"]]
;; => #figure(image("arch.png"), caption: [Architecture diagram])

;; With label for referencing
[:figure {:caption "Architecture" :label :fig:arch}
  [:image {:width "80%"} "arch.png"]]
;; => #figure(image("arch.png", width: 80%), caption: [Architecture]) <fig:arch>

Typst output:

#figure(
  image("arch.png", width: 80%),
  caption: [Architecture],
) <fig:arch>

Math

;; Inline math
[:$ "x^2 + y^2"]
;; => $x^2 + y^2$

;; Block/display math
[:$$ "sum_(i=0)^n i"]
;; => $ sum_(i=0)^n i $

;; Or with explicit flag
[:math "x^2"]           ;; inline by default
[:math {:block true} "sum_(i=0)^n i"]

Code/Raw

;; Inline code
[:raw "let x = 1"]
;; => `let x = 1`

;; Code block with language
[:raw {:lang "python" :block true} "print('hello')"]
;; => ```python
;;    print('hello')
;;    ```

Typst output:

#raw("let x = 1")
#raw(lang: "python", block: true, "print('hello')")

References and Citations

;; Reference a label
[:ref :fig:arch]
;; => @fig:arch

;; Citation
[:cite :smith2020]
;; => @smith2020

;; Multiple citations
[:cite :smith2020 :jones2021]
;; => @smith2020 @jones2021

Horizontal/Vertical Space

[:h "2em"]    ;; => #h(2em)
[:v "1em"]    ;; => #v(1em)

Page/Document Settings

set rules are special - they affect following content:

;; Set rules (affects everything after)
[:set :page {:paper "a4" :margin "2cm"}]
;; => #set page(paper: "a4", margin: 2cm)

[:set :text {:font "New Computer Modern" :size "11pt"}]
;; => #set text(font: "New Computer Modern", size: 11pt)

;; Show rules
[:show :heading {:set {:text {:fill "blue"}}}]
;; => #show heading: set text(fill: blue)

Paragraphs

There is no paragraph function. Paragraphs are created by blank lines:

;; Just strings, separated by [:parbreak] or blank content
"First paragraph."
[:parbreak]
"Second paragraph."

;; Or in raw mode, just write naturally
#t"
First paragraph.

Second paragraph.
"

Revised Full Example

(def my-doc
  [;; Set rules at top
   [:set :page {:paper "a4"}]
   [:set :text {:font "Linux Libertine"}]

   [:heading {:level 1} "My Paper"]

   "This is the introduction. We discuss "
   [:emph "important things"] "."

   [:parbreak]

   [:heading {:level 2} "Methods"]

   "We used the following approach:"

   [:list
     "Step one"
     "Step two"
     [:strong "Step three (important)"]]

   [:heading {:level 2} "Results"]

   "See " [:ref :fig:results] " and " [:ref :tab:data] "."

   [:figure {:caption "Results visualization" :label :fig:results}
     [:image {:width "80%"} "results.png"]]

   [:table {:columns 2 :label :tab:data}
     [:strong "Input"] [:strong "Output"]
     "1" "1"
     "2" "4"
     "3" "9"]

   "The equation is " [:$ "E = mc^2"] "."

   [:$$ "integral_0^infinity e^(-x^2) dif x = sqrt(pi)/2"]

   [:bibliography "refs.bib"]])

Compiles to:

#set page(paper: "a4")
#set text(font: "Linux Libertine")

#heading(level: 1)[My Paper]

This is the introduction. We discuss #emph[important things].

#heading(level: 2)[Methods]

We used the following approach:

#list(
  [Step one],
  [Step two],
  [#strong[Step three (important)]],
)

#heading(level: 2)[Results]

See @fig:results and @tab:data.

#figure(
  image("results.png", width: 80%),
  caption: [Results visualization],
) <fig:results>

#table(
  columns: 2,
  [#strong[Input]], [#strong[Output]],
  [1], [1],
  [2], [4],
  [3], [9],
) <tab:data>

The equation is $E = mc^2$.

$ integral_0^infinity e^(-x^2) dif x = sqrt(pi)/2 $

#bibliography("refs.bib")

Summary of Changes

  1. Removed: :p, :item, :cell, :div, :span, :aside, :section, :doc
  2. Lists/Tables: Children are direct content, not wrapped in :item/:cell
  3. Figures: Caption is an attribute, not a child
  4. Math: Use :$ for inline, :$$ for block
  5. Code: Use :raw not :code
  6. Space: Use :h/:v not :h-space
  7. Settings: :set takes element type and attrs
  8. Paragraphs: Use :parbreak or just content flow