ideate
This commit is contained in:
+391
@@ -0,0 +1,391 @@
|
||||
# Dual Mode: Hiccup + Raw Escapes
|
||||
|
||||
Both systems coexist. Use whichever fits the moment.
|
||||
|
||||
## The Two Modes
|
||||
|
||||
```clojure
|
||||
;; HICCUP - when you need programmatic structure
|
||||
[:heading {:level 1} "Title"]
|
||||
|
||||
;; RAW - when you just want to write
|
||||
#t"= Title"
|
||||
```
|
||||
|
||||
## Mixing Freely
|
||||
|
||||
```clojure
|
||||
[;; Hiccup for structured parts
|
||||
[:heading {:level 1} title]
|
||||
|
||||
;; Raw escape for prose-heavy sections
|
||||
#t"
|
||||
This is just regular Typst content. I can write *bold* and _italic_
|
||||
without all the brackets. Much nicer for prose.
|
||||
|
||||
- Bullet one
|
||||
- Bullet two
|
||||
"
|
||||
|
||||
;; Back to hiccup for programmatic stuff
|
||||
[:table {:columns 2}
|
||||
(for [row data]
|
||||
(list (:name row) (:value row)))]
|
||||
|
||||
;; Raw with interpolation
|
||||
#t"The answer is ~(calculate-answer data)."
|
||||
|
||||
;; Nested: raw inside hiccup (use :block for container)
|
||||
[:block {:inset "1em" :fill "gray.lighten(90%)"}
|
||||
#t"This is a _sidebar_ with easy formatting."]
|
||||
|
||||
;; Nested: hiccup inside raw
|
||||
#t"
|
||||
= Section
|
||||
|
||||
Here's a dynamic table:
|
||||
~(render-table results)
|
||||
|
||||
And back to prose.
|
||||
"]
|
||||
```
|
||||
|
||||
## Escape Syntax Options
|
||||
|
||||
```clojure
|
||||
;; Short string
|
||||
#t"= Heading"
|
||||
|
||||
;; Multi-line block
|
||||
#t"
|
||||
Multiple lines
|
||||
of typst content
|
||||
"
|
||||
|
||||
;; Triple-quote for content with quotes
|
||||
#t"""
|
||||
He said "hello" and *left*.
|
||||
"""
|
||||
|
||||
;; With explicit delimiters (if we need)
|
||||
#typst{
|
||||
Content here with {braces} works fine
|
||||
}
|
||||
|
||||
;; Tagged for syntax highlighting in editors?
|
||||
#typst/content "..."
|
||||
```
|
||||
|
||||
## Interpolation Inside Raw
|
||||
|
||||
Using `~()` - the unquote concept from Clojure's syntax-quote:
|
||||
|
||||
```clojure
|
||||
;; Simple expression
|
||||
#t"The value is ~(expr)."
|
||||
|
||||
;; Hiccup expression returns content
|
||||
#t"Click ~([:link {:dest url} label]) to continue."
|
||||
|
||||
;; Conditional
|
||||
#t"Status: ~(if done? 'Complete' 'Pending')"
|
||||
|
||||
;; Loop
|
||||
#t"
|
||||
= Items
|
||||
~(for [i items]
|
||||
(str '- ' (:name i) '\n'))
|
||||
"
|
||||
|
||||
;; Or loop returning hiccup (items are direct list children)
|
||||
#t"
|
||||
= Items
|
||||
~[:list (for [i items] (:name i))]
|
||||
"
|
||||
```
|
||||
|
||||
Same mental model as macro unquote:
|
||||
```clojure
|
||||
`(let [x ~expr] ...) ; macro: escape to eval
|
||||
#t"Value: ~(expr)" ; template: escape to eval
|
||||
```
|
||||
|
||||
## Full Example
|
||||
|
||||
```clojure
|
||||
(ns my-paper.core
|
||||
(:require [clojure-typst.core :refer :all]))
|
||||
|
||||
(def authors
|
||||
[{:name "Alice Chen" :affiliation "MIT" :email "alice@mit.edu"}
|
||||
{:name "Bob Smith" :affiliation "Stanford" :email "bob@stanford.edu"}])
|
||||
|
||||
(def results
|
||||
[{:method "Baseline" :accuracy 0.72}
|
||||
{:method "Ours" :accuracy 0.94}])
|
||||
|
||||
(defn author-card [{:keys [name affiliation email]}]
|
||||
[:block {:inset "1em"}
|
||||
[:strong name] [:linebreak]
|
||||
[:emph affiliation] [:linebreak]
|
||||
[:link {:dest (str "mailto:" email)} email]])
|
||||
|
||||
(defn results-table [data]
|
||||
[:table {:columns 2 :align ["left" "right"]}
|
||||
[:strong "Method"] [:strong "Accuracy"]
|
||||
(for [{:keys [method accuracy]} data]
|
||||
(list
|
||||
method
|
||||
(format "%.1f%%" (* 100 accuracy))))])
|
||||
|
||||
(def paper
|
||||
[[:heading {:level 1} "A Very Important Paper"]
|
||||
|
||||
;; Programmatic author list
|
||||
[:block {:align "center"}
|
||||
(interpose [:h "2em"]
|
||||
(map author-card authors))]
|
||||
|
||||
;; Prose in raw mode - much nicer to write
|
||||
#t"
|
||||
= 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.
|
||||
|
||||
In this work, we propose a new framework that addresses these
|
||||
limitations directly. Our key contributions are:
|
||||
|
||||
+ A novel architecture for processing data
|
||||
+ Theoretical analysis of convergence properties
|
||||
+ Extensive empirical evaluation
|
||||
|
||||
= Methods
|
||||
"
|
||||
|
||||
;; Back to hiccup for the technical diagram
|
||||
[:figure {:caption "System architecture overview."}
|
||||
[:image {:width "80%"} "architecture.png"]]
|
||||
|
||||
#t"
|
||||
Our method works by first processing the input through
|
||||
the encoder (see @fig:arch). The encoded representation
|
||||
is then passed to the decoder which produces the output.
|
||||
|
||||
= Results
|
||||
"
|
||||
|
||||
;; Programmatic table
|
||||
(results-table results)
|
||||
|
||||
#t"
|
||||
As shown in the table above, our method significantly
|
||||
outperforms the baseline.
|
||||
|
||||
= Conclusion
|
||||
|
||||
We have demonstrated that our approach is ~(if (> (:accuracy (last results)) 0.9)
|
||||
"highly effective"
|
||||
"somewhat effective").
|
||||
Future work will explore extensions to other domains.
|
||||
"
|
||||
|
||||
;; Bibliography could be generated
|
||||
[:bibliography "refs.bib"]])
|
||||
|
||||
;; Compile it
|
||||
(compile-to-typst paper "paper.typ")
|
||||
```
|
||||
|
||||
## Macros
|
||||
|
||||
It's a Lisp - of course we have macros.
|
||||
|
||||
### Standard Code Macros
|
||||
|
||||
```clojure
|
||||
;; Threading for cleaner data transforms
|
||||
(defmacro -> [x & forms]
|
||||
...)
|
||||
|
||||
(-> data
|
||||
(filter :active)
|
||||
(map :name)
|
||||
(sort))
|
||||
|
||||
;; Custom control flow
|
||||
(defmacro when-let [[binding expr] & body]
|
||||
`(let [~binding ~expr]
|
||||
(when ~binding ~@body)))
|
||||
```
|
||||
|
||||
### Content Macros
|
||||
|
||||
Macros that expand to hiccup/content:
|
||||
|
||||
```clojure
|
||||
;; Define a reusable content pattern
|
||||
(defmacro defcomponent [name args & body]
|
||||
`(defn ~name ~args
|
||||
(list ~@body))) ; sequences flatten into parent content
|
||||
|
||||
;; Conditional content sections
|
||||
(defmacro when-content [test & body]
|
||||
`(when ~test
|
||||
(list ~@body)))
|
||||
|
||||
;; Use it
|
||||
(when-content show-abstract?
|
||||
[:heading {:level 2} "Abstract"]
|
||||
abstract-text)
|
||||
```
|
||||
|
||||
### Document Structure Macros
|
||||
|
||||
```clojure
|
||||
;; Academic paper structure
|
||||
(defmacro paper [& {:keys [title authors abstract] :as opts} & sections]
|
||||
`[[:heading {:level 1} ~title]
|
||||
(author-block ~authors)
|
||||
(when ~abstract
|
||||
(list
|
||||
[:heading {:level 2} "Abstract"]
|
||||
~abstract))
|
||||
~@sections])
|
||||
|
||||
;; Usage
|
||||
(paper
|
||||
:title "My Great Paper"
|
||||
:authors ["Alice" "Bob"]
|
||||
:abstract "We did cool stuff."
|
||||
|
||||
[:heading {:level 2} "Introduction"]
|
||||
"..."
|
||||
|
||||
[:heading {:level 2} "Methods"]
|
||||
"...")
|
||||
```
|
||||
|
||||
### DSL Macros
|
||||
|
||||
Build mini-languages for specific domains:
|
||||
|
||||
```clojure
|
||||
;; Math DSL that's easier to write than raw Typst math
|
||||
(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! $
|
||||
|
||||
;; Table DSL
|
||||
(defmacro deftable [name headers & row-specs]
|
||||
...)
|
||||
|
||||
(deftable results-table
|
||||
["Method" "Precision" "Recall" "F1"]
|
||||
:from results
|
||||
:row (fn [{:keys [method p r f1]}]
|
||||
[method (fmt p) (fmt r) (fmt f1)]))
|
||||
|
||||
;; Figure DSL with auto-numbering
|
||||
(defmacro figure [id & {:keys [src caption width]}]
|
||||
`(do
|
||||
(register-figure! ~id)
|
||||
[:figure {:label ~id :caption ["Figure " (figure-num ~id) ": " ~caption]}
|
||||
[:image {:width ~(or width "100%")} ~src]]))
|
||||
|
||||
(figure :arch
|
||||
:src "architecture.png"
|
||||
:caption "System overview"
|
||||
:width "80%")
|
||||
```
|
||||
|
||||
### Syntax Extension Macros
|
||||
|
||||
```clojure
|
||||
;; Custom reader syntax for common patterns
|
||||
;; (would require reader macro support)
|
||||
|
||||
;; Shorthand for references
|
||||
(defmacro ref [id]
|
||||
`[:ref ~(str "@" (name id))])
|
||||
|
||||
;; Shorthand for citations
|
||||
(defmacro cite [& keys]
|
||||
`[:cite ~@(map #(str "@" (name %)) keys)])
|
||||
|
||||
;; Usage
|
||||
(ref :fig:arch) ; => @fig:arch
|
||||
(cite :smith2020 :jones2021) ; => @smith2020 @jones2021
|
||||
```
|
||||
|
||||
### Template Macros
|
||||
|
||||
```clojure
|
||||
;; Define document templates
|
||||
(defmacro deftemplate [name args & structure]
|
||||
`(defmacro ~name ~args
|
||||
~@structure))
|
||||
|
||||
(deftemplate ieee-paper [title authors abstract]
|
||||
[[:set :page {:paper "us-letter" :columns 2}]
|
||||
[:heading {:level 1 :align "center"} ~title]
|
||||
(render-authors ~authors)
|
||||
(render-abstract ~abstract)
|
||||
~'&body]) ; splice remaining content
|
||||
|
||||
;; Use template
|
||||
(ieee-paper
|
||||
"Neural Networks for Fun and Profit"
|
||||
[{:name "Alice" :affil "MIT"}]
|
||||
"We present..."
|
||||
|
||||
[:heading {:level 2} "Introduction"]
|
||||
"..."
|
||||
[:heading {:level 2} "Methods"]
|
||||
"...")
|
||||
```
|
||||
|
||||
### Why Macros Matter Here
|
||||
|
||||
| Pattern | Without Macros | With Macros |
|
||||
|---------|---------------|-------------|
|
||||
| Repeated structure | Copy-paste hiccup | `defcomponent` |
|
||||
| Conditional sections | Verbose `if` expressions | `when-content` |
|
||||
| Domain languages | Manual compilation | DSL macros |
|
||||
| Document templates | Function composition | Template macros |
|
||||
| Boilerplate elimination | Nowhere to hide it | Macro it away |
|
||||
|
||||
**The power:** Your document language grows to fit your domain.
|
||||
|
||||
## Rules
|
||||
|
||||
1. **`#t"..."`** - raw Typst content, returned as-is
|
||||
2. **`~(...)`** inside raw - interpolate Clojure expression (like unquote)
|
||||
3. **`[:tag ...]`** - hiccup, compiled to Typst function calls
|
||||
4. **Strings in hiccup** - become Typst content directly
|
||||
5. **Seqs in hiccup** - flattened (so `map`/`for` just work)
|
||||
6. **Sequences flatten** - `(for ...)`, `(map ...)`, `(list ...)` results merge into parent
|
||||
|
||||
## Why Both?
|
||||
|
||||
| Situation | Use |
|
||||
|-----------|-----|
|
||||
| Prose, paragraphs, natural writing | Raw `#t"..."` |
|
||||
| Tables, figures, structured layout | Hiccup |
|
||||
| Loops, conditionals, data-driven | Hiccup or interpolated raw |
|
||||
| Components, reusable parts | Hiccup functions |
|
||||
| Quick one-off formatting | Either, your preference |
|
||||
|
||||
**The principle:** Structure when you need it, prose when you don't.
|
||||
Reference in New Issue
Block a user