-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathutils.rkt
341 lines (311 loc) · 13.5 KB
/
utils.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
#lang at-exp racket
(require scribble/eval scribble/core scribble/sigplan)
(require scribble/manual
scribble/decode
scribble/bnf
scribble/racket
scribble/latex-properties
scheme/string
racket/runtime-path
"unmap.rkt"
(for-syntax syntax/id-table syntax/parse)
(only-in scribble/struct make-flow make-omitable-paragraph flow-paragraphs
make-blockquote make-styled-paragraph)
(for-label racket))
(provide m mp um renewcommand
graybox ; really specific
bracket curlies parens
tenv
align* envalign*
array style-matrix matrix
;; amsthm
mdef mthm mlem mprop mnotation mcor
parthm parunthm parlem parprop parprf
tprf
ntthm ntlem ntprf
;; mathpartir
mathpar
;; listings
lstlisting
lstset
;; pfsteps
byCases bc-case bc-otherwise pfsteps*)
(struct bracket (element))
(struct curlies (element))
(struct parens (element))
(provide/contract
[exact (->* () (#:operators operators/c) #:rest (listof content?) content?)]
[env (->* (content?) (#:opt (listof (or/c bracket? curlies? parens?)))
#:rest (listof content?) content?)])
(define-runtime-path id-path "identity.tex")
(define-runtime-path amsthm-path "amsthm.tex")
(define-runtime-path pfsteps-path "pfsteps.tex")
(define-runtime-path listings-path "listings.tex")
(define-runtime-path mathpar-path "mathpar.tex")
(define-runtime-path bgcolor-path "bgcolor.tex")
(define exact-style
(make-style "Iidentity" `(exact-chars ,(make-tex-addition id-path)
)))
(define current-style (make-parameter exact-style))
(define amsthm-style
(make-style "Iidentity" `(exact-chars ,(make-tex-addition amsthm-path)
)))
(define listings-addition (make-tex-addition listings-path))
(define pfsteps-style
(make-style "Iidentity" `(exact-chars ,(make-tex-addition pfsteps-path)
)))
(define (exact #:operators [operators default-ops] . items)
(make-element (current-style)
(map (λ (i)
(content->latex-content i #:operators operators))
items)))
(define-syntax-rule (m items ...)
(cond [(math-mode) (exact items ...)]
[else (in-math (exact "$" items ... "$"))]))
(define-syntax-rule (mp items ...)
(cond [(math-mode) (exact items ...)]
[else (in-math (exact "\\[" items ... "\\]"))]))
(define-syntax-rule (um items ...)
(cond [(math-mode) (unmath (exact "\\mbox{" items ... "}"))]
[else (exact items ...)]))
(define (renewcommand item0 item1)
(make-multiarg-element (make-style "renewcommand" '(exact-chars)) (list item0 item1)))
(define (tagit tag . items)
(cond [tag (cons (exact `("\\label{" ,tag "}")) items)]
[else items]))
(define bg-color-style
(make-style "BgColor" (list (make-tex-addition bgcolor-path))))
(define (graybox elm) (make-element bg-color-style elm))
(define (interpret-option option)
(match option
[(bracket e) `("[" ,e "]")]
[(curlies e) `("{" ,e "}")]
[(parens e) `("(" ,e ")")]))
(define (env t #:opt [optional '()] . items)
(apply exact `("\\begin{" ,t "}"
,@(append-map interpret-option optional)
,@items
"\\end{" ,t "}")))
(define (tenv t title items)
(keyword-apply env '() '() t items #:opt (list (bracket title))))
(define-syntax-rule (mathpar items ...)
(list (make-element (make-style "setbox\\mymathpar=\\vbox"
`(exact-chars ,(make-tex-addition mathpar-path)
))
(list "\n"
"\\begin{mathpar}"
(parameterize ([math-mode #t])
(map content->latex-content (list items ...)))
"\n\\end{mathpar}\n"))
(make-element (make-style "box\\mymathpar" '(exact-chars)) "")))
(define (lstlisting #:math-escape? [math-escape? #f] . items)
(list (make-element (make-style "setbox\\mylistings=\\vbox"
`(exact-chars ,listings-addition))
(list "\n"
"\\begin{lstlisting}"
(cond [math-escape? "[mathescape]\n"]
[else "\n"])
(parameterize ([math-mode #t])
(map content->latex-content items))
"\n\\end{lstlisting}\n"))
#;(make-element (make-style "copy\\mylistings" '(exact-chars)) "")
(make-element (make-style "box\\mylistings" '(exact-chars)) "")))
(define (lstset #:basicstyle [basicstyle #f]
#:keywordstyle [keywordstyle #f]
#:identifierstyle [identifierstyle #f]
#:commentstyle [commentstyle #f]
#:stringstyle [stringstyle #f]
#:showstringspaces [showstringspaces #f]
#:numbers [numbers #f]
#:numberstyle [numberstyle #f]
#:numberblanklines [numberblanklines #f]
#:stepnumber [stepnumber #f]
#:numbersep [numbersep #f]
#:backgroundcolor [backgroundcolor #f]
#:showspaces [showspaces #f]
#:showtabs [showtabs #f]
#:frame [frame #f]
#:label [label #f]
#:rulecolor [rulecolor #f]
#:tabsize [tabsize #f]
#:language [language #f]
#:caption [caption #f]
#:captionpos [captionpos #f]
#:breaklines [breaklines #f]
#:breakatwhitespace [breakatwhitespace #f]
#:title [title #f]
#:escapeinside [escapeinside #f]
#:morekeywords [morekeywords #f]
#:moredelim [moredelim #f]
#:xleftmargin [xleftmargin #f]
#:xrightmargin [xrightmargin #f])
(define key-values
`(;; styling
("basicstyle" . ,basicstyle)
("keywordstyle" . ,keywordstyle)
("identifierstyle" . ,identifierstyle)
("commentstyle" . ,commentstyle)
("stringstyle" . ,stringstyle)
;; line numbering
("numbers" . ,numbers)
("numberstyle" . ,numberstyle)
("numberblanklines" . ,numberblanklines)
("stepnumber" . ,stepnumber)
("numbersep" . ,numbersep)
;; display
("backgroundcolor" . ,backgroundcolor)
("rulecolor" . ,rulecolor)
("frame" . ,frame)
;; spacing
("showstringspaces" . ,showstringspaces)
("showspaces" . ,showspaces)
("showtabs" . ,showtabs)
("tabsize" . ,tabsize)
;; margins
("xleftmargin" . ,xleftmargin)
("xrightmargin" . ,xrightmargin)
;; line breaking
("breaklines" . ,breaklines)
("breakatwhitespace" . ,breakatwhitespace)
;; legend
("title" . ,title)
("caption" . ,caption)
("captionpos" . ,captionpos)
("label" . ,label)
;; special
("language" . ,language)
;; extra
("escapeinside" . ,escapeinside)
("morekeywords" . ,morekeywords)
("moredelim" . ,moredelim)))
(make-element (make-style "lstset" `(exact-chars ,listings-addition))
(string-join
(foldr (λ (pair acc)
(match-define (cons key val) pair)
(cond [val
(cons (format "~a=~a" key val)
acc)]
[else acc]))
'() key-values)
",\n")))
(define (array style . items)
(keyword-apply env '() '() "array" items #:opt (list (curlies style))))
(define-syntax-rule (in-style style body1 body ...)
(parameterize ([current-style style]) body1 body ...))
;; For working with Jesse's pfsteps library
(define-syntax-rule (byCases items ...)
(in-style pfsteps-style (env "byCases" items ...)))
(define-syntax-rule (pfsteps* items ...)
(in-style pfsteps-style (env "pfsteps*" items ...)))
(define-syntax-rule (bc-case title items ...)
(in-style pfsteps-style (exact "\\case{" (in-math (um title)) "}" items ...)))
(define-syntax-rule (bc-otherwise items ...)
(in-style pfsteps-style (exact `("\\otherwise{}" items ...))))
(define (parblock env title tag items)
(define par
(make-paragraph (current-style)
(exact `("\\begin{" ,env "}"
,@(if title
`("[" ,title "]")
'())))))
(define blocks
(map content->block (collapse-content (apply tagit tag items))))
(define end
(make-paragraph (current-style) (exact `("\\end{" ,env "}"))))
(make-compound-paragraph (current-style)
(append (list par) blocks (list end))))
(define (mdef title #:tag [tag #f] . items)
(in-style amsthm-style (tenv "definition" title (apply tagit tag items))))
(define (mthm title #:tag [tag #f] . items)
(in-style amsthm-style (tenv "theorem" title (apply tagit tag items))))
(define (mlem title #:tag [tag #f] . items)
(in-style amsthm-style (tenv "lemma" title (apply tagit tag items))))
(define (mprop title #:tag [tag #f] . items)
(in-style amsthm-style (tenv "property" title (apply tagit tag items))))
(define (mcor title #:tag [tag #f]. items)
(in-style amsthm-style (tenv "corollary" title (apply tagit tag items))))
(define (mnotation title #:tag [tag #f] . items)
(in-style amsthm-style (tenv "notation" title (apply tagit tag items))))
(define (unthm title #:tag [tag #f] . items)
(in-style amsthm-style (tenv "untheorem" title (apply tagit tag items))))
(define (tprf title . items)
(in-style amsthm-style (tenv "proof" title items)))
(define (parthm title #:tag [tag #f] . items)
(in-style amsthm-style (parblock "theorem" title tag items)))
(define (parlem title #:tag [tag #f] . items)
(in-style amsthm-style (parblock "lemma" title tag items)))
(define (parunthm title #:tag [tag #f] . items)
(in-style amsthm-style (parblock "untheorem" title tag items)))
(define (parprf #:tag [tag #f] . items)
(in-style amsthm-style (parblock "proof" #f tag items)))
(define (parprop title #:tag [tag #f] . items)
(in-style amsthm-style (parblock "property" title tag items)))
(define (ntthm . items) (in-style amsthm-style (apply env "theorem" items)))
(define (ntlem . items) (in-style amsthm-style (apply env "lemma" items)))
(define (ntprf . items) (in-style amsthm-style (apply env "proof" items)))
;; align* is a special LaTeX environment that puts its body directly in a math mode context.
(define-syntax-rule (envalign* items ...)
(in-math (env "align*" items ...)))
(define (content->block c)
(if (content? c)
(make-paragraph (current-style) c)
c))
(define (collapse-content items)
(let recur ([items items]
[current '()]
[all '()])
(define (extend)
(if (empty? current)
all
(cons (reverse current) all)))
(cond [(empty? items) (reverse (extend))]
[(content? (car items))
(recur (cdr items) (cons (car items) current) all)]
[else (recur (cdr items) '() (cons (car items) (extend)))])))
(define-syntax (sep-rows stx)
(syntax-case stx ()
[(_ (args ...) ...)
(let ([rows (reverse
(let recur ([rows (map syntax->list (syntax->list #'((args ...) ...)))]
[acc '()])
(define (dorow row last? acc)
(cond [(null? row) acc]
[(null? (cdr row))
(cond [last? (cons (car row) acc)]
[else (list* "\\\\" (car row) acc)])]
[else (dorow (cdr row) last? (list* "&" (car row) acc))]))
(cond [(null? rows) acc]
[else (recur (cdr rows)
(append (dorow (car rows) (null? (cdr rows)) '())
acc))])))])
(quasisyntax/loc stx (#,@rows)))]))
(define-syntax (align* stx)
(syntax-case stx ()
[(_ (args ...) ...)
(let ([rows (local-expand #'(sep-rows (args ...) ...) 'expression #f)])
#`(envalign* #,@rows))]))
(define-syntax (style-matrix stx)
(define lut (make-free-id-table (hasheq #'l #\l #'r #\r #'c #\c #'bar #\|)))
(define-syntax-class style
#:attributes (kind)
(pattern x:id #:attr kind (free-id-table-ref lut #'x #f) #:when (attribute kind)))
(syntax-parse stx
[(_ (s:style ...) (args ...) ...)
(let* ([argss (map syntax->list (syntax->list #'((args ...) ...)))]
[n (length argss)]
[_ (when (zero? n) (raise-syntax-error #f "matrix needs at least one row." stx))]
[m (length (car argss))]
[ss (attribute s.kind)])
(unless (for/and ([arg (in-list (cdr argss))])
(= m (length arg)))
(raise-syntax-error #f "matrix needs same number of columns in each row." stx))
(let ([rows (local-expand #'(sep-rows (args ...) ...) 'expression #f)])
(quasisyntax/loc stx (array #,(list->string ss) #,@rows))))]))
(define-syntax (matrix stx)
(syntax-case stx ()
[(_ (args ...) ...)
(let* ([argss (map syntax->list (syntax->list #'((args ...) ...)))]
[_ (when (null? argss) (raise-syntax-error #f "matrix needs at least one row." stx))]
[m (length (car argss))]
[style (datum->syntax stx (build-list m (λ _ #'l)))])
(quasisyntax/loc stx (style-matrix #,style (args ...) ...)))]))