File: make-html.scm

package info (click to toggle)
guile-lib 0.2.7-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,904 kB
  • sloc: lisp: 7,014; sh: 3,986; makefile: 191
file content (237 lines) | stat: -rwxr-xr-x 8,700 bytes parent folder | download | duplicates (6)
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#!/bin/sh
# -*- scheme -*-
exec guile --debug -s $0 "$@"
!#

;; make-html.scm -- document a set of scheme modules as HTML
;; Copyright (C) 2006,2007,2009  Andy Wingo <wingo at pobox dot com>

;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

(use-modules (texinfo)
             (texinfo reflection)
             (texinfo html)
             (sxml simple)
             (sxml transform)
             ((srfi srfi-13) :select (string-join)))

(define (makedirs path)
  (let loop ((path ".") (components (string-split path #\/)))
    (if (not (null? components))
        (let ((sub-path (string-append path "/" (car components))))
          (if (or (not (file-exists? sub-path))
                  (not (file-is-directory? sub-path)))
              (mkdir sub-path))
          (loop sub-path (cdr components))))))

(define (wrap-html title root-path scm-url body)
  `(html (@ (xmlns "http://www.w3.org/1999/xhtml"))
    (head
     (title ,title)
     (meta (@ (name "Generator")
              (content "The Guile SXML Toolkit")))
     (style (@ (type "text/css") (media "screen"))
       "@import url("
       ,(string-append root-path "base.css")
       ");"))
    (body
     (div (@ (id "body"))
          (h1 (@ (id "heading"))
              (a (@ (href ,root-path)) ,*name*))
          (div (@ (id "text"))
               (h2 (@ (class "centered")) ,title)
               ,@body)
          (div (@ (id "footer"))
               "powered by sxml")))))

(define xhtml-doctype
  (string-append
   "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
   "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n"))

(define (module->str scm)
  (call-with-output-string (lambda (p) (display scm p))))
(define (module->ustr scm)
  (string-append (string-join (map symbol->string scm) ".") "/"))
(define (extra-entry->ustr str)
  (string-append (string-join (string-split str #\space) ".") "/"))
(define (script->ustr str)
  (string-append str "/"))

(define (make-html-index)
  (with-output-to-file "html/index.html"
    (lambda ()
      (display xhtml-doctype)
      (sxml->xml
       (pre-post-order
        (stexi->shtml
         `(texinfo
           (% (title "unused"))
           ,@(cdr
              (package-stexi-standard-copying
               *name* *version* *updated* *years* *copyright-holder*
               *permissions*))
           (table
            (% (formatter (bold)))
            ,@(map
               (lambda (module description)
                 `(entry
                   (% (heading
                       (uref (% (url ,(module->ustr module))
                                (title ,(module->str module))))))
                   ,@description))
               (map car *modules*) (map cdr *modules*))
            ,@(map
               (lambda (script description)
                 `(entry
                   (% (heading
                       (uref (% (url ,(script->ustr script))
                                (title ,script)))))
                   ,@description))
               (map basename (map car *scripts*)) (map cdr *scripts*))
            ,@(map
               (lambda (args)
                 (apply
                  (lambda (filename label . description)
                    `(entry
                      (% (heading
                          (uref (% (url ,(extra-entry->ustr label))
                                   (title ,label)))))
                      ,@description))
                  args))
               *extra-html-entry-files*))))
        `((html . ,(lambda (tag attrs head body)
                     (wrap-html
                      *name*
                      *html-relative-root-path*
                      "index.scm"
                      (cdr body)))) ;; cdr past the 'body tag
          (*text* . ,(lambda (tag text) text))
          (*default* . ,(lambda args args))))))))

(define (append-map proc l)
  (let lp ((in l))
    (if (null? in)
        '()
        (append (proc (car in)) (lp (cdr in))))))
(define (string-split* s . chars)
  (let lp ((chars (cdr chars)) (out (string-split s (car chars))))
    (if (null? chars)
        out
        (append-map
         (lambda (x)
           (lp (cdr chars) (string-split x (car chars))))
         out))))
(define (negate pred)
  (lambda (x) (not (pred x))))

(define (resolve-ref node manual)
  (and (or (not manual) (string=? manual *name*))
       (let* ((split (filter (negate string-null?)
                             (string-split* node #\space #\newline)))
              (symbols (map string->symbol split))
              (last (car (last-pair symbols)))
              (except-last (reverse (cdr (reverse symbols)))))
         (cond
          ((member symbols (map car *modules*))
           (string-append "../" (module->ustr symbols)))
          ((member except-last (map car *modules*))
           (string-append "../" (module->ustr except-last)
                          "#" (string-join split "-")))
          ((member node (map car *scripts*))
           (string-append "../" (script->ustr node)))
          ((member node (map cadr *extra-html-entry-files*))
           (string-append "../" (extra-entry->ustr node)))
          (else
           (warn "dangling reference" split)
           #f)))))
(add-ref-resolver! resolve-ref)
      
(define (make-html-module-pages)
  (for-each
   (lambda (module)
     (let* ((ustr (string-append "./html/" (module->ustr module)))
            (port (begin
                    (makedirs ustr)
                    (open-output-file (string-append ustr "index.html")))))
       (display xhtml-doctype port)
       (sxml->xml
        (pre-post-order
         (stexi->shtml (module-stexi-documentation module))
         `((html . ,(lambda (tag attrs head body)
                      (wrap-html
                       (module->str module)
                       (string-append "../" *html-relative-root-path*)
                       "../index.scm"
                       (cdr body)))) ;; cdr past the 'body tag
           (*text* . ,(lambda (tag text) text))
           (*default* . ,(lambda args args))))
        port)))
   (map car *modules*)))

(define (make-html-script-pages)
  (for-each
   (lambda (scriptpath)
     (let* ((script (basename scriptpath))
            (ustr (string-append "./html/" (script->ustr script)))
            (port (begin
                    (makedirs ustr)
                    (open-output-file (string-append ustr "index.html")))))
       (display xhtml-doctype port)
       (sxml->xml
        (pre-post-order
         (stexi->shtml (script-stexi-documentation scriptpath))
         `((html . ,(lambda (tag attrs head body)
                      (wrap-html
                       script
                       (string-append "../" *html-relative-root-path*)
                       "../index.scm"
                       (cdr body)))) ;; cdr past the 'body tag
           (*text* . ,(lambda (tag text) text))
           (*default* . ,(lambda args args))))
        port)))
   (map car *scripts*)))

(define (make-html-extra-pages)
  (for-each
   (lambda (filename label)
     (let* ((ustr (string-append "./html/" (extra-entry->ustr label)))
            (port (begin
                    (makedirs ustr)
                    (open-output-file (string-append ustr "index.html")))))
       (display xhtml-doctype port)
       (sxml->xml
        (pre-post-order
         (stexi->shtml (call-with-input-file filename texi-fragment->stexi))
         `((html . ,(lambda (tag attrs head body)
                      (wrap-html
                       label
                       (string-append "../" *html-relative-root-path*)
                       "../index.scm"
                       (cdr body)))) ;; cdr past the 'body tag
           (*text* . ,(lambda (tag text) text))
           (*default* . ,(lambda args args))))
        port)))
   (map car *extra-html-entry-files*)
   (map cadr *extra-html-entry-files*)))

(define (main config-scm)
  (load config-scm)
  (makedirs "./html")
  (make-html-index)
  (make-html-module-pages)
  (make-html-script-pages)
  (make-html-extra-pages))

(apply main (cdr (command-line)))