diff --git a/collects/scribble/base-render.ss b/collects/scribble/base-render.ss new file mode 100644 index 00000000..38deb5fb --- /dev/null +++ b/collects/scribble/base-render.ss @@ -0,0 +1,265 @@ + +(module base-render mzscheme + (require "struct.ss" + (lib "class.ss") + (lib "serialize.ss") + (lib "file.ss")) + + (provide render%) + + (define render% + (class object% + + (init-field dest-dir) + + (define/public (get-dest-directory) + dest-dir) + + (define/public (get-substitutions) null) + + (define/public (get-suffix) #".txt") + + (define/public (format-number number sep) + (if (or (null? number) + (andmap not number)) + null + (cons + (apply + string-append + (map (lambda (n) + (if n + (format "~s." n) + "")) + (reverse number))) + sep))) + + ;; ---------------------------------------- + ;; global-info collection + + (define/public (save-info fn info) + (let ([s (serialize info)]) + (with-output-to-file fn + (lambda () + (write s)) + 'truncate/replace))) + + (define/public (load-info fn info) + (let ([ht (deserialize (with-input-from-file fn read))]) + (hash-table-for-each ht (lambda (k v) + (hash-table-put! info k v)))) + info) + + (define/public (collect ds fns) + (let ([ht (make-hash-table 'equal)]) + (map (lambda (d) + (collect-part d #f ht null)) + ds) + ht)) + + (define/public (collect-part d parent ht number) + (let ([p-ht (make-hash-table 'equal)]) + (when (part-title-content d) + (collect-content (part-title-content d) p-ht)) + (when (part-tag d) + (collect-part-tag d p-ht)) + (collect-flow (part-flow d) p-ht) + (let loop ([parts (part-parts d)] + [pos 1]) + (unless (null? parts) + (let ([s (car parts)]) + (collect-part s d p-ht + (cons (if (unnumbered-part? s) + #f + pos) + number)) + (loop (cdr parts) + (if (unnumbered-part? s) pos (add1 pos)))))) + (set-part-collected-info! d (make-collected-info + number + parent + p-ht)) + (hash-table-for-each p-ht + (lambda (k v) + (hash-table-put! ht k v))))) + + (define/public (collect-part-tag d ht) + (hash-table-put! ht `(part ,(part-tag d)) (part-title-content d))) + + (define/public (collect-content c ht) + (for-each (lambda (i) + (collect-element i ht)) + c)) + + (define/public (collect-paragraph p ht) + (collect-content (paragraph-content p) ht)) + + (define/public (collect-flow p ht) + (for-each (lambda (p) + (collect-flow-element p ht)) + (flow-paragraphs p))) + + (define/public (collect-flow-element p ht) + (cond + [(table? p) (collect-table p ht)] + [(itemization? p) (collect-itemization p ht)] + [(delayed-flow-element? p) (void)] + [else (collect-paragraph p ht)])) + + (define/public (collect-table i ht) + (for-each (lambda (d) (collect-flow d ht)) + (apply append (table-flowss i)))) + + (define/public (collect-itemization i ht) + (for-each (lambda (d) (collect-flow d ht)) + (itemization-flows i))) + + (define/public (collect-element i ht) + (when (target-element? i) + (collect-target-element i ht)) + (when (index-element? i) + (collect-index-element i ht)) + (when (element? i) + (for-each (lambda (e) + (collect-element e ht)) + (element-content i)))) + + (define/public (collect-target-element i ht) + (hash-table-put! ht (target-element-tag i) i)) + + (define/public (collect-index-element i ht) + (hash-table-put! ht `(index-entry ,(index-element-tag i)) + (list (index-element-plain-seq i) + (index-element-entry-seq i)))) + + ;; ---------------------------------------- + ;; render methods + + (define/public (render ds fns ht) + (map (lambda (d fn) + (printf " [Output to ~a]\n" fn) + (with-output-to-file fn + (lambda () + (render-one d ht fn)) + 'truncate/replace)) + + ds + fns)) + + (define/public (render-one d ht fn) + (render-part d ht)) + + (define/public (render-part d ht) + (list + (when (part-title-content d) + (render-content (part-title-content d) d ht)) + (render-flow (part-flow d) d ht) + (map (lambda (s) (render-part s ht)) + (part-parts d)))) + + (define/public (render-content c part ht) + (apply append + (map (lambda (i) + (render-element i part ht)) + c))) + + (define/public (render-paragraph p part ht) + (render-content (paragraph-content p) part ht)) + + (define/public (render-flow p part ht) + (apply append + (map (lambda (p) + (render-flow-element p part ht)) + (flow-paragraphs p)))) + + (define/public (render-flow-element p part ht) + (cond + [(table? p) (render-table p part ht)] + [(itemization? p) (render-itemization p part ht)] + [(delayed-flow-element? p) (render-flow-element + ((delayed-flow-element-render p) this part ht) + part ht)] + [else (render-paragraph p part ht)])) + + (define/public (render-table i part ht) + (map (lambda (d) (render-flow d part ht)) + (apply append (table-flowss i)))) + + (define/public (render-itemization i part ht) + (map (lambda (d) (render-flow d part ht)) + (itemization-flows i))) + + (define/public (render-element i part ht) + (cond + [(and (link-element? i) + (null? (element-content i))) + (let ([v (hash-table-get ht (link-element-tag i) #f)]) + (if v + (render-content v part ht) + (render-content (list "[missing]") part ht)))] + [(element? i) + (render-content (element-content i) part ht)] + [(delayed-element? i) + (render-content (force-delayed-element i this part ht) part ht)] + [else + (render-other i part ht)])) + + (define/public (render-other i part ht) + (list i)) + + ;; ---------------------------------------- + + (define/public (install-file fn) + (let ([src-dir (path-only fn)] + [dest-dir (get-dest-directory)] + [fn (file-name-from-path fn)]) + (let ([src-file (build-path (or src-dir (current-directory)) + fn)] + [dest-file (build-path (or dest-dir (current-directory)) + fn)]) + (unless (and (file-exists? dest-file) + (call-with-input-file* + src-file + (lambda (src) + (call-with-input-file* + dest-file + (lambda (dest) + (or (equal? (port-file-identity src) + (port-file-identity dest)) + (let loop () + (let ([s (read-bytes 4096 src)] + [d (read-bytes 4096 dest)]) + (and (equal? s d) + (if (eof-object? s) + #t + (loop))))))))))) + (when (file-exists? dest-file) (delete-file dest-file)) + (copy-file src-file dest-file)) + (path->string fn)))) + + ;; ---------------------------------------- + + (define/public (table-of-contents part ht) + (make-table #f (cdr (render-toc part)))) + + (define/private (render-toc part) + (let ([number (collected-info-number (part-collected-info part))]) + (cons + (list (make-flow + (list + (make-paragraph + (list + (make-element 'hspace (list (make-string (* 2 (length number)) #\space))) + (make-link-element "toclink" + (append + (format-number number + (list + (make-element 'hspace '(" ")))) + (part-title-content part)) + `(part ,(part-tag part)))))))) + (apply + append + (map (lambda (p) (render-toc p)) (part-parts part)))))) + + ;; ---------------------------------------- + + (super-new)))) diff --git a/collects/scribble/basic.ss b/collects/scribble/basic.ss new file mode 100644 index 00000000..5fac4c40 --- /dev/null +++ b/collects/scribble/basic.ss @@ -0,0 +1,189 @@ + +(module basic mzscheme + (require "decode.ss" + "struct.ss" + "config.ss" + (lib "kw.ss") + (lib "list.ss") + (lib "class.ss")) + + (provide title + section + subsection + subsubsection + subsubsub*section + include-section) + + (define (gen-tag content) + (regexp-replace* "[^-a-zA-Z0-9_=]" + (content->string content) + "_")) + + (define/kw (title #:key [tag #f] #:body str) + (let ([content (decode-content str)]) + (make-title-decl (or tag (gen-tag content)) content))) + + (define/kw (section #:key [tag #f] #:body str) + (let ([content (decode-content str)]) + (make-part-start 0 (or tag (gen-tag content)) content))) + + (define/kw (subsection #:key [tag #f] #:body str) + (let ([content (decode-content str)]) + (make-part-start 1 (or tag (gen-tag content)) content))) + + (define/kw (subsubsection #:key [tag #f] #:body str) + (let ([content (decode-content str)]) + (make-part-start 2 (or tag (gen-tag content)) content))) + + (define/kw (subsubsub*section #:key [tag #f] #:body str) + (let ([content (decode-content str)]) + (make-paragraph (list (make-element 'bold content))))) + + (define-syntax include-section + (syntax-rules () + [(_ mod) + (begin + (require (only mod doc)) + doc)])) + + ;; ---------------------------------------- + + (provide itemize item item?) + + (define/kw (itemize #:body items) + (let ([items (filter (lambda (v) (not (whitespace? v))) items)]) + (for-each (lambda (v) + (unless (an-item? v) + (error 'itemize + "expected an item, found something else: ~e" + v))) + items) + (make-itemization (map an-item-flow items)))) + + (define-struct an-item (flow)) + (define (item? x) (an-item? x)) + + (define/kw (item #:body str) + (make-an-item (decode-flow str))) + + ;; ---------------------------------------- + + (provide hspace + elem + italic bold + tt span-class + subscript superscript) + + (define (hspace n) + (make-element 'hspace (list (make-string n #\space)))) + + (define/kw (elem #:body str) + (make-element #f (decode-content str))) + + (define/kw (italic #:body str) + (make-element 'italic (decode-content str))) + + (define/kw (bold #:body str) + (make-element 'bold (decode-content str))) + + (define/kw (tt #:body str) + (make-element 'tt (decode-content str))) + + (define/kw (span-class classname #:body str) + (make-element classname (decode-content str))) + + (define/kw (subscript #:body str) + (make-element 'subscript (decode-content str))) + + (define/kw (superscript #:body str) + (make-element superscript (decode-content str))) + + ;; ---------------------------------------- + + (provide index index* as-index index-section) + + (define (gen-target) + (format "index:~s:~s" (current-seconds) (gensym))) + + (define (record-index word-seq element-seq tag content) + (make-index-element + #f + (list (make-target-element #f content tag)) + tag + word-seq + element-seq)) + + (define/kw (index* word-seq content-seq #:body s) + (let ([key (gen-target)]) + (record-index word-seq + content-seq + key + (decode-content s)))) + + (define/kw (index word-seq #:body s) + (let ([word-seq (if (string? word-seq) + (list word-seq) + word-seq)]) + (apply index* word-seq word-seq s))) + + (define/kw (as-index #:body s) + (let ([key (gen-target)] + [content (decode-content s)]) + (record-index (list (content->string content)) + (list (make-element #f content)) + key + content))) + + (define (index-section tag) + (make-unnumbered-part + tag + (list "Index") + #f + (make-flow (list (make-delayed-flow-element + (lambda (renderer sec ht) + (let ([l null]) + (hash-table-for-each + (collected-info-info + (part-collected-info + (collected-info-parent + (part-collected-info sec)))) + (lambda (k v) + (if (and (pair? k) + (eq? 'index-entry (car k))) + (set! l (cons (cons (cadr k) v) l))))) + (let ([l (sort + l + (lambda (a b) + (let loop ([a (cadr a)][b (cadr b)]) + (cond + [(null? a) #t] + [(null? b) #f] + [(string-ci=? (car a) (car b)) + (loop (cdr a) (cdr b))] + [else + (string-ci (car a) (car b))]))))]) + (make-table + 'index + (map (lambda (i) + (list (make-flow + (list + (make-paragraph + (list + (make-link-element + #f + (caddr i) + (car i)))))))) + l)))))))) + null)) + + ;; ---------------------------------------- + + (provide table-of-contents) + + (define (table-of-contents) + (make-delayed-flow-element + (lambda (renderer part ht) + (send renderer table-of-contents part ht))))) + + + diff --git a/collects/scribble/bnf.ss b/collects/scribble/bnf.ss new file mode 100644 index 00000000..ecfcd699 --- /dev/null +++ b/collects/scribble/bnf.ss @@ -0,0 +1,74 @@ + +(module bnf mzscheme + (require "struct.ss" + "decode.ss" + (lib "kw.ss") + (lib "class.ss")) + + (provide BNF + nonterm + BNF-seq + BNF-alt ; single-lie alternatives + BNF-etc + BNF-group + optional kleenestar kleeneplus kleenerange) + + (define spacer (make-element 'hspace (list " "))) + (define equals (make-element 'tt (list spacer "::=" spacer))) + (define alt (make-element 'tt (list spacer spacer "|" spacer spacer))) + + (define (as-flow i) (make-flow (list (make-paragraph (list i))))) + + (define (BNF . defns) + (make-table + #f + (apply + append + (map (lambda (defn) + (cons + (list (as-flow spacer) (as-flow (car defn)) (as-flow equals) (as-flow (cadr defn))) + (map (lambda (i) + (list (as-flow spacer) (as-flow " ") (as-flow alt) (as-flow i))) + (cddr defn)))) + defns)))) + + (define (interleave l spacer) + (make-element #f (cons (car l) + (apply append + (map (lambda (i) + (list spacer i)) + (cdr l)))))) + + (define (BNF-seq . l) + (if (null? l) + "" + (interleave l spacer))) + + (define (BNF-alt . l) + (interleave l alt)) + + (define BNF-etc "...") + + (define/kw (nonterm #:body s) + (make-element #f (append (list "<") + (list (make-element 'italic (decode-content s))) + (list ">")))) + + (define/kw (optional #:body s) + (make-element #f (append (list "[") (decode-content s) (list "]")))) + + (define/kw (BNF-group #:body s) + (make-element #f (append (list "{") + (list (apply BNF-seq (decode-content s))) + (list "}")))) + + (define/kw (kleenestar #:body s) + (make-element #f (append (decode-content s) (list "*")))) + + (define/kw (kleeneplus #:body s) + (make-element #f (append (decode-content s) (list (make-element 'superscript (list "+")))))) + + (define/kw (kleenerange a b #:body s) + (make-element #f (append (decode-content s) + (list (make-element 'superscript + (list (format "{~a,~a}" a b)))))))) diff --git a/collects/scribble/config.ss b/collects/scribble/config.ss new file mode 100644 index 00000000..9907cd0a --- /dev/null +++ b/collects/scribble/config.ss @@ -0,0 +1,6 @@ + +(module config mzscheme + + (provide value-color) + + (define value-color "DarkBlue")) diff --git a/collects/scribble/decode.ss b/collects/scribble/decode.ss new file mode 100644 index 00000000..b245e7ad --- /dev/null +++ b/collects/scribble/decode.ss @@ -0,0 +1,178 @@ + +(module decode mzscheme + (require "struct.ss" + (lib "contract.ss") + (lib "class.ss")) + + (provide decode + decode-part + decode-flow + decode-paragraph + decode-content + decode-string + whitespace?) + + (provide-structs + [title-decl ([tag any/c] + [content list?])] + [part-start ([depth integer?] + [tag (or/c false/c string?)] + [title list?])] + [splice ([run list?])]) + + (define (decode-string s) + (let loop ([l '((#rx"---" mdash) + (#rx"--" ndash) + (#rx"``" ldquo) + (#rx"''" rdquo) + (#rx"'" rsquo))]) + (cond + [(null? l) (list s)] + [(regexp-match-positions (caar l) s) + => (lambda (m) + (append (decode-string (substring s 0 (caar m))) + (cdar l) + (decode-string (substring s (cdar m)))))] + [else (loop (cdr l))]))) + + (define (line-break? v) + (and (string? v) + (equal? v "\n"))) + + (define (whitespace? v) + (and (string? v) + (regexp-match #px"^[\\s]*$" v))) + + (define (decode-accum-para accum) + (if (andmap whitespace? accum) + null + (list (decode-paragraph (reverse (skip-whitespace accum)))))) + + (define (decode-flow* l tag title part-depth) + (let loop ([l l][next? #f][accum null][title title][tag tag]) + (cond + [(null? l) (make-part tag + title + #f + (make-flow (decode-accum-para accum)) + null)] + [(title-decl? (car l)) + (unless part-depth + (error 'decode + "misplaced title: ~e" + (car l))) + (when title + (error 'decode + "found extra title: ~v" + (car l))) + (loop (cdr l) next? accum (title-decl-content (car l)) (title-decl-tag (car l)))] + [(or (paragraph? (car l)) + (table? (car l)) + (itemization? (car l)) + (delayed-flow-element? (car l))) + (let ([para (decode-accum-para accum)] + [part (decode-flow* (cdr l) tag title part-depth)]) + (make-part (part-tag part) + (part-title-content part) + (part-collected-info part) + (make-flow (append para + (list (car l)) + (flow-paragraphs (part-flow part)))) + (part-parts part)))] + [(part? (car l)) + (let ([para (decode-accum-para accum)] + [part (decode-part (cdr l) tag title part-depth)]) + (make-part (part-tag part) + (part-title-content part) + (part-collected-info part) + (make-flow (append para + (flow-paragraphs + (part-flow part)))) + (cons (car l) (part-parts part))))] + [(and (part-start? (car l)) + (or (not part-depth) + ((part-start-depth (car l)) . <= . part-depth))) + (unless part-depth + (error 'decode + "misplaced part: ~e" + (car l))) + (let ([s (car l)]) + (let loop ([l (cdr l)] + [s-accum null]) + (if (or (null? l) + (or (and (part-start? (car l)) + ((part-start-depth (car l)) . <= . part-depth)) + (part? (car l)))) + (let ([para (decode-accum-para accum)] + [s (decode-part (reverse s-accum) + (part-start-tag s) + (part-start-title s) + (add1 part-depth))] + [part (decode-part l tag title part-depth)]) + (make-part (part-tag part) + (part-title-content part) + (part-collected-info part) + (make-flow para) + (cons s (part-parts part)))) + (loop (cdr l) (cons (car l) s-accum)))))] + [(splice? (car l)) + (loop (append (splice-run (car l)) (cdr l)) next? accum title tag)] + [(null? (cdr l)) (loop null #f (cons (car l) accum) title tag)] + [(and (pair? (cdr l)) + (splice? (cadr l))) + (loop (cons (car l) (append (splice-run (cadr l)) (cddr l))) next? accum title tag)] + [(line-break? (car l)) + (if next? + (loop (cdr l) #t accum title tag) + (let ([m (match-newline-whitespace (cdr l))]) + (if m + (let ([part (loop m #t null title tag)]) + (make-part (part-tag part) + (part-title-content part) + (part-collected-info part) + (make-flow (append (decode-accum-para accum) + (flow-paragraphs (part-flow part)))) + (part-parts part))) + (loop (cdr l) #f (cons (car l) accum) title tag))))] + [else (loop (cdr l) #f (cons (car l) accum) title tag)]))) + + (define (decode-part l tag title depth) + (decode-flow* l tag title depth)) + + (define (decode-flow l) + (part-flow (decode-flow* l #f #f #f))) + + (define (match-newline-whitespace l) + (cond + [(null? l) #f] + [(line-break? (car l)) + (skip-whitespace l)] + [(splice? (car l)) + (match-newline-whitespace (append (splice-run (car l)) + (cdr l)))] + [(whitespace? (car l)) + (match-newline-whitespace (cdr l))] + [else #f])) + + (define (skip-whitespace l) + (let loop ([l l]) + (if (or (null? l) + (not (whitespace? (car l)))) + l + (loop (cdr l))))) + + (define (decode l) + (decode-part l #f #f 0)) + + (define (decode-paragraph l) + (make-paragraph + (decode-content l))) + + (define (decode-content l) + (apply append + (map (lambda (s) + (cond + [(string? s) + (decode-string s)] + [else (list s)])) + (skip-whitespace l))))) diff --git a/collects/scribble/doclang.ss b/collects/scribble/doclang.ss new file mode 100644 index 00000000..ad6ee794 --- /dev/null +++ b/collects/scribble/doclang.ss @@ -0,0 +1,61 @@ + +(module doclang mzscheme + (require "struct.ss" + "decode.ss" + (lib "kw.ss")) + (require-for-syntax (lib "kerncase.ss" "syntax")) + + (provide (all-from-except mzscheme #%module-begin) + (rename *module-begin #%module-begin)) + + ;; Module wrapper ---------------------------------------- + + (define-syntax (*module-begin stx) + (syntax-case stx () + [(_ id exprs . body) + #'(#%plain-module-begin + (doc-begin id exprs . body))])) + + (define-syntax (doc-begin stx) + (syntax-case stx () + [(_ m-id (expr ...)) + #`(begin + (define m-id (decode (list . #,(reverse (syntax->list #'(expr ...)))))) + (provide m-id))] + [(_ m-id exprs . body) + ;; `body' probably starts with lots of string constants; + ;; it's slow to trampoline on every string, so do them + ;; in a batch here: + (let loop ([body #'body] + [accum null]) + (syntax-case body () + [(s . rest) + (string? (syntax-e #'s)) + (loop #'rest (cons #'s accum))] + [() + (with-syntax ([(accum ...) accum]) + #`(doc-begin m-id (accum ... . exprs)))] + [(body1 . body) + (with-syntax ([exprs (append accum #'exprs)]) + (let ([expanded (local-expand #'body1 + 'module + (append + (kernel-form-identifier-list #'here) + (syntax->list #'(provide + require + require-for-syntax))))]) + (syntax-case expanded (begin) + [(begin body1 ...) + #`(doc-begin m-id exprs body1 ... . body)] + [(id . rest) + (and (identifier? #'id) + (ormap (lambda (kw) (module-identifier=? #'id kw)) + (syntax->list #'(require + provide + require-for-syntax + define-values + define-syntaxes + define-for-syntaxes)))) + #`(begin #,expanded (doc-begin m-id exprs . body))] + [_else + #`(doc-begin m-id (#,expanded . exprs) . body)])))]))]))) diff --git a/collects/scribble/docreader.ss b/collects/scribble/docreader.ss new file mode 100644 index 00000000..8329a325 --- /dev/null +++ b/collects/scribble/docreader.ss @@ -0,0 +1,34 @@ + +(module docreader mzscheme + (require (prefix scribble: "reader.ss") + (lib "kw.ss")) + + (provide (rename *read read) + (rename *read-syntax read-syntax)) + + (define (call-with-scribble-params t) + (parameterize ([scribble:read-accept-=-keyword #f] + [scribble:read-insert-indents #f]) + (t))) + + (define/kw (*read #:optional [inp (current-input-port)]) + (call-with-scribble-params + (lambda () + (wrap inp (scribble:read-inside inp))))) + + (define/kw (*read-syntax #:optional src [port (current-input-port)]) + (call-with-scribble-params + (lambda () + (wrap port (scribble:read-inside-syntax src port))))) + + (define (wrap port body) + (let* ([p-name (object-name port)] + [name (if (path? p-name) + (let-values ([(base name dir?) (split-path p-name)]) + (string->symbol (path->string (path-replace-suffix name #"")))) + 'page)] + [id 'doc]) + `(module ,name (lib "doclang.ss" "scribble") + (#%module-begin + ,id () + . ,body))))) diff --git a/collects/scribble/eval.ss b/collects/scribble/eval.ss new file mode 100644 index 00000000..866d7ce2 --- /dev/null +++ b/collects/scribble/eval.ss @@ -0,0 +1,227 @@ + +(module eval mzscheme + (require "manual.ss" + "struct.ss" + "scheme.ss" + "decode.ss" + (lib "class.ss") + (lib "file.ss") + (lib "string.ss")) + + (provide interaction + interaction-eval + interaction-eval-show + schemeblock+eval + schememod+eval + def+int + defs+int + examples + defexamples + + current-int-namespace + eval-example-string + + scribble-eval-handler) + + (define current-int-namespace (make-parameter (make-namespace))) + (define scribble-eval-handler (make-parameter (lambda (c? x) (eval x)))) + + (define image-counter 0) + + (define (interleave title expr-paras val-list+outputs) + (make-table + #f + (append + (if title (list (list title)) null) + (let loop ([expr-paras expr-paras] + [val-list+outputs val-list+outputs] + [first? #t]) + (if (null? expr-paras) + null + (append + (list (list (let ([p (car expr-paras)]) + (if (flow? p) + p + (make-flow (list p)))))) + (append + (if (string? (car val-list+outputs)) + (list + (list (make-flow (list (make-paragraph + (list + (hspace 2) + (span-class "schemeerror" + (italic (car val-list+outputs))))))))) + (append + (if (string=? "" (cdar val-list+outputs)) + null + (list + (list + (make-flow + (list + (let ([s (regexp-split #rx"\n" + (regexp-replace #rx"\n$" + (cdar val-list+outputs) + ""))]) + (if (= 1 (length s)) + (make-paragraph + (list + (hspace 2) + (span-class "schemestdout" (car s)))) + (make-table + #f + (map (lambda (s) + (list (make-flow (list (make-paragraph + (list + (hspace 2) + (span-class "schemestdout" s))))))) + s))))))))) + (let ([val-list (caar val-list+outputs)]) + (if (equal? val-list (list (void))) + null + (map (lambda (v) + (list (make-flow (list (make-paragraph + (list + (hspace 2) + (span-class "schemeresult" + (to-element/no-color v)))))))) + val-list))))) + (loop (cdr expr-paras) + (cdr val-list+outputs) + #f)))))))) + + (define (do-eval s) + (cond + [(and (list? s) + (eq? 'code:line (car s)) + (= (length s) 3) + (list? (caddr s)) + (eq? 'code:comment (caaddr s))) + (do-eval (cadr s))] + [(and (list? s) + (eq? 'eval:alts (car s)) + (= (length s) 3)) + (do-eval (caddr s))] + [else + (let ([o (open-output-string)]) + (parameterize ([current-output-port o]) + (with-handlers ([exn? (lambda (e) + (exn-message e))]) + (cons (do-plain-eval s #t) + (get-output-string o)))))])) + + (define (strip-comments s) + (cond + [(and (pair? s) + (pair? (car s)) + (eq? (caar s) 'code:comment)) + (strip-comments (cdr s))] + [(pair? s) + (cons (strip-comments (car s)) + (strip-comments (cdr s)))] + [(eq? s 'code:blank) (void)] + [else s])) + + + (define (do-plain-eval s catching-exns?) + (parameterize ([current-namespace (current-int-namespace)]) + (call-with-values (lambda () ((scribble-eval-handler) catching-exns? (strip-comments s))) list))) + + (define-syntax interaction-eval + (syntax-rules () + [(_ e) (#%expression + (begin (parameterize ([current-command-line-arguments #()]) + (do-plain-eval (quote e) #f)) + ""))])) + + + (define (show-val v) + (span-class "schemeresult" + (to-element/no-color v))) + + (define-syntax interaction-eval-show + (syntax-rules () + [(_ e) (#%expression + (parameterize ([current-command-line-arguments #()]) + (show-val (car (do-plain-eval (quote e) #f)))))])) + + (define (eval-example-string s) + (eval (read (open-input-string s)))) + + (parameterize ([current-namespace (current-int-namespace)]) + (eval `(define eval-example-string ,eval-example-string))) + + (define-syntax schemeinput* + (syntax-rules (eval-example-string eval:alts) + [(_ (eval-example-string s)) + (make-paragraph + (list + (hspace 2) + (tt "> ") + (span-class "schemevalue" (schemefont s))))] + [(_ (eval:alts a b)) (schemeinput* a)] + [(_ e) (schemeinput e)])) + + (define (defspace p) + (make-flow (list p + (make-paragraph null)))) + + (define-syntax (schemedefinput* stx) + (syntax-case stx (eval-example-string define) + [(_ (eval-example-string s)) + #'(schemeinput* (eval-example-string s))] + [(_ (define . rest)) + (syntax-case stx () + [(_ e) #'(defspace (schemeblock e))])] + [(_ (code:line (define . rest) . rest2)) + (syntax-case stx () + [(_ e) #'(defspace (schemeblock e))])] + [(_ e) #'(schemeinput e)])) + + (define-syntax titled-interaction + (syntax-rules () + [(_ t schemeinput* e ...) + (interleave t + (list (schemeinput* e) ...) + (map do-eval (list (quote e) ...)))])) + + (define-syntax interaction + (syntax-rules () + [(_ e ...) (titled-interaction #f schemeinput* e ...)])) + + (define-syntax schemeblock+eval + (syntax-rules () + [(_ e ...) + (#%expression + (begin (interaction-eval e) ... + (schemeblock e ...)))])) + + (define-syntax schememod+eval + (syntax-rules () + [(_ name e ...) + (#%expression + (begin (interaction-eval e) ... + (schememod name e ...)))])) + + (define-syntax def+int + (syntax-rules () + [(_ def e ...) + (make-splice (list (schemeblock+eval def) + (interaction e ...)))])) + + (define-syntax defs+int + (syntax-rules () + [(_ [def ...] e ...) + (make-splice (list (schemeblock+eval def ...) + (interaction e ...)))])) + + (define example-title + (make-flow (list (make-paragraph (list "Examples:"))))) + (define-syntax examples + (syntax-rules () + [(_ e ...) + (titled-interaction example-title schemeinput* e ...)])) + (define-syntax defexamples + (syntax-rules () + [(_ e ...) + (titled-interaction example-title schemedefinput* e ...)]))) + diff --git a/collects/scribble/html-render.ss b/collects/scribble/html-render.ss new file mode 100644 index 00000000..eccc0e81 --- /dev/null +++ b/collects/scribble/html-render.ss @@ -0,0 +1,324 @@ + +(module html-render mzscheme + (require "struct.ss" + (lib "class.ss") + (lib "file.ss") + (lib "runtime-path.ss") + (prefix xml: (lib "xml.ss" "xml"))) + (provide render-mixin + render-multi-mixin) + + (xml:empty-tag-shorthand xml:html-empty-tags) + + (define-runtime-path scribble-css "scribble.css") + + (define current-subdirectory (make-parameter #f)) + (define current-output-file (make-parameter #f)) + (define on-separate-page (make-parameter #f)) + (define collecting-sub (make-parameter 0)) + + ;; ---------------------------------------- + ;; main mixin + + (define (render-mixin %) + (class % + (inherit render-content + render-flow-element + collect-part + install-file + get-dest-directory + format-number) + + (define/override (get-suffix) #".html") + + ;; ---------------------------------------- + + (define/override (collect ds fns) + (let ([ht (make-hash-table 'equal)]) + (map (lambda (d fn) + (parameterize ([current-output-file fn]) + (collect-part d #f ht null))) + ds + fns) + ht)) + + (define/override (collect-part-tag d ht) + (hash-table-put! ht + `(part ,(part-tag d)) + (list (current-output-file) + (part-title-content d)))) + + (define/override (collect-target-element i ht) + (hash-table-put! ht + (target-element-tag i) + (list (current-output-file) #f))) + + ;; ---------------------------------------- + + (define/public (render-one-part d ht fn number) + (parameterize ([current-output-file fn]) + (let ([xpr `(html () + (head + (meta ((http-equiv "content-type") + (content "text-html; charset=utf-8"))) + ,@(let ([c (part-title-content d)]) + (if c + `((title ,@(render-content c d ht))) + null)) + (link ((rel "stylesheet") + (type "text/css") + (href "scribble.css") + (title "default")))) + (body ,@(render-part d ht)))]) + (install-file scribble-css) + (xml:write-xml/content (xml:xexpr->xml xpr))))) + + (define/override (render-one d ht fn) + (render-one-part d ht fn null)) + + (define/override (render-part d ht) + (let ([number (collected-info-number (part-collected-info d))]) + `(,@(if (and (not (part-title-content d)) + (null? number)) + null + `((,(case (length number) + [(0) 'h2] + [(1) 'h3] + [else 'h4]) + ,@(format-number number '((tt nbsp))) + ,@(if (part-tag d) + `((a ((name ,(format "~a" `(part ,(part-tag d))))))) + null) + ,@(if (part-title-content d) + (render-content (part-title-content d) d ht) + null)))) + ,@(render-flow* (part-flow d) d ht #f) + ,@(let loop ([pos 1] + [secs (part-parts d)]) + (if (null? secs) + null + (append + (render-part (car secs) ht) + (loop (add1 pos) (cdr secs)))))))) + + (define/private (render-flow* p part ht special-last?) + ;; Wrap each table with
, except for a trailing table
+ ;; when `special-last?' is #t
+ (let loop ([f (flow-paragraphs p)])
+ (cond
+ [(null? f) null]
+ [(and (table? (car f))
+ (or (not special-last?)
+ (not (null? (cdr f)))))
+ (cons `(p ,@(render-flow-element (car f) part ht))
+ (loop (cdr f)))]
+ [else
+ (append (render-flow-element (car f) part ht)
+ (loop (cdr f)))])))
+
+ (define/override (render-flow p part ht)
+ (render-flow* p part ht #t))
+
+ (define/override (render-paragraph p part ht)
+ `((p ,@(super render-paragraph p part ht))))
+
+ (define/override (render-element e part ht)
+ (cond
+ [(target-element? e)
+ `((a ((name ,(target-element-tag e))) ,@(render-plain-element e part ht)))]
+ [(link-element? e)
+ (let ([dest (hash-table-get ht (link-element-tag e) #f)])
+ (if dest
+ `((a ((href ,(format "~a#~a"
+ (from-root (car dest)
+ (get-dest-directory))
+ (link-element-tag e)))
+ ,@(if (string? (element-style e))
+ `((class ,(element-style e)))
+ null))
+ ,@(if (null? (element-content e))
+ (render-content (cadr dest) part ht)
+ (render-content (element-content e) part ht))))
+ `((font ((class "badlink"))
+ ,@(if (null? (element-content e))
+ `(,(format "~s" (link-element-tag e)))
+ (render-plain-element e part ht))))))]
+ [else (render-plain-element e part ht)]))
+
+ (define/private (render-plain-element e part ht)
+ (let ([style (and (element? e)
+ (element-style e))])
+ (cond
+ [(symbol? style)
+ (case style
+ [(italic) `((i ,@(super render-element e part ht)))]
+ [(bold) `((b ,@(super render-element e part ht)))]
+ [(tt) `((tt ,@(super render-element e part ht)))]
+ [(sf) `((b (font ([size "-1"][face "Helvetica"]) ,@(super render-element e part ht))))]
+ [(subscript) `((sub ,@(super render-element e part ht)))]
+ [(superscript) `((sup ,@(super render-element e part ht)))]
+ [(hspace) `((tt ,@(map (lambda (c) 'nbsp) (string->list (content->string (element-content e))))))]
+ [else (error 'html-render "unrecognized style symbol: ~e" style)])]
+ [(string? style)
+ `((span ([class ,style]) ,@(super render-element e part ht)))]
+ [(target-url? style)
+ `((a ((href ,(target-url-addr style))) ,@(super render-element e part ht)))]
+ [(image-file? style) `((img ((src ,(install-file (image-file-path style))))))]
+ [else (super render-element e part ht)])))
+
+ (define/override (render-table t part ht)
+ `((table ((cellspacing "0") ,@(case (table-style t)
+ [(boxed) '((width "100%") (bgcolor "lightgray"))]
+ [(centered) '((align "center"))]
+ [else null]))
+ ,@(map (lambda (flows)
+ `(tr ,@(map (lambda (d a)
+ `(td ,@(case a
+ [(#f) null]
+ [(right) '(((align "right")))]
+ [(left) '(((align "left")))])
+ ,@(render-flow d part ht)))
+ flows
+ (cdr (or (and (list? (table-style t))
+ (assoc 'alignment (or (table-style t) null)))
+ (cons #f (map (lambda (x) #f) flows)))))))
+ (table-flowss t)))))
+
+ (define/override (render-itemization t part ht)
+ `((ul
+ ,@(map (lambda (flow)
+ `(li ,@(render-flow flow part ht)))
+ (itemization-flows t)))))
+
+ (define/override (render-other i part ht)
+ (list (cond
+ [(string? i) i]
+ [(eq? i 'mdash) `(span " " ndash " ")]
+ [(symbol? i) i]
+ [else (format "~s" i)])))
+
+ ;; ----------------------------------------
+
+ (super-new)))
+
+ ;; ----------------------------------------
+ ;; multi-file output
+
+ (define (render-multi-mixin %)
+ (class %
+ (inherit render-one
+ render-one-part
+ render-content)
+
+ (define/override (get-suffix) #"")
+
+ (define/override (get-dest-directory)
+ (or (build-path (or (super get-dest-directory) (current-directory))
+ (current-subdirectory))
+ (super get-dest-directory)))
+
+ (define/private (derive-filename d)
+ (format "~a.html" (regexp-replace*
+ "[^-a-zA-Z0-9_=]"
+ (or (format "~a" (part-tag d))
+ (content->string (part-title-content d)))
+ "_")))
+
+ (define/override (collect ds fns)
+ (super collect ds (map (lambda (fn)
+ (build-path fn "index.html"))
+ fns)))
+
+ (define/override (collect-part d parent ht number)
+ (let ([prev-sub (collecting-sub)])
+ (parameterize ([collecting-sub (add1 prev-sub)])
+ (if (= 1 prev-sub)
+ (let ([filename (derive-filename d)])
+ (parameterize ([current-output-file (build-path (path-only (current-output-file))
+ filename)])
+ (super collect-part d parent ht number)))
+ (super collect-part d parent ht number)))))
+
+ (define/override (render ds fns ht)
+ (map (lambda (d fn)
+ (printf " [Output to ~a/index.html]\n" fn)
+ (unless (directory-exists? fn)
+ (make-directory fn))
+ (parameterize ([current-subdirectory (file-name-from-path fn)])
+ (let ([fn (build-path fn "index.html")])
+ (with-output-to-file fn
+ (lambda ()
+ (render-one d ht fn))
+ 'truncate/replace))))
+ ds
+ fns))
+
+ (define/override (render-part d ht)
+ (let ([number (collected-info-number (part-collected-info d))])
+ (cond
+ [(and (not (on-separate-page))
+ (= 1 (length number)))
+ ;; Render as just a link, and put the actual
+ ;; content in a new file:
+ (let* ([filename (derive-filename d)]
+ [full-path (build-path (path-only (current-output-file))
+ filename)])
+ (parameterize ([on-separate-page #t])
+ (with-output-to-file full-path
+ (lambda ()
+ (render-one-part d ht full-path number))
+ 'truncate/replace)
+ null
+ #;
+ `((table
+ ((width "90%") (cellspacing "0") (align "center"))
+ ,@(render-toc-entry d filename ht number)))))]
+ [else
+ ;; Normal section render
+ (super render-part d ht)])))
+
+ (super-new)))
+
+ ;; ----------------------------------------
+ ;; utils
+
+ (define (from-root p d)
+ (if d
+ (let ([e-d (explode (path->complete-path d (current-directory)))]
+ [e-p (explode (path->complete-path p (current-directory)))])
+ (let loop ([e-d e-d]
+ [e-p e-p])
+ (cond
+ [(null? e-d) (let loop ([e-p e-p])
+ (cond
+ [(null? e-p) "/"]
+ [(null? (cdr e-p)) (car e-p)]
+ [(eq? 'same (car e-p)) (loop (cdr e-p))]
+ [(eq? 'up (car e-p))
+ (string-append "../" (loop (cdr e-p)))]
+ [else (string-append (car e-p)
+ "/"
+ (loop (cdr e-p)))]))]
+ [(equal? (car e-d) (car e-p))
+ (loop (cdr e-d) (cdr e-p))]
+ [(eq? 'same (car e-d))
+ (loop (cdr e-d) e-p)]
+ [(eq? 'same (car e-p))
+ (loop e-d (cdr e-p))]
+ [else
+ (string-append
+ (apply string-append (map (lambda (x) "../") e-d))
+ (loop null e-p))])))
+ p))
+
+ (define (explode p)
+ (reverse (let loop ([p p])
+ (let-values ([(base name dir?) (split-path p)])
+ (let ([name (if base
+ (if (path? name)
+ (path-element->string name)
+ name)
+ name)])
+ (if (path? base)
+ (cons name (loop base))
+ (list name))))))))
diff --git a/collects/scribble/latex-render.ss b/collects/scribble/latex-render.ss
new file mode 100644
index 00000000..c61c3b20
--- /dev/null
+++ b/collects/scribble/latex-render.ss
@@ -0,0 +1,208 @@
+
+(module latex-render mzscheme
+ (require "struct.ss"
+ (lib "class.ss"))
+ (provide render-mixin)
+
+ (define current-table-depth (make-parameter 0))
+
+ (define-struct (toc-paragraph paragraph) ())
+
+ (define (render-mixin %)
+ (class %
+ (define/override (get-suffix) #".tex")
+
+ (inherit render-flow
+ render-content
+ install-file)
+
+ (define (define-color s s2)
+ (printf "\\newcommand{\\~a}[1]{{\\texttt{\\color{~a}{#1}}}}\n" s s2))
+
+ (define/override (render-one d ht fn)
+ (printf "\\documentclass{article}\n")
+ (printf "\\parskip=10pt%\n")
+ (printf "\\parindent=0pt%\n")
+ (printf "\\usepackage{graphicx}\n")
+ (printf "\\usepackage{fullpage}\n")
+ (printf "\\usepackage{longtable}\n")
+ (printf "\\usepackage[usenames,dvipsnames]{color}\n")
+ (define-color "schemeplain" "black")
+ (printf "\\newcommand{\\schemekeyword}[1]{{\\color{black}{\\texttt{\\textbf{#1}}}}}\n")
+ (printf "\\newcommand{\\schemesyntaxlink}[1]{\\schemekeyword{#1}}\n")
+ (define-color "schemecomment" "Brown")
+ (define-color "schemeparen" "BrickRed")
+ (define-color "schemeinputcol" "BrickRed")
+ (define-color "schemesymbol" "NavyBlue")
+ (define-color "schemevalue" "ForestGreen")
+ (define-color "schemevaluelink" "blue")
+ (define-color "schemeresult" "blue")
+ (define-color "schemestdout" "Purple")
+ (define-color "schemevariablecol" "NavyBlue")
+ (printf "\\newcommand{\\schemevariable}[1]{{\\schemevariablecol{\\textsl{#1}}}}\n")
+ (define-color "schemeerrorcol" "red")
+ (printf "\\newcommand{\\schemeerror}[1]{{\\schemeerrorcol{\\textit{#1}}}}\n")
+ (printf "\\newcommand{\\schemeopt}[1]{#1}\n")
+ (printf "\\newcommand{\\textsub}[1]{$_{#1}$}\n")
+ (printf "\\newcommand{\\textsuper}[1]{$^{#1}$}\n")
+ (printf "\\definecolor{LightGray}{rgb}{0.85,0.85,0.85}\n")
+ (printf "\\newcommand{\\schemeinput}[1]{\\colorbox{LightGray}{\\schemeinputcol{#1}}}\n")
+ (printf "\\begin{document}\n")
+ (when (part-title-content d)
+ (printf "\\title{")
+ (render-content (part-title-content d) d ht)
+ (printf "}\\maketitle\n"))
+ (render-part d ht)
+ (printf "\\end{document}\n"))
+
+ (define/override (render-part d ht)
+ (let ([number (collected-info-number (part-collected-info d))])
+ (when (and (part-title-content d)
+ (pair? number))
+ (printf "\\~a~a{"
+ (case (length number)
+ [(0 1) "section"]
+ [(2) "subsection"]
+ [(3) "subsubsection"]
+ [else "subsubsection*"])
+ (if (and (pair? number)
+ (not (car number)))
+ "*"
+ ""))
+ (render-content (part-title-content d) d ht)
+ (printf "}"))
+ (when (part-tag d)
+ (printf "\\label{section:~a}" (part-tag d)))
+ (render-flow (part-flow d) d ht)
+ (for-each (lambda (sec) (render-part sec ht))
+ (part-parts d))
+ null))
+
+ (define/override (render-paragraph p part ht)
+ (printf "\n\n")
+ (if (toc-paragraph? p)
+ (printf "\\tableofcontents")
+ (super render-paragraph p part ht))
+ (printf "\n\n")
+ null)
+
+ (define/override (render-element e part ht)
+ (when (and (link-element? e)
+ (pair? (link-element-tag e))
+ (eq? 'part (car (link-element-tag e))))
+ (printf "\\S\\ref{section:~a} " (cadr (link-element-tag e))))
+ (let ([style (and (element? e)
+ (element-style e))]
+ [wrap (lambda (e s)
+ (printf "{\\~a{" s)
+ (super render-element e part ht)
+ (printf "}}"))])
+ (cond
+ [(symbol? style)
+ (case style
+ [(italic) (wrap e "textit")]
+ [(bold) (wrap e "textbf")]
+ [(tt) (wrap e "texttt")]
+ [(sf) (wrap e "textsf")]
+ [(subscript) (wrap e "textsub")]
+ [(superscript) (wrap e "textsuper")]
+ [(hspace) (let ([s (content->string (element-content e))])
+ (unless (zero? (string-length s))
+ (printf "{\\texttt ~a}"
+ (regexp-replace* #rx"." s "~"))))]
+ [else (error 'latex-render "unrecognzied style symbol: ~s" style)])]
+ [(string? style)
+ (wrap e style)]
+ [(image-file? style)
+ (let ([fn (install-file (image-file-path style))])
+ (printf "\\includegraphics{~a}" fn))]
+ [else (super render-element e part ht)]))
+ null)
+
+ (define/override (render-table t part ht)
+ (let* ([boxed? (eq? 'boxed (table-style t))]
+ [index? (eq? 'index (table-style t))]
+ [tableform (cond
+ [index? "theindex"]
+ [(zero? (current-table-depth))
+ "longtable"]
+ [else "tabular"])]
+ [opt (if (zero? (current-table-depth))
+ "[l]"
+ "")])
+ (unless (null? (table-flowss t))
+ (parameterize ([current-table-depth (add1 (current-table-depth))])
+ (if index?
+ (printf "\n\n\\begin{theindex}\n")
+ (printf "\n\n~a\\begin{~a}~a{@{}~a@{}}\n"
+ (if boxed? "\\vspace{4ex}\\hrule\n\\vspace{-2ex}\n" "")
+ tableform
+ opt
+ (make-string (length (car (table-flowss t))) #\l)))
+ (for-each (lambda (flows)
+ (let loop ([flows flows])
+ (unless (null? flows)
+ (render-flow (car flows) part ht)
+ (unless (null? (cdr flows))
+ (printf " &\n")
+ (loop (cdr flows)))))
+ (unless index?
+ (printf " \\\\\n")))
+ (table-flowss t))
+ (printf "\n\n\\end{~a}\n" tableform))))
+ null)
+
+ (define/override (render-itemization t part ht)
+ (printf "\n\n\\begin{itemize}\n")
+ (for-each (lambda (flow)
+ (printf "\n\n\\item ")
+ (render-flow flow part ht))
+ (itemization-flows t))
+ (printf "\n\n\\end{itemize}\n")
+ null)
+
+ (define/override (render-other i part ht)
+ (cond
+ [(string? i) (display-protected i)]
+ [(symbol? i) (display
+ (case i
+ [(nbsp) "~"]
+ [(mdash) "---"]
+ [(ndash) "--"]
+ [(ldquo) "``"]
+ [(rdquo) "''"]
+ [(rsquo) "'"]
+ [(rarr) "$\\rightarrow$"]))]
+ [else (display-protected (format "~s" i))])
+ null)
+
+ (define/private (display-protected s)
+ (let ([len (string-length s)])
+ (let loop ([i 0])
+ (unless (= i len)
+ (let ([c (string-ref s i)])
+ (case c
+ [(#\\) (display "$\\backslash$")]
+ [(#\_) (display "$\\_$")]
+ [(#\>) (display "$>$")]
+ [(#\<) (display "$<$")]
+ [(#\~) (display "$\\sim$")]
+ [(#\{ #\} #\# #\% #\&) (display "\\") (display c)]
+ [(#\uDF) (display "{\\ss}")]
+ [(#\u039A #\u0391 #\u039F #\u03A3
+ #\u03BA #\u03b1 #\u03BF #\u03C3)
+ (printf "$\\backslash$u~a"
+ (let ([s (format "0000~x" (char->integer c))])
+ (substring s (- (string-length s) 4))))]
+ [else (display c)]))
+ (loop (add1 i))))))
+
+ ;; ----------------------------------------
+
+ (define/override (table-of-contents sec ht)
+ ;; FIXME: isn't local to the section
+ (make-toc-paragraph null))
+
+ ;; ----------------------------------------
+
+ (super-new))))
diff --git a/collects/scribble/manual.ss b/collects/scribble/manual.ss
new file mode 100644
index 00000000..70e50f6b
--- /dev/null
+++ b/collects/scribble/manual.ss
@@ -0,0 +1,467 @@
+
+(module manual mzscheme
+ (require "decode.ss"
+ "struct.ss"
+ "scheme.ss"
+ "config.ss"
+ "basic.ss"
+ (lib "string.ss")
+ (lib "kw.ss")
+ (lib "list.ss")
+ (lib "class.ss"))
+
+ (provide (all-from "basic.ss"))
+
+ (provide PLaneT)
+ (define PLaneT "PLaneT")
+
+ (define-code schemeblock0 to-paragraph)
+ (define-code schemeblock (to-paragraph/prefix (hspace 2)
+ (hspace 2)))
+ (define-code SCHEMEBLOCK (to-paragraph/prefix (hspace 2)
+ (hspace 2))
+ UNSYNTAX)
+ (define-code SCHEMEBLOCK0 to-paragraph UNSYNTAX)
+ (define-code schemeinput (to-paragraph/prefix (make-element
+ #f
+ (list
+ (hspace 2)
+ (make-element 'tt (list "> " ))))
+ (hspace 4)))
+
+ (define-syntax (schememod stx)
+ (syntax-case stx ()
+ [(_ lang rest ...)
+ (with-syntax ([modtag (datum->syntax-object
+ #'here
+ '(unsyntax (schemefont "#module "))
+ #'lang)])
+ #'(schemeblock modtag lang rest ...))]))
+
+ (define (to-element/result s)
+ (make-element "schemeresult" (list (to-element/no-color s))))
+ (define (to-element/id s)
+ (make-element "schemesymbol" (list (to-element/no-color s))))
+
+ (define-code scheme to-element unsyntax (lambda (ctx s v) s))
+ (define-code schemeresult to-element/result unsyntax (lambda (ctx s v) s))
+ (define-code schemeid to-element/id unsyntax (lambda (ctx s v) s))
+ (define-code schememodname to-element unsyntax (lambda (ctx s v) s))
+
+ (define (litchar . strs)
+ (unless (andmap string? strs)
+ (raise-type-error 'litchar "strings" strs))
+ (let ([s (apply string-append
+ (map (lambda (s) (if (string=? s "\n") " " s))
+ strs))])
+ (let ([spaces (regexp-match-positions #rx"^ *" s)])
+ (make-element "schemeinput"
+ (list (hspace (cdar spaces))
+ (make-element 'tt (list (substring s (cdar spaces)))))))))
+
+ (define (verbatim s)
+ (let ([strs (regexp-split #rx"\n" s)])
+ (make-table
+ #f
+ (map (lambda (s)
+ (list (make-flow (list (make-paragraph
+ (let ([spaces (cdar (regexp-match-positions #rx"^ *" s))])
+ (list
+ (hspace spaces)
+ (make-element 'tt (list (substring s spaces))))))))))
+ strs))))
+
+ (provide schemeblock SCHEMEBLOCK
+ schemeblock0 SCHEMEBLOCK0
+ schemeinput
+ schememod
+ scheme schemeresult schemeid schememodname
+ litchar
+ verbatim)
+
+ (provide onscreen menuitem defterm
+ schemefont schemevalfont schemeresultfont schemeidfont
+ schemeparenfont schemekeywordfont
+ file exec
+ link procedure
+ idefterm)
+
+ (define/kw (onscreen #:body str)
+ (make-element 'sf (decode-content str)))
+ (define (menuitem menu item)
+ (make-element 'sf (list menu "|" item)))
+ (define/kw (defterm #:body str)
+ (make-element 'italic (decode-content str)))
+ (define/kw (idefterm #:body str)
+ (let ([c (decode-content str)])
+ (make-element 'italic c)))
+ (define/kw (schemefont #:body str)
+ (apply tt str))
+ (define/kw (schemevalfont #:body str)
+ (make-element "schemevalue" (decode-content str)))
+ (define/kw (schemeresultfont #:body str)
+ (make-element "schemeresult" (decode-content str)))
+ (define/kw (schemeidfont #:body str)
+ (make-element "schemesymbol" (decode-content str)))
+ (define/kw (schemeparenfont #:body str)
+ (make-element "schemeparen" (decode-content str)))
+ (define/kw (schemekeywordfont #:body str)
+ (make-element "schemekeyword" (decode-content str)))
+ (define/kw (file #:body str)
+ (make-element 'tt (append (list "\"") (decode-content str) (list "\""))))
+ (define/kw (exec #:body str)
+ (make-element 'tt (decode-content str)))
+ (define/kw (procedure #:body str)
+ (make-element 'tt (append (list "#