about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorCase Duckworth2023-03-29 21:21:14 -0500
committerCase Duckworth2023-03-29 21:21:14 -0500
commit6d7bbec15031d689022c8e5155b81c15784f7deb (patch)
tree530d40aaf0ad41cce80213895905211482a9fa62
downloadwikme-6d7bbec15031d689022c8e5155b81c15784f7deb.tar.gz
wikme-6d7bbec15031d689022c8e5155b81c15784f7deb.zip
Initial commit (oops)
-rw-r--r--src/wikme.scm177
1 files changed, 177 insertions, 0 deletions
diff --git a/src/wikme.scm b/src/wikme.scm new file mode 100644 index 0000000..187864e --- /dev/null +++ b/src/wikme.scm
@@ -0,0 +1,177 @@
1;;; wikme --- build a static wiki out of a folder of markdown files
2
3(import (cmark)
4 (srfi-152)
5 (utf8)
6 (chicken irregex)
7 (chicken port)
8 (chicken string))
9
10
11;;; Configuration
12
13(define site-config
14 (make-parameter `((base-url . "https://www.example.com")
15 ;; These default directories aren't .. great.
16 (source-dir . "src")
17 (output-dir . "out")
18 (transformers . ,(list commonmark->html
19 wikify-links))
20 (filename-transform
21 . (lambda (fname)
22 (md->index-html fname)))
23 (page-environment
24 . ((title
25 . ,(lambda (page)
26 (cdr (assq 'title (page-meta page)))))
27 (body
28 . ,(lambda (page)
29 (page-body page)))
30 (last_updated
31 . ,(lambda (page)
32 (cdr (assq 'last-updated (page-meta page))))))))))
33
34(define (config-get x)
35 (if (assq x (site-config))
36 (cdr (assq x (site-config)))
37 #f))
38
39
40;;; Templates
41
42(define (render template env)
43 ;;; Render TEMPLATE using ENV.
44 ;; TEMPLATE is a string with {{placeholders}}; ENV is an alist of key-value
45 ;; pairs to insert into the TEMPLATE's placeholders.
46 (string-substitute* template (env->replacements env)))
47
48(define (env->replacements env)
49 ;;; Convert an ENV alist of the form `((X . Y) ...) to '(("{{X}}" . "Y") ...).
50 ;; X's are template variables and Y's are the values of those variables. In
51 ;; the template, both "{{X}}" and "{{ X }}" will be replaced.
52 ;; If Y is a thunk, call it.
53 (let loop ((env env)
54 (res '()))
55 (if (null? env)
56 res
57 (let* ((this (car env))
58 (rest (cdr env))
59 (key (->string (car this)))
60 (val (if (procedure? (cdr this))
61 ((cdr this))
62 (->string (cdr this)))))
63 (loop (cdr env)
64 (append (list (cons (string-append "{{" key "}}") val)
65 (cons (string-append "{{ " key " }}") val))
66 env))))))
67
68
69;;; Wiki links
70
71(define wiki-link-sre
72 ;;; An SRE for [[wiki-style links|with optional titles]].
73 '(: "[["
74 (submatch-named page (+ (~ "|")))
75 (? (submatch "|" (submatch-named title (*? nonl))))
76 "]]"))
77
78(define (wikify-links text)
79 ;;; Convert [[Wiki-style links]] to HTML style in TEXT.
80 (irregex-replace/all wiki-link-sre text
81 (lambda (m)
82 (let* ((page (irregex-match-substring m 'page))
83 (title (or (irregex-match-substring m 'title)
84 page)))
85 (string-append
86 "<a href=\"" (linkify page) "\">" title "</a>")))))
87
88(define (linkify pagename)
89 ;;; Turn a page name into a link suitable for an <a> tag.
90 (string-append (base-url) "/" (slugify pagename) "/index.html"))
91
92(define (string-capitalize str)
93 ;;; Capitalize the first word in STR, and ensure the rest of it is lowercase.
94 ;; Stolen and adapted from MIT/GNU Scheme
95 (let* ((end (string-length str))
96 (str* (make-string end)))
97 (do ((i 0 (+ i 1)))
98 ((= i end))
99 (string-set! str* i ((if (= i 0) char-upcase char-downcase)
100 (string-ref str i))))
101 str*))
102
103(define (slugify str)
104 ;;; Convert STR to a 'slug', that is, another string suitable for linking.
105 ;; This function will return the input string, in sentence case, and with all
106 ;; punctuation and spaces converted to a hypen.
107 (string-capitalize
108 (string-trim-both (irregex-replace/all '(+ (~ alnum)) str "-")
109 (lambda (c)
110 (char=? c #\-)))))
111
112(define (unslugify slug)
113 ;;; Convert a SLUG back into a normal string as best as possible.
114 ;; Because information is lost in slugification, it's impossible to be sure
115 ;; that the result of this procedure is totally accurate. That is,
116 ;; slugification is not round-trippable.
117 (irregex-replace/all '("-") slug " "))
118
119
120;;; Transform source
121
122(define (transform source . transformers)
123 ;;; Transform SOURCE to html by passing it through a series of TRANSFORMERS.
124 ;; Each TRANSFORMER should be a one-argument procedure taking and returning a
125 ;; string.
126 (let loop ((transformers transformers)
127 (output source))
128 (if (null? transformers)
129 output
130 (loop (cdr transformers)
131 ((car transformers) output)))))
132
133(define (md->index-html filename)
134 ;;; Transform a FILENAME of the form dir/name.md to dir/name/index.html.
135 ;; Uses source
136 )
137
138
139;;; Pages
140
141(define-record-type <page>
142 ;;; A wiki page is a mapping between source and body content, and between the
143 ;;; page's origin and its destination files, wrapped together with some
144 ;;; metadata.
145 (make-page source body origin destination meta)
146 page?
147 (source page-source ; source markup
148 (setter page-source))
149 (body page-body ; rendered page body
150 (setter page-source))
151 (origin page-origin ; file containing the markup
152 (setter page-origin))
153 (destination page-destination ; destination file
154 (setter page-destination))
155 (meta page-meta ; alist of metadata tags
156 (setter page-meta)))
157
158(define (page-meta-ref key page)
159 ;;; Get metadata KEY from PAGE.
160 (cdr (assq key (page-meta page))))
161
162(define (file->page file
163 #!key
164 (transformers (config-get 'transformers))
165 (destination ))
166 ;;; Create a <page> from FILE.
167 ;; Wraps make-page for easier use.
168
169 )
170
171
172;;; Writing files
173
174(define (publish file config)
175 ;;; Publish FILE, using CONFIG.
176 ;; CONFIG should be a configuration alist, which see above.
177 #f)