summary refs log tree commit diff stats
path: root/lib/schmaltz.sls
diff options
context:
space:
mode:
Diffstat (limited to 'lib/schmaltz.sls')
-rw-r--r--lib/schmaltz.sls103
1 files changed, 103 insertions, 0 deletions
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))))))