summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorCase Duckworth2023-08-15 23:33:17 -0500
committerCase Duckworth2023-08-15 23:33:17 -0500
commitd4830cdd422258a7c91a5ed07af50f8c208a29ee (patch)
treebacdf4124ef9b9467ea64c6d098a5cd78426912a /lib
parentEtc (diff)
downloadboudin-d4830cdd422258a7c91a5ed07af50f8c208a29ee.tar.gz
boudin-d4830cdd422258a7c91a5ed07af50f8c208a29ee.zip
A new start (again)
Diffstat (limited to 'lib')
-rw-r--r--lib/config.sld45
-rw-r--r--lib/schmaltz.sld17
-rw-r--r--lib/schmaltz.sls103
-rw-r--r--lib/types.sld24
-rw-r--r--lib/types.sls72
-rw-r--r--lib/util.sld50
6 files changed, 311 insertions, 0 deletions
diff --git a/lib/config.sld b/lib/config.sld new file mode 100644 index 0000000..bdd6ef5 --- /dev/null +++ b/lib/config.sld
@@ -0,0 +1,45 @@
1;;; (boudin config) --- default values for configuration options
2;;
3;; To change these, make a `config.scm' in your site's root directory and change
4;; these. They're all parameters so .. change em like that.
5
6(define-library (boudin config)
7 (import (scheme base)
8 (boudin schmaltz)
9 ;; not portable
10 (chicken pathname)
11 (html-parser)
12 )
13
14 (export site-url site-dest
15 page-path-transformers page-text-transformers
16 page-template index-template feed-template)
17
18 (begin
19 ;; Site information
20 (define site-url
21 (make-parameter "example.com"))
22 (define site-dest
23 (make-parameter "out/"))
24 ;; Transformers
25 (define page-path-transformers
26 (make-parameter
27 (list (lambda (path) (make-pathname (site-dest) path)))))
28 (define page-text-transformers
29 (make-parameter
30 (list wrap-paragraphs
31 render-string
32 html->sxml)))
33 ;; Templates --- note that we use quote but include unquote forms here.
34 ;; This is to simplify the configuration and to avoid a cyclical dependency
35 ;; with (boudin types).
36 (define page-template
37 (make-parameter
38 '(html (@ (lang "en-us"))
39 (head (title (or (page-ref pg "title") "[untitled]")))
40 (body ,@(page-sxml pg)))))
41 (define index-template
42 (make-parameter 'todo))
43 (define feed-template
44 (make-parameter 'todo))
45 ))
diff --git a/lib/schmaltz.sld b/lib/schmaltz.sld new file mode 100644 index 0000000..d54d53e --- /dev/null +++ b/lib/schmaltz.sld
@@ -0,0 +1,17 @@
1(define-library (boudin schmaltz)
2 (export render
3 render-string
4 wrap-paragraphs)
5
6 (import (scheme base)
7 (scheme case-lambda) ; case-lambda
8 (scheme eval) ; eval
9 (scheme read) ; read
10 (scheme repl) ; interaction-environment
11 (scheme write) ; display
12 (only (html-parser)
13 sxml->html)
14 (only (srfi 152)
15 string-split string-trim))
16
17 (include "lib/schmaltz.sls"))
diff --git a/lib/schmaltz.sls b/lib/schmaltz.sls new file mode 100644 index 0000000..623191f --- /dev/null +++ b/lib/schmaltz.sls
@@ -0,0 +1,103 @@
1;;; (boudin schmaltz) --- transform almost-html plus scheme into html
2
3;;; Embedded scheme code
4
5(define (->string x)
6 (call-with-port (open-output-string)
7 (lambda (port)
8 (display x port)
9 (get-output-string port))))
10
11(define render-string
12 (case-lambda
13 ((s) (render-string s (interaction-environment)))
14 ((s env)
15 (call-with-port (open-input-string s)
16 (lambda (port)
17 (render port env))))))
18
19(define (render port env)
20 ;; A few rough edges:
21 ;; #, x will try to render x
22 (define (burn-char)
23 ;; Throw a character away. I've defined this for clarity below.
24 (read-char port))
25
26 (let loop ((ch (read-char port))
27 (acc '()))
28 (define (proceed) (loop (read-char port) (cons ch acc)))
29 (cond
30 ((not ch)
31 (loop (read-char port) acc))
32 ((eof-object? ch)
33 (list->string (reverse acc)))
34 ((eq? ch #\#) ; special processing to come
35 (case (peek-char port)
36 ((#\\) ; inhibit processing of the next char
37 (burn-char)
38 (loop (read-char port) (cons ch acc)))
39 ((#\,) ; scheme eval expansion
40 (burn-char)
41 (loop #f
42 (append (let ((s (->string
43 (eval (read port)
44 env))))
45 (cond
46 ((equal? s "#<unspecified>") ; XXX NOT PORTABLE
47 '())
48 ((equal? s "#!eof") ; XXX NOT PORTABLE
49 '(#\, #\#))
50 (else (reverse (string->list s)))))
51 acc)))
52 ((#\@) ; embedded sxml
53 (burn-char)
54 (loop #f
55 (append (let ((h (eval `(sxml->html ,(list 'quasiquote
56 (read port)))
57 env)))
58 (cond
59 ((equal? h "#!eof") ; XXX NOT PORTABLE
60 '(#\@ #\#))
61 (else (reverse (string->list h)))))
62 acc)))
63 (else (proceed))))
64 (else (proceed)))))
65
66;;; Wrap paragraphs
67
68(define (split-paragraphs str)
69 (let loop ((lines (string-split str "\n"))
70 (par '())
71 (acc '()))
72 (cond
73 ((and (null? lines) ; base case: no more lines
74 (null? par)) ; ... or pending paragraph
75 (reverse acc))
76 ((null? lines) ; add the final paragraph
77 (loop '() '() (cons (apply string-append (reverse par)) acc)))
78 ((equal? (car lines) "") ; paragraph break
79 (loop (cdr lines)
80 '()
81 (cons (apply string-append (reverse par)) acc)))
82 (else ; line break
83 (loop (cdr lines)
84 (cons (string-append (car lines) "\n") par)
85 acc)))))
86
87(define (wrap-paragraphs str)
88 (let loop ((pars (split-paragraphs str))
89 (acc '()))
90 (cond
91 ((null? pars)
92 (apply string-append (reverse acc)))
93 ((zero? (string-length (car pars)))
94 (loop (cdr pars)
95 acc))
96 ((eq? #\< (string-ref (string-trim (car pars)) 0))
97 (loop (cdr pars)
98 (cons (car pars)
99 acc)))
100 (else
101 (loop (cdr pars)
102 (cons (string-append "<p>" (car pars) "</p>\n")
103 acc))))))
diff --git a/lib/types.sld b/lib/types.sld new file mode 100644 index 0000000..791ff53 --- /dev/null +++ b/lib/types.sld
@@ -0,0 +1,24 @@
1(define-library (boudin types)
2 (import (scheme base)
3 (scheme case-lambda)
4 (scheme file)
5 (boudin config)
6 (boudin util)
7 ;; non-portable bits
8 (chicken pathname)
9 (html-parser)
10 )
11
12 (export
13 ;; pages
14 make-page page?
15 page-path page-dest page-text page-sxml page-meta
16 set-page-dest! set-page-text! set-page-sxml! set-page-meta!
17 extract-metadata page-ref page-set!
18 page-url page-slug
19 read-page write-page
20 ;; indeces
21 ;; static files
22 )
23
24 (include "lib/types.sls"))
diff --git a/lib/types.sls b/lib/types.sls new file mode 100644 index 0000000..2b4da5d --- /dev/null +++ b/lib/types.sls
@@ -0,0 +1,72 @@
1;;; (boudin types) --- pages, indeces, and static files
2
3;; All paths are relative to the site directory unless otherwise noted
4
5(define-record-type page
6 (make-page path ; Input path
7 dest ; Output path (rel. to output directory)
8 text ; Input text
9 sxml ; Rendered sxml
10 meta ; Metadata (title, etc.)
11 )
12 page?
13 (path page-path)
14 (dest page-dest set-page-dest!)
15 (text page-text set-page-text!)
16 (sxml page-sxml set-page-sxml!)
17 (meta page-meta set-page-meta!))
18
19(define (page-ref pg key)
20 (assoc-ref key (page-meta pg) (identity #f)))
21
22(define (page-set! pg key val)
23 (set-page-meta! pg (cons (cons key val)
24 (page-meta pg))))
25
26(define (extract-metadata sxml)
27 #f)
28
29(define (*urlify path)
30 (normalize-pathname
31 (make-pathname (list (site-url)
32 (pathname-strip-extension path))
33 "index.html")))
34
35(define (page-url pg) ; foo.html => http://site.com/foo/index.html
36 (or (page-ref pg "url") ; memoization
37 (let ((url (*urlify (page-path pg))))
38 (page-set! pg "url" url)
39 url)))
40
41(define (*slugify url) ; I don't love how this is written..
42 (let-values (((_ _ dirs) (decompose-directory url)))
43 (let loop ((this (car dirs))
44 (rest (cdr dirs)))
45 (if (null? (cdr rest))
46 (make-pathname (list "/" this) #f)
47 (loop (car rest)
48 (cdr rest))))))
49
50(define (page-slug pg) ; http://site.com/foo/index.html => /foo/
51 (or (page-ref pg "slug") ; memoization
52 (let ((slug (*slugify (page-url pg))))
53 (page-set! pg "slug" slug)
54 slug)))
55
56(define (read-page path)
57 (let ((pg (make-page path #f #f #f #f)))
58 (set-page-dest! pg ((apply o (page-path-transformers)) path))
59 (set-page-text! pg (with-input-from-file path slurp))
60 (set-page-sxml! pg ((apply o (page-text-transformers)) (page-text pg)))
61 (set-page-meta! pg (extract-metadata (page-sxml pg)))
62 pg))
63
64(define write-page
65 (case-lambda
66 ((pg) (call-with-output-file (page-dest pg)
67 (lambda (port) (write-page pg port))))
68 ((pg port)
69 (sxml-display-as-html ((eval/q (page-template)) pg) port))))
70
71
72
diff --git a/lib/util.sld b/lib/util.sld new file mode 100644 index 0000000..64c633e --- /dev/null +++ b/lib/util.sld
@@ -0,0 +1,50 @@
1;;; (boudin util) --- utility functions
2
3(define-library (boudin util)
4 (import (scheme base)
5 (scheme case-lambda)
6 (scheme eval))
7
8 (export identity
9 o
10 assoc-ref
11 slurp
12 eval/q)
13
14 (begin
15 (define (identity x) x)
16
17 (define (o . procs) ; stole from chicken core
18 (if (null? procs)
19 identity
20 (let loop ((procs procs))
21 (let ((h (car procs))
22 (t (cdr procs)))
23 (if (null? t)
24 h
25 (lambda (x) (h ((loop t) x))))))))
26
27 (define assoc-ref
28 (case-lambda
29 ((key alist)
30 (assoc-ref alist
31 key
32 (lambda () (error "Unrecognized key." key))))
33 ((key alist failure)
34 (cond ((assoc key alist) => cdr)
35 (else (failure))))))
36
37 (define slurp
38 (case-lambda
39 (() (slurp (current-input-port)))
40 ((port)
41 (let loop ((ch (read-char))
42 (acc '()))
43 (if (eof-object? ch)
44 (list->string (reverse acc))
45 (loop (read-char) (cons ch acc)))))))
46
47 (define (eval/q form env) ; this is probably a bad idea
48 (eval (list 'quasiquote form) env))
49
50 ))