#lang racket/base
(require (for-syntax racket/base
syntax/parse)
(for-template racket/base
scribble/manual)
racket/base
scribble/manual
syntax/parse
syntax/strip-context
"main.rkt"
"mcfly-misc.rkt"
"mcfly-parse.rkt"
"mcfly-spec.rkt")
(define (%mcfly-format expand-stx parsedata inforkt)
(let-values (((inforkt-loc) expand-stx)
((name-string) (inforkt 'name 'string))
((legal-string) (inforkt 'mcfly-legal 'string #f))
((planet-exact-string planet-relaxed-string planet-version-number-string)
(cond ((inforkt 'mcfly-planet 'symbol #f)
=> (lambda (planet-sym)
(let-values (((owner name major minor)
(parse-planet-symbol-string/ignore-equals
(symbol->string planet-sym))))
(values (format-exact-planet-version-string
owner name major minor)
(format-relaxed-planet-version-string
owner name major minor)
(string-append major ":" minor)))))
(else (values #f #f)))))
(quasisyntax/loc inforkt-loc
(begin
#,@(quasisyntax/loc expand-stx
#,(let ((warnings (mcfly-parsedata-warnings parsedata)))
(if (null? warnings)
#'()
#`((para (bold (racketerror "This document had warnings from McFly:")))
(itemlist
#,@(map (lambda (stx)
(quasisyntax/loc stx
(item (racketerror #,@(replace-context expand-stx stx)))))
warnings))))))
(title #,@(cond
((or (inforkt 'version 'string #f)
planet-version-number-string)
=> (lambda (version-string)
#`(#:version #,version-string)))
(else #'()))
#,@(let ((title-string (inforkt 'mcfly-title 'string #f))
(subtitle-string (inforkt 'mcfly-subtitle 'string #f)))
(cond ((and title-string subtitle-string)
(raise-syntax-error
'%mcfly-format
"both mcfly-title and mcfly-subtitle defined"
inforkt-loc))
(title-string
#`(#,title-string))
(subtitle-string
#`("" (bold #,name-string) ": " #,subtitle-string))
(else #`(#,name-string)))))
#,@(cond ((or (inforkt 'mcfly-author 'string #f)
(inforkt 'mcfly-authors 'string #f))
=> (lambda (auth)
#`((author #,auth))))
(else #'()))
#,@(let* ((license-string (or (inforkt 'mcfly-license 'string #f)
(and legal-string "(see below)")))
(homepage-string (inforkt 'homepage 'string #f)))
(if (or license-string homepage-string)
#`("\n" #,@(if license-string
#`("License: "
(seclink "Legal"
#:underline? #f
#,license-string))
#'())
#,@(if homepage-string
#`(#,@(if license-string
#'(" " (hspace 1) " ")
#'())
"Web: "
(link #,homepage-string
#:underline? #f
#,homepage-string))
#'())
"\n")
#'()))
#,@(if (and (inforkt 'mcfly-default-defmodule? 'boolean #t) planet-relaxed-string)
#`((defmodule (planet #,(string->symbol planet-relaxed-string))))
#'())
#,@(%mcfly-format-doc-parts expand-stx parsedata inforkt)
#,@(if legal-string
#`("\n" (section #:tag "Legal" "Legal") #,legal-string "\n")
#'())
))))
(define (%scribble-stx-toplevel? stx)
(syntax-parse stx
(((~datum require) Xn ...) #t)
(else #f)))
(define (%scribble-syntax-list-with-possible-paras-added context-stx orig-stx-list)
(letrec
((do-unknown-whether-null
(lambda (stx-list)
(if (null? stx-list)
'()
(let ((stx (car stx-list)))
(if (%scribble-stx-toplevel? stx)
(do-stx-is-toplevel stx
(cdr stx-list))
(let loop-nontoplevel-stxes ((reverse-nontoplevel-stxes (cons stx '()))
(stx-list (cdr stx-list)))
(if (or (null? stx-list) (%scribble-stx-toplevel? (car stx-list)))
(cons (quasisyntax/loc context-stx
(mcfly:para-if-pre-content
#,@(reverse reverse-nontoplevel-stxes)))
(if (null? stx-list)
'()
(do-stx-is-toplevel (car stx-list)
(cdr stx-list))))
(loop-nontoplevel-stxes (cons (car stx-list)
reverse-nontoplevel-stxes)
(cdr stx-list)))))))))
(do-stx-is-toplevel
(lambda (stx stx-list)
(cons stx (do-unknown-whether-null stx-list)))))
(do-unknown-whether-null orig-stx-list)))
(define (%mcfly-format-doc-parts expand-stx parsedata inforkt)
(quasisyntax/loc expand-stx
(#,@(let loop ((body-stxes (mcfly-parsedata-body-stxes parsedata))
(out-stxes '()))
(if (null? body-stxes)
(map (lambda (out-stx)
(replace-context expand-stx out-stx))
out-stxes)
(let ((body-stx (car body-stxes)))
(syntax-parse body-stx
((DOC:id (~datum scribble) Xn ...)
(loop (cdr body-stxes)
(append out-stxes
(%scribble-syntax-list-with-possible-paras-added
body-stx
(syntax->list (syntax (Xn ...)))))))
((DOC:id (~datum history) ITEM ...)
(loop (cdr body-stxes)
(append out-stxes
`(,(quasisyntax/loc body-stx
(section "History"))
,(quasisyntax/loc body-stx
(itemlist
#,@(map (lambda (item-stx)
(syntax-parse item-stx
(((~or (~optional (~seq #:planet PLANET) #:name "#:planet option")
(~optional (~seq #:version VERSION) #:name "#:version option")
(~optional (~seq #:date DATE) #:name "#:date option"))
...
BODYn ...)
(quasisyntax/loc item-stx
(item (para #,@(let loop ((in-pairs
`(("Version" . ,(attribute VERSION))
("PLaneT" . ,(let ((s (attribute PLANET)))
(and s
(let ((s2 (syntax-e s)))
(if (symbol? s2)
(datum->syntax (syntax PLANET)
(symbol->string s2))
s)))))
(#f . ,(attribute DATE))))
(out-stxes '()))
(if (null? in-pairs)
(reverse out-stxes)
(let ((pair (car in-pairs)))
(cond ((cdr pair)
=> (lambda (val-stx)
(loop (cdr in-pairs)
`(,val-stx
,@(cond ((car pair)
=> (lambda (label)
`(,#'" "
,(datum->syntax val-stx
(car pair)))))
(else '()))
,@(if (null? out-stxes)
'()
`(" --- "
,@out-stxes))))))
(else (loop (cdr in-pairs)
out-stxes)))))))
BODYn ...)))))
(syntax->list (syntax (ITEM ...))))))))))
(else (error '%mcfly-format-doc-parts
"Unrecognized doc syntax: ~S"
(syntax->datum body-stx))))))))))
(define (mcfly-format-from-file expand-stx rkt-path)
(let* ((rkt-path (path->complete-path (cleanse-path rkt-path)))
(info-path (parent-directory-of-path rkt-path)))
(%mcfly-format
expand-stx
(call-with-input-file rkt-path
(lambda (in)
(mcfly-parse in #:sourcename rkt-path)))
(get-inforkt info-path))))
(provide mcfly-format-from-file)