racket/collects/scribble/run.rkt
2010-05-21 19:40:33 -06:00

142 lines
5.9 KiB
Racket

#lang racket/base
(require "core.ss"
"base-render.ss"
"xref.ss"
scheme/cmdline
scheme/file
scheme/class
raco/command-name
(prefix-in text: "text-render.ss")
(prefix-in html: "html-render.ss")
(prefix-in latex: "latex-render.ss")
(prefix-in pdf: "pdf-render.ss"))
(define multi-html:render-mixin
(lambda (%) (html:render-multi-mixin (html:render-mixin %))))
(define current-render-mixin (make-parameter text:render-mixin))
(define current-dest-directory (make-parameter #f))
(define current-dest-name (make-parameter #f))
(define current-info-output-file (make-parameter #f))
(define current-info-input-files (make-parameter null))
(define current-xref-input-modules (make-parameter null))
(define current-prefix-file (make-parameter #f))
(define current-style-file (make-parameter #f))
(define current-style-extra-files (make-parameter null))
(define current-extra-files (make-parameter null))
(define current-redirect (make-parameter #f))
(define current-redirect-main (make-parameter #f))
(define current-quiet (make-parameter #f))
(define (read-one str)
(let ([i (open-input-string str)])
(with-handlers ([exn:fail:read? (lambda (x) #f)])
(let ([v (read i)])
(and (eof-object? (read i)) v)))))
(current-render-mixin html:render-mixin)
(define (run)
(command-line
#:program (short-program+command-name)
#:once-any
[("--text") "generate text-format output (the default)"
(current-render-mixin text:render-mixin)]
[("--html") "generate HTML-format output file"
(current-render-mixin html:render-mixin)]
[("--htmls") "generate HTML-format output directory"
(current-render-mixin multi-html:render-mixin)]
[("--latex") "generate LaTeX-format output"
(current-render-mixin latex:render-mixin)]
[("--pdf") "generate PDF-format output (with PDFLaTeX)"
(current-render-mixin pdf:render-mixin)]
#:once-each
[("--dest") dir "write output in <dir>"
(current-dest-directory dir)]
[("--dest-name") name "write output as <name>"
(current-dest-name name)]
[("--prefix") file "use given .html/.tex prefix (for doctype/documentclass)"
(current-prefix-file file)]
[("--style") file "use given base .css/.tex file"
(current-style-file file)]
[("--redirect") url "redirect external links to tag search via <url>"
(current-redirect url)]
[("--redirect-main") url "redirect main doc links to <url>"
(current-redirect-main url)]
[("--info-out") file "write format-specific link information to <file>"
(current-info-output-file file)]
#:multi
[("++extra") file "add given file"
(current-extra-files (cons file (current-extra-files)))]
[("++style") file "add given .css/.tex file after others"
(current-style-extra-files (cons file (current-style-extra-files)))]
[("++info-in") file "load format-specific link information from <file>"
(current-info-input-files
(cons file (current-info-input-files)))]
[("++xref-in") module-path proc-id "load format-specific link information by"
"calling <proc-id> as exported by <module-path>"
(let ([mod (read-one module-path)]
[id (read-one proc-id)])
(unless (module-path? mod)
(raise-user-error
'scribble "bad module path for ++ref-in: ~s" module-path))
(unless (symbol? id)
(raise-user-error
'scribble "bad procedure identifier for ++ref-in: ~s" proc-id))
(current-xref-input-modules
(cons (cons mod id) (current-xref-input-modules))))]
#:once-each
[("--quiet") "suppress output-file reporting"
(current-quiet #t)]
#:args (file . another-file)
(let ([files (cons file another-file)])
(build-docs (map (lambda (file) (dynamic-require `(file ,file) 'doc))
files)
files))))
(define (build-docs docs files)
(define dir (current-dest-directory))
(when dir (make-directory* dir))
(let ([renderer (new ((current-render-mixin) render%)
[dest-dir dir]
[prefix-file (current-prefix-file)]
[style-file (current-style-file)]
[style-extra-files (reverse (current-style-extra-files))]
[extra-files (reverse (current-extra-files))])])
(when (current-redirect)
(send renderer set-external-tag-path (current-redirect)))
(when (current-redirect-main)
(send renderer set-external-root-url (current-redirect-main)))
(unless (current-quiet)
(send renderer report-output!))
(let* ([fns (map (lambda (fn)
(let-values ([(base name dir?) (split-path fn)])
(let ([fn (path-replace-suffix
(or (current-dest-name) name)
(send renderer get-suffix))])
(if dir (build-path dir fn) fn))))
files)]
[fp (send renderer traverse docs fns)]
[info (send renderer collect docs fns fp)])
(for ([file (in-list (reverse (current-info-input-files)))])
(let ([s (with-input-from-file file read)])
(send renderer deserialize-info s info)))
(for ([mod+id (in-list (reverse (current-xref-input-modules)))])
(let* ([get-xref (dynamic-require (car mod+id) (cdr mod+id))]
[xr (get-xref)])
(unless (xref? xr)
(raise-user-error
'scribble "result from `~s' of `~s' is not an xref: ~e"
(cdr mod+id) (car mod+id) xr))
(xref-transfer-info renderer info xr)))
(let ([r-info (send renderer resolve docs fns info)])
(send renderer render docs fns r-info)
(when (current-info-output-file)
(let ([s (send renderer serialize-info r-info)])
(with-output-to-file (current-info-output-file)
#:exists 'truncate/replace
(lambda () (write s)))))))))
(run)