-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathexpand-template.scm
More file actions
135 lines (118 loc) · 4.64 KB
/
expand-template.scm
File metadata and controls
135 lines (118 loc) · 4.64 KB
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
(import (srfi srfi-1)
(srfi srfi-26)
(ice-9 receive)
(ice-9 rdelim)
(ice-9 regex)
(rnrs io ports)
(web client)
(json))
;;; Utilities
(define-syntax-rule (values->list body)
(receive lst body lst))
(define (lines str)
(string-split str (char-set #\newline)))
(define (unlines lst)
(string-join lst "\n"))
(define (clamp lower upper x)
(min upper (max lower x)))
(define* (port-map proc
#:optional
(input-port (current-input-port))
(output-port (current-output-port)))
(let ((line (read-line input-port 'concat)))
(unless (eof-object? line)
(display (proc line) output-port)
(port-map proc input-port output-port))))
;;; Markdown file parsing
(define (header? str)
(let ((matches (string-match " {0,3}(#{1,6}) ([^#]+)" str)))
(and matches
(values (match:substring matches 2)
(- (match:end matches 1) (match:start matches 1))))))
(define (shift-header str offset)
(if (header? str)
(let* ((matches (string-match " {0,3}(#{1,6})" str))
(level (string-length (match:substring matches 1))))
(string-replace str
(make-string (clamp 0 6 (+ level offset)) #\#)
(match:start matches 1)
(match:end matches 1)))
str))
(define (get-section text str)
(define (%get-section text lst state min-level)
(if (null? lst)
'()
(let ((header-info (values->list (header? (car lst)))))
(case state
((header-not-found)
(if (and (car header-info)
(>= (cadr header-info) min-level)
(string=? (car header-info) text))
(%get-section text (cdr lst) 'header-found (cadr header-info))
(%get-section text (cdr lst) 'header-not-found min-level)))
((header-found)
(if (and (car header-info) (<= (cadr header-info) min-level))
'()
(cons (car lst)
(%get-section text (cdr lst) 'header-found min-level))))))))
(unlines (%get-section text (lines str) 'header-not-found 0)))
;;; GitHub-related procedures
(define (render-markdown str)
(receive (status body)
(http-post "https://api.github.com/markdown"
#:headers '((user-agent . "Celluloid Website Updater"))
#:body (call-with-output-string
(cute scm->json `(("text" . ,str)) <>)))
body))
(define (fetch url)
(receive (status body)
(http-get url)
body))
(define (get-readme)
(fetch "https://raw.githubusercontent.com/celluloid-player/celluloid/master/README.md"))
(define (get-contributing)
(fetch "https://raw.githubusercontent.com/celluloid-player/celluloid/master/.github/CONTRIBUTING.md"))
(define (get-faq)
(fetch "https://raw.githubusercontent.com/wiki/celluloid-player/celluloid/FAQ.md"))
;;; Template expansion
(define* (expand-template str #:optional (start 0) (min-level 2))
(define (ensure-min-level str)
(let* ((str-lines
(lines str))
(first-header
(find (cute header? <>) str-lines))
(first-header-level
(and first-header (cadr (values->list (header? first-header))))))
(if first-header-level
(unlines (map (cute shift-header <> (- min-level first-header-level))
str-lines))
str)))
(let ((matches (string-match "\\{([^ }]+)(\\s+[^}]+)?\\}" str start)))
(if matches
(let* ((process-section
(compose render-markdown ensure-min-level))
(page-text
(match:substring matches 1))
(header-text
(let ((text (match:substring matches 2)))
(and text (string-trim text))))
(src
(cond
((string-ci=? page-text "readme") (get-readme))
((string-ci=? page-text "contributing") (get-contributing))
((string-ci=? page-text "faq") (get-faq))
(else (error "ERROR: Unknown page '~A'" page-text))))
(section
(process-section
(if header-text (get-section header-text src) src)))
(new-str
(string-replace
str
section
(match:start matches 0)
(match:end matches 0)))
(new-start
(+ (match:start matches 0) (string-length section))))
(expand-template new-str new-start min-level))
str)))
(port-map expand-template)