# Hiccup for Typst Content - Prototype ## The Idea Hiccup represents markup as nested data structures: ```clojure [:tag {attrs} & children] ``` ## Syntax Mapping ### Clojure-Typst Hiccup → Typst Output ```clojure ;; Heading [:heading {:level 2} "My Section"] ;; => #heading(level: 2)[My Section] ;; Inline formatting (paragraphs are implicit in Typst) ["Hello " [:strong "world"] " and " [:emph "goodbye"]] ;; => Hello #strong[world] and #emph[goodbye] ;; Lists (children are direct content, not :item tags) [:list "First thing" "Second thing" [[:strong "Important"] " third thing"]] ;; => #list( ;; [First thing], ;; [Second thing], ;; [#strong[Important] third thing] ;; ) ;; Tables (cells are direct content, not :cell tags) [:table {:columns 3} "A" "B" "C" "1" "2" "3"] ;; => #table(columns: 3, ;; [A], [B], [C], ;; [1], [2], [3] ;; ) ;; Code blocks (use :raw for displayed code) [:raw {:lang "python" :block true} "print('hello')"] ;; => #raw(lang: "python", block: true, "print('hello')") ;; Math (inline by default) [:math "x^2 + y^2 = z^2"] ;; => $x^2 + y^2 = z^2$ ;; Math (block/display) [:math {:block true} "sum_(i=0)^n i = (n(n+1))/2"] ;; => $ sum_(i=0)^n i = (n(n+1))/2 $ ;; Images (src in attrs, no children) [:image {:src "diagram.png" :width "50%"}] ;; => #image("diagram.png", width: 50%) ;; Links (src in attrs, child is display text) [:link {:src "https://typst.app"} "Typst"] ;; => #link("https://typst.app")[Typst] ``` ## Full Document Example ```clojure (def my-doc [[: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" "Step three"] [:heading {:level 2} "Results"] "The result is " [:math "x = 42"] "." [:table {:columns 2} [:strong "Input"] [:strong "Output"] "1" "1" "2" "4" "3" "9"]]) ``` **Compiles to:** ```typst #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], [Step three] ) #heading(level: 2)[Results] The result is $x = 42$. #table(columns: 2, [#strong[Input]], [#strong[Output]], [1], [1], [2], [4], [3], [9] ) ``` ## Mixing Code and Content ```clojure ;; Define a reusable component (defn author-block [name institution] [:block {:align "center"} [:strong name] [:linebreak] [:emph institution]]) ;; Use it with data (def authors [{:name "Alice" :inst "MIT"} {:name "Bob" :inst "Stanford"}]) ;; Generate content programmatically [[:heading "Authors"] (for [{:keys [name inst]} authors] (author-block name inst))] ``` ## Special Forms for Content ```clojure ;; Conditional content (strings become paragraphs naturally) (if peer-reviewed? "This paper was peer reviewed." "Preprint - not yet reviewed.") ;; Loop over data (items are direct content in lists) [:list (for [item items] (format-item item))] ;; Let bindings for intermediate content (let [title (get-title data) abstract (get-abstract data)] [[:heading title] abstract]) ``` ## The Alternative: Lisp for Code Only If hiccup feels too heavy, we could just use Lisp for logic and escape to raw Typst: ```clojure (defn factorial [n] (if (<= n 1) 1 (* n (factorial (dec n))))) ;; Escape to typst content #t" = Results The factorial of 5 is ~(factorial 5). Here's a table of factorials: ~(for [i (range 1 11)] (str \"- \" i \"! = \" (factorial i) \"\\n\")) " ``` ## Questions 1. **Implicit paragraphs?** Should adjacent strings auto-wrap in `[:p ...]`? 2. **Shorthand syntax?** Maybe `:#strong` instead of `[:strong ...]`? 3. **Component system?** How fancy do we get with reusable components? 4. **Escaping?** How to include literal `[` or other special chars? 5. **Whitespace handling?** Typst is whitespace-sensitive in content mode ## Verdict? Hiccup gives us: - ✅ Pure data representation of documents - ✅ Full programmatic control - ✅ Composable components - ✅ Familiar to Clojure devs But: - ❌ More verbose than raw Typst markup - ❌ Loses Typst's nice content syntax - ❌ Another layer to learn **Hybrid approach might be best:** Lisp for code/logic, with easy escape to Typst content syntax when you just want to write prose.