scribble-enhanced/scribble-doc/scribblings/scribble/renderer.scrbl
Vincent St-Amour cce1eff495 Extend special characters using a function rather than a dict.
Based on feedback from David Van Horn.
2016-08-24 16:14:03 -05:00

475 lines
18 KiB
Racket

#lang scribble/doc
@(require scribble/manual
"utils.rkt"
(for-label racket/class
scribble/render
scribble/xref))
@(define-syntax-rule (defmodule/local lib . content)
(begin
(define-syntax-rule (intro)
(begin
(require (for-label lib))
(defmodule lib)
. content))
(intro)))
@(begin
(define-syntax-rule (def-html-render-mixin id mid)
(begin
(require (for-label scribble/html-render))
(define id @racket[render-mixin])
(define mid @racket[render-multi-mixin])))
(def-html-render-mixin html:render-mixin html:render-multi-mixin))
@(begin
(define-syntax-rule (def-latex-render-mixin id)
(begin
(require (for-label scribble/latex-render))
(define id @racket[render-mixin])))
(def-latex-render-mixin latex:render-mixin))
@title[#:tag "renderer"]{Renderers}
A renderer is an object that provides four main methods:
@racket[traverse], @racket[collect], @racket[resolve], and
@racketidfont{render}. Each method corresponds to a pass described in
@secref["core"], and they are chained together by the @racket[render]
function to render a document.
@section{Rendering Driver}
@defmodule[scribble/render]
@defproc[(render [docs (listof part?)]
[names (listof path-string?)]
[#:render-mixin render-mixin (class? . -> . class?) @#,html:render-mixin]
[#:dest-dir dest-dir (or/c #f path-string?) #f]
[#:helper-file-prefix helper-file-prefix (or/c #f string?) #f]
[#:prefix-file prefix-file (or/c #f path-string?) #f]
[#:style-file style-file (or/c #f path-string?) #f]
[#:style-extra-files style-extra-files (listof path-string?) #f]
[#:extra-files extra-files (listof path-string?) #f]
[#:image-preferences image-preferences (listof (or/c 'ps 'pdf 'png 'svg 'gif)) null]
[#:xrefs xrefs (listof xref?) null]
[#:info-in-files info-in-files (listof path-string?) null]
[#:info-out-file info-out-file (or/c #f path-string?) #f]
[#:redirect redirect (or/c #f string?) #f]
[#:redirect-main redirect-main (or/c #f string?) #f]
[#:directory-depth directory-depth exact-nonnegative-integer? 0]
[#:quiet? quiet? any/c #t]
[#:warn-undefined? warn-undefined? any/c (not quiet?)])
void?]{
Renders the given @racket[docs], each with an output name derived from
the corresponding element of @racket[names]. A directory path (if any)
for a name in @racket[names] is discarded, and the file suffix is
replaced (if any) with a suitable suffix for the output format.
The @racket[render-mixin] argument determines the output format. By
default, it is @html:render-mixin from @racketmodname[scribble/html-render].
The @racket[dest-dir] argument determines the output directory, which
is created using @racket[make-directory*] if it is non-@racket[#f] and
does not exist already.
The @racket[helper-file-prefix], @racket[prefix-file],
@racket[style-file], @racket[style-extra-files], and
@racket[extra-files] arguments are passed on to the @racket[render%]
constructor.
The @racket[image-preferences] argument specified preferred formats
for image files and conversion, where formats listed earlier in the
list are more preferred. The renderer specified by
@racket[render-mixin] may not support all of the formats listed in
@racket[image-preferences].
The @racket[xrefs] argument provides extra cross-reference information
to be used during the documents' @tech{resolve pass}. The
@racket[info-in-files] arguments supply additional cross-reference
information in serialized form. When the @racket[info-out-file]
argument is not @racket[#f], cross-reference information for the
rendered documents is written in serialized for to the specified file.
The @racket[redirect] and @racket[redirect-main] arguments correspond
to the @racket[set-external-tag-path] and
@racket[set-external-root-url] methods of @|html:render-mixin| from
@racketmodname[scribble/html-render], so they should be
non-@racket[#f] only for HTML rendering.
The @racket[directory-depth] arguments correspond to the
@racket[set-directory-depth] method of @|html:render-multi-mixin|.
If @racket[quiet?] is a false value, output-file information is
written to the current output port.
If @racket[warn-undefined?] is a true value, then references to
missing cross-reference targets trigger a warning message on the
current error port.
@history[#:changed "1.4" @elem{Added the @racket[#:image-preferences] argument.}]}
@section{Base Renderer}
@defmodule[scribble/base-render]{The
@racketmodname[scribble/base-render] module provides @racket[render%],
which implements the core of a renderer. This rendering class must be
refined with a mixin from @racketmodname[scribble/text-render],
@racketmodname[scribble/markdown-render], or
@racketmodname[scribble/html-render], or
@racketmodname[scribble/latex-render].}
The mixin structure is meant to support document-specific extensions
to the renderers. For example, the @exec{scribble} command-line tool
might, in the future, extract rendering mixins from a document module
(in addition to the document proper).
See the @filepath{base-render.rkt} source for more information about
the methods of the renderer. Documents built with higher layers, such
as @racketmodname[scribble/manual], generally do not call the render
object's methods directly.
@definterface[render<%> ()]{
@defmethod[(traverse [srcs (listof part?)]
[dests (listof path-string?)])
(and/c hash? immutable?)]{
Performs the @techlink{traverse pass}, producing a hash table that
contains the replacements for and @racket[traverse-block]s and
@racket[traverse-elements]s. See @method[render<%> render] for
information on the @racket[dests] argument.}
@defmethod[(collect [srcs (listof part?)]
[dests (listof path-string?)]
[fp (and/c hash? immutable?)]
[demand (tag? collect-info? . -> . any/c) (lambda (_tag _ci) #f)])
collect-info?]{
Performs the @techlink{collect pass}. See @method[render<%> render] for
information on the @racket[dests] arguments. The @racket[fp] argument
is a result from the @method[render<%> traverse] method.
The @racket[demand] argument supplies external tag mappings on demand.
When the @racket[collect-info] result is later used to find a mapping
for a tag and no mapping is already available, @racket[demand] is
called with the tag and the @racket[collect-info]. The @racket[demand]
function returns true to indicate when it adds information to the
@racket[collect-info] so that the lookup should be tried again; the
@racket[demand] function should return @racket[#f] if it does not
extend @racket[collect-info].}
@defmethod[(resolve [srcs (listof part?)]
[dests (listof path-string?)]
[ci collect-info?])
resolve-info?]{
Performs the @techlink{resolve pass}. See @method[render<%> render] for
information on the @racket[dests] argument. The @racket[ci] argument
is a result from the @method[render<%> collect] method.}
@defmethod[(render [srcs (listof part?)]
[dests (listof path-string?)]
[ri resolve-info?])
void?]{
Produces the final output. The @racket[ri] argument is a result from
the @method[render<%> render] method.
The @racket[dests] provide names of files for Latex or single-file
HTML output, or names of sub-directories for multi-file HTML output.
If the @racket[dests] are relative, they're relative to the current
directory; normally, they should indicates a path within the
@racket[_dest-dir] supplied on initialization of the @racket[render%]
object.}
@defmethod[(serialize-info [ri resolve-info?])
any/c]{
Serializes the collected info in @racket[ri].}
@defmethod[(serialize-infos [ri resolve-info?]
[count exact-positive-integer?]
[doc part?])
list?]{
Like @method[render<%> serialize-info], but produces @racket[count] results
that together have the same information as produced by
@method[render<%> serialize-info]. The structure of @racket[doc] is used to
drive the partitioning (on the assumption that @racket[ri] is derived
from @racket[doc]).}
@defmethod[(deserialize-info [v any/c]
[ci collect-info?]
[#:root root-path (or/c path-string? false/c) #f])
void?]{
Adds the deserialized form of @racket[v] to @racket[ci].
If @racket[root-path] is not @racket[#f], then file paths that are
recorded in @racket[ci] as relative to an instantiation-supplied
@racket[root-path] are deserialized as relative instead to the given
@racket[root-path].}
@defmethod[(get-defined [ci collect-info?]) (listof tag?)]{
Returns a list of tags that were defined within the documents
represented by @racket[ci].}
@defmethod[(get-defineds [ci collect-info?]
[count exact-positive-integer?]
[doc part?])
(listof (listof tag?))]{
Analogous to @method[render<%> serialize-infos]: returns a list of
tags for each of @racket[count] partitions of the result of
@method[render<%> get-defined], using the structure of @racket[doc] to
drive the partitioning.}
@defmethod[(get-external [ri resolve-info?]) (listof tag?)]{
Returns a list of tags that were referenced but not defined within the
documents represented by @racket[ri] (though possibly found in
cross-reference information transferred to @racket[ri] via
@racket[xref-transfer-info]).}
@defmethod[(get-undefined [ri resolve-info?]) (listof tag?)]{
Returns a list of tags that were referenced by the resolved documents
with no target found either in the resolved documents represented by
@racket[ri] or cross-reference information transferred to @racket[ri]
via @racket[xref-transfer-info].
If multiple tags were referenced via @racket[resolve-search] and a
target was found for any of the tags using the same dependency key,
then no tag in the set is included in the list of undefined tags.}
}
@defclass[render% object% (render<%>)]{
Represents a renderer.
@defconstructor[([dest-dir path-string?]
[refer-to-existing-files any/c #f]
[root-path (or/c path-string? #f) #f]
[prefix-file (or/c path-string? #f) #f]
[style-file (or/c path-string? #f) #f]
[style-extra-files (listof path-string?) null]
[extra-files (listof path-string?) null]
[image-preferences (listof (or/c 'ps 'pdf 'png 'svg 'gif)) null])]{
Creates a renderer whose output will go to @racket[dest-dir]. For
example, @racket[dest-dir] could name the directory containing the
output Latex file, the HTML file for a single-file output, or the
output sub-directory for multi-file HTML output.
If @racket[refer-to-existing-files] is true, then when a document
refers to external files, such as an image or a style file, then the
file is referenced from its source location instead of copied to the
document destination.
If @racket[root-path] is not @racket[#f], it is normally the same as
@racket[dest-dir] or a parent of @racket[dest-dir]. It causes
cross-reference information to record destination files relative to
@racket[root-path]; when cross-reference information is serialized, it
can be deserialized via @method[render<%> deserialize-info] with a
different root path (indicating that the destination files have
moved).
The @racket[prefix-file], @racket[style-file], and
@racket[style-extra-files] arguments set files that control output
styles in a formal-specific way; see @secref["config-style"] for more
information.
The @racket[extra-files] argument names files to be copied to the
output location, such as image files or extra configuration files.
The @racket[image-preferences] argument specified preferred formats
for image files and conversion, where formats listed earlier in the
list are more preferred. The renderer may not support all of the
formats listed in @racket[image-preferences].
@history[#:changed "1.4" @elem{Added the @racket[image-preferences]
initialization argument.}]}}
@; ----------------------------------------
@section{Text Renderer}
@defmodule/local[scribble/text-render]{
@defmixin[render-mixin (render<%>) ()]{
Specializes a @racket[render<%>] class for generating plain text.}}
@; ----------------------------------------
@section{Markdown Renderer}
@defmodule/local[scribble/markdown-render]{
@defmixin[render-mixin (render<%>) ()]{
Specializes a @racket[render<%>] class for generating Markdown text.
Code blocks are marked using the
@hyperlink["http://github.github.com/github-flavored-markdown/"
"Github convention"] @verbatim{```racket} so that they are lexed and
formatted as Racket code.}}
@; ----------------------------------------
@section{HTML Renderer}
@defmodule/local[scribble/html-render]{
@defmixin[render-mixin (render<%>) ()]{
@defconstructor/auto-super[([search-box? boolean? #f])]{
Specializes a @racket[render<%>] class for generating
HTML output. The arguments are the same as
@racket[render<%>], except for the addition of
@racket[search-box].
If @racket[search-box?] is @racket[#t] and the document
is created with @racket[scribble/manual], then it will be
rendered with a search box, similar to this page. Note
that the @racket[search-box?] argument does not create
the search page itself. Rather, it passes the search
query to whatever page is located at
@tt{search/index.html}. The query is passed as an HTTP
query string in the @tt{q} field.}
@defmethod[(set-external-tag-path [url string?]) void?]{
Configures the renderer to redirect links to external documents via
@racket[url], adding a @tt{tag} query element to the end of the
URL that contains the Base64-encoded, @racket[print]ed, serialized
original tag (in the sense of @racket[link-element]) for the link.
If the link is based on a cross-reference entry that has a
document-identifying string (see @racket[load-xref] and its
@racket[#:doc-id] argument), the document identifier is added as a
@tt{doc} query element, and a path to the target within the
document is added as a @tt{rel} query element.}
@defmethod[(set-external-root-url [url string?]) void?]{
Configures the renderer to redirect links to documents installed in
the distribution's documentation directory to the given URL, using the
URL as a replacement to the path of the distribution's document
directory.}
}
@defmixin[render-multi-mixin (render<%>) ()]{
Further specializes a rendering class produced by
@racket[render-mixin] for generating multiple HTML
files.
@defmethod[(set-directory-depth [depth exact-nonnegative-integer?]) void?]{
Sets the depth of directory structure used when rendering parts that
are own their own pages. A value of @racket[0] is treated the same as
@racket[1].}
}
}
@; ----------------------------------------
@section{Latex Renderer}
@defmodule/local[scribble/latex-render]{
@defmixin[render-mixin (render<%>) ()]{
Specializes a @racket[render<%>] class for generating Latex input.}}
@defparam[extra-character-conversions convs (-> char? (or/c string? #f))]{
Function that maps (special) characters to strings corresponding to the Latex
code that should be used to render them. This function should return false for
any character it does not know how to handle.
Scribble already converts many special characters to the proper Latex
commands. This parameter should be used in case you need characters it does not
support yet.
}
@; ----------------------------------------
@section{PDF Renderer}
@defmodule/local[scribble/pdf-render]{
@defmixin[render-mixin (render<%>) ()]{
Specializes a @racket[render<%>] class for generating PDF output via
Latex, building on @|latex:render-mixin| from @racketmodname[scribble/latex-render].}}
@; ----------------------------------------
@section{Contract (Blue boxes) Renderer}
@defmodule/local[scribble/contract-render]{
@defmixin[override-render-mixin-multi (render<%>) ()]{
Overrides the @method[render<%> render] method of
given renderer to record the content of the
blue boxes (generated by @racket[defproc], @racket[defform], etc)
that appear in the document.
@defmethod[#:mode override
(render [srcs (listof part?)]
[dests (listof path?)]
[ri render-info?])
void?]{
In addition to doing whatever the @racket[super] method
does, also save the content of the blue boxes (rendered
via a @racketmodname[scribble/text-render] renderer).
It saves this information in three pieces in a file
inside the @racket[dests] directories called
@filepath{blueboxes.rktd}. The first piece is
a single line containing a (decimal, ASCII) number. That number
is the number of bytes that the second piece of information
occupies in the file. The second piece of information
is a @racket[hash] that maps @racket[tag?] values to
a list of offsets and line numbers that follow the hash table.
For example, if the @racket[hash] maps
@racket['(def ((lib "x/main.rkt") abcdef))] to
@racket['((10 . 3))], then that means that the documentation
for the @racket[abcdef] export from the @racket[x] collection
starts 10 bytes after the end of the hash table and continues for
@racket[3] lines. Multiple elements in the list mean that that
@racket[tag?] has multiple blue boxes and each shows where one
of the boxes appears in the file.
}}
@defmixin[override-render-mixin-single (render<%>) ()]{
Just like @racket[override-render-mixin-multi], except
it saves the resulting files in a different place.
@defmethod[#:mode override
(render [srcs (listof part?)]
[dests (listof path?)]
[ri render-info?])
void?]{
Just like @method[override-render-mixin-multi render], except
that it saves the file @filepath{blueboxes.rktd} in
the same directory where each @racket[dests] element resides.
}}
}