diff options
Diffstat (limited to 'wikme-0.scm')
-rw-r--r-- | wikme-0.scm | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/wikme-0.scm b/wikme-0.scm new file mode 100644 index 0000000..ea99125 --- /dev/null +++ b/wikme-0.scm | |||
@@ -0,0 +1,105 @@ | |||
1 | ;;; Wikme --- build a static wiki from a folder full of markdown | ||
2 | ;; -*- geiser-scheme-implementation: chicken -*- | ||
3 | |||
4 | ;; Copyright (C) C. Duckworth <acdw@acdw.net> under the GPL-MD license. | ||
5 | ;; See COPYING for details. | ||
6 | ;; Written with help from (and thanks to!) S. Dunlap | ||
7 | |||
8 | (import | ||
9 | (chicken irregex) ; Regex engine | ||
10 | (chicken file posix) ; File access | ||
11 | (chicken port) ; Input/Output ports | ||
12 | (chicken process) ; Processes and pipes | ||
13 | (ersatz) ; Jinja-compatible templating | ||
14 | (filepath) ; File paths | ||
15 | (lowdown) ; Markdown parser | ||
16 | (srfi-19) ; Time library | ||
17 | (srfi-19-io) ; Time input/output | ||
18 | (srfi-152) ; String library | ||
19 | (utf8)) ; UTF8 support | ||
20 | |||
21 | |||
22 | ;;; Strings | ||
23 | |||
24 | (define (string-capitalize str) | ||
25 | "Capitalize the first word in STR, and ensure the rest of it is lowercase." | ||
26 | ;; Stolen and adapted from MIT/GNU Scheme | ||
27 | (let* ((end (string-length str)) | ||
28 | (str* (make-string end))) | ||
29 | (do ((i 0 (+ i 1))) | ||
30 | ((= i end)) | ||
31 | (string-set! str* i ((if (= i 0) char-upcase char-downcase) | ||
32 | (string-ref str i)))) | ||
33 | str*)) | ||
34 | |||
35 | (define (slugify str) | ||
36 | "Convert STR to a 'slug', that is, another string suitable for linking. | ||
37 | This function will return the input string, in sentence case, and with all | ||
38 | punctuation and spaces converted to a hypen." | ||
39 | (string-capitalize | ||
40 | (string-trim-both (irregex-replace/all '(+ (~ alnum)) str "-") | ||
41 | (lambda (c) | ||
42 | (char=? c #\-))))) | ||
43 | |||
44 | (define (unslugify slug) | ||
45 | "Convert a SLUG back into a normal string as best as possible. | ||
46 | Because information is lost in slugification, it's impossible to be sure that | ||
47 | the result of this procedure is totally accurate. That is, slugification is not | ||
48 | round-trippable." | ||
49 | (irregex-replace/all '("-") slug " ")) | ||
50 | |||
51 | |||
52 | ;;; Pages | ||
53 | |||
54 | (define-record-type <page> | ||
55 | (make-page title content source last-edited) | ||
56 | page? | ||
57 | (title page-title page-title-set!) | ||
58 | (content page-content page-content-set!) | ||
59 | (source page-source page-source-set!) | ||
60 | (last-edited page-last-edited page-last-edited-set!)) | ||
61 | |||
62 | (define (read-page file) | ||
63 | "Read a <page> record from FILE." | ||
64 | (let* ((src (with-input-from-file file read-string)) | ||
65 | (sxml (call-with-input-string src markdown->sxml))) | ||
66 | (title (or (extract-title sxml) | ||
67 | (unslugify (filepath:take-base-name file))))) | ||
68 | (make-page title | ||
69 | sxml | ||
70 | src | ||
71 | (get-last-mtime file))) | ||
72 | |||
73 | (define (get-last-mtime file) | ||
74 | "Figure out FILE's mtime. | ||
75 | First, try running a git log command. If that doesn't work, use the file | ||
76 | system." | ||
77 | (seconds->time | ||
78 | (or (string->number | ||
79 | (string-trim-both | ||
80 | (with-input-from-pipe | ||
81 | (string-append "git -C " _ "log -1 --format=%ct --date=unix " file) | ||
82 | read-string))) | ||
83 | (file-modification-time file)))) | ||
84 | |||
85 | |||
86 | ;;; Templates | ||
87 | |||
88 | (define (render-template template page | ||
89 | #!key | ||
90 | (last-updated-format "~4") | ||
91 | (escape-html #f) | ||
92 | ) | ||
93 | "Render PAGE using TEMPLATE. | ||
94 | TEMPLATE is a jinja2-compatible template file and PAGE is a <page> record type. | ||
95 | TEMPLATE will be passed the following variables: | ||
96 | - title: the page title | ||
97 | - body: the page body as HTML, escaped depending on ESCAPE-HTML (default #f). | ||
98 | - last_updated: the time the page was updated in LAST-UPDATED-FORMAT | ||
99 | (default ISO-8601 year-month-day-hour-minute-second-timezone)" | ||
100 | (from-file template | ||
101 | #:env (template-std-env #:autoescape escape-html) | ||
102 | #:models `((title . ,(Tstr (page-title page))) | ||
103 | (body . ,(Tstr (page-content page))) | ||
104 | (last_updated . ,(Tstr (format-date #f last-updated-format | ||
105 | (page-last-edited page))))))) | ||