This commit is contained in:
2026-01-30 10:09:18 -10:00
parent 064481283e
commit 1cf47ea3e2
6 changed files with 208 additions and 1657 deletions
+208 -28
View File
@@ -17,6 +17,18 @@ Two modes coexist. Use whichever fits the moment.
### Mixing Freely
```clojure
(def title "My Document")
(def data [{:name "Alice" :value 100}
{:name "Bob" :value 200}])
(defn calculate-total [rows]
(reduce + (map :value rows)))
(defn render-table [rows]
[:table {:columns 2}
(for [row rows]
(list (:name row) (:value row)))])
[;; Hiccup for structured parts
[:heading {:level 1} title]
@@ -30,12 +42,10 @@ Two modes coexist. Use whichever fits the moment.
"
;; Back to hiccup for programmatic stuff
[:table {:columns 2}
(for [row data]
(list (:name row) (:value row)))]
(render-table data)
;; Raw with interpolation
#t"The answer is ~(calculate-answer data)."
#t"The total is ~(calculate-total data)."
;; Nested: raw inside hiccup
[:block {:inset "1em" :fill "gray.lighten(90%)"}
@@ -46,12 +56,35 @@ Two modes coexist. Use whichever fits the moment.
= Section
Here's a dynamic table:
~(render-table results)
~(render-table data)
And back to prose.
"]
```
```typst
#heading(level: 1)[My Document]
This is just regular Typst content. I can write *bold* and _italic_
without all the brackets. Much nicer for prose.
- Bullet one
- Bullet two
#table(columns: 2, [Alice], [100], [Bob], [200])
The total is 300.
#block(inset: 1em, fill: gray.lighten(90%))[This is a _sidebar_ with easy formatting.]
= Section
Here's a dynamic table:
#table(columns: 2, [Alice], [100], [Bob], [200])
And back to prose.
```
### Raw Escape Syntax
```clojure
@@ -74,15 +107,38 @@ Using `~()` - the unquote concept from Clojure's syntax-quote:
```clojure
;; Simple expression
#t"The value is ~(expr)."
(def answer 42)
#t"The value is ~answer."
```
```typst
The value is 42.
```
```clojure
;; Hiccup expression returns content
(def url "https://example.com")
(def label "here")
#t"Click ~([:link {:src url} label]) to continue."
```
```typst
Click #link("https://example.com")[here] to continue.
```
```clojure
;; Conditional
#t"Status: ~(if done? 'Complete' 'Pending')"
(def done true)
#t"Status: ~(if done 'Complete' 'Pending')"
```
```typst
Status: Complete
```
```clojure
;; Loop
(def items [{:name "Apples"} {:name "Oranges"}])
#t"
= Items
~(for [i items]
@@ -90,6 +146,12 @@ Using `~()` - the unquote concept from Clojure's syntax-quote:
"
```
```typst
= Items
- Apples
- Oranges
```
## Hiccup Syntax
All elements follow standard Hiccup:
@@ -352,54 +414,112 @@ It's a Lisp - of course we have macros.
(list ~@body)))
;; Use it
(when-content show-abstract?
(def show-abstract true)
(def abstract-text "This paper presents...")
(when-content show-abstract
[:heading {:level 2} "Abstract"]
abstract-text)
```
```typst
== Abstract
This paper presents...
```
### DSL Macros
```clojure
;; Math DSL
(defmacro math-block [& exprs]
`[:math {:block true}
~(compile-math-dsl exprs)])
(math-block
(sum :i 0 :n
(frac (pow x i) (factorial i))))
;; => $ sum_(i=0)^n x^i / i! $
;; Shorthand for references
;; Shorthand macros for references
(defmacro ref [id]
`[:ref {:target ~id}])
(defmacro cite [& keys]
`[:cite {:keys [~@keys]}])
(ref :fig/arch) ; => [:ref {:target :fig/arch}]
(cite :smith2020 :jones2021) ; => [:cite {:keys [:smith2020 :jones2021]}]
(ref :fig/arch)
(cite :smith2020 :jones2021)
```
```typst
@fig:arch
@smith2020 @jones2021
```
```clojure
;; Math helper functions
(defn sum [var from to body]
(str "sum_(" var "=" from ")^" to " " body))
(defn frac [num denom]
(str "(" num ") / (" denom ")"))
(defn pow [base exp]
(str base "^" exp))
;; Math block macro
(defmacro math-block [& body]
`[:math {:block true} (str ~@body)])
(math-block (sum "i" 0 "n" (frac (pow "x" "i") "i!")))
```
```typst
$ sum_(i=0)^n (x^i) / (i!) $
```
### Template Macros
```clojure
;; Helper functions for template rendering
(defn render-author [{:keys [name affil]}]
[:block {:align "center"}
[:strong name] [:linebreak]
[:emph affil]])
(defn render-authors [authors]
(map render-author authors))
(defn render-abstract [text]
[[:heading {:level 2} "Abstract"]
[:block {:inset "1em"} [:emph text]]])
;; Template macro - captures body and prepends document setup
(defmacro deftemplate [name params & preamble]
`(defmacro ~name [~@params & ~'body]
(concat ~@preamble ~'body)))
(deftemplate ieee-paper [title authors abstract]
[[:set {:element :page :paper "us-letter" :columns 2}]
[:heading {:level 1 :align "center"} ~title]
(render-authors ~authors)
(render-abstract ~abstract)
~'&body])
[:set {:element :text :size "10pt"}]
[:heading {:level 1 :align "center"} title]
(render-authors authors)
(render-abstract abstract)])
;; Use the template
(ieee-paper
"Neural Networks for Fun and Profit"
[{:name "Alice" :affil "MIT"}]
"We present..."
"We present a novel approach..."
[:heading {:level 2} "Introduction"]
"..."
"The problem of machine learning..."
[:heading {:level 2} "Methods"]
"...")
"Our method consists of...")
```
```typst
#set page(paper: "us-letter", columns: 2)
#set text(size: 10pt)
#heading(level: 1, align: center)[Neural Networks for Fun and Profit]
#block(align: center)[#strong[Alice] \ #emph[MIT]]
== Abstract
#block(inset: 1em)[#emph[We present a novel approach...]]
== Introduction
The problem of machine learning...
== Methods
Our method consists of...
```
## Full Example
@@ -482,6 +602,66 @@ It's a Lisp - of course we have macros.
(compile-to-typst paper "paper.typ")
```
```typst
#set page(paper: "a4")
#set text(font: "Linux Libertine")
#heading(level: 1)[A Very Important Paper]
#block(align: center)[
#block(inset: 1em)[
#strong[Alice Chen] \
#emph[MIT] \
#link("mailto:alice@mit.edu")[alice@mit.edu]
]
#h(2em)
#block(inset: 1em)[
#strong[Bob Smith] \
#emph[Stanford] \
#link("mailto:bob@stanford.edu")[bob@stanford.edu]
]
]
= Abstract
We present a novel approach to solving important problems.
Our method achieves *state-of-the-art* results on several
benchmarks while maintaining computational efficiency.
= Introduction
The problem of _important things_ has long challenged researchers.
Previous approaches @citation1 @citation2 have made progress but
fundamental limitations remain.
#figure(
image("architecture.png", width: 80%),
caption: [System architecture overview.]
) <fig:arch>
Our method works by first processing the input through
the encoder (see @fig:arch).
= Results
#table(
columns: 2,
align: (left, right),
[#strong[Method]], [#strong[Accuracy]],
[Baseline], [72.0%],
[Ours], [94.0%]
)
As shown in the table above, our method significantly
outperforms the baseline.
= Conclusion
We have demonstrated that our approach is highly effective.
#bibliography("refs.bib")
```
## Rules Summary
1. **`#t"..."`** - raw Typst content, returned as-is