402 lines
15 KiB
Racket
402 lines
15 KiB
Racket
#lang scribble/manual
|
|
@require[@for-label[scribble-math
|
|
racket/base
|
|
scribble/core]
|
|
@for-syntax[racket/base
|
|
syntax/parse]
|
|
scribble-math]
|
|
|
|
|
|
@(define-syntax scribbleblock
|
|
(syntax-parser
|
|
[(_ (~optional (~seq #:keep-lang-line? keep-lang))
|
|
str ...+)
|
|
#`(codeblock
|
|
#:keep-lang-line? #,(if (attribute keep-lang) #'keep-lang #'#f)
|
|
"#lang scribble/base" "\n"
|
|
str ...)]))
|
|
|
|
@(define-syntax scribblecode
|
|
(syntax-parser
|
|
[(_ str ...+)
|
|
#`(code #:lang "scribble/base"
|
|
str ...)]))
|
|
|
|
@(use-mathjax)
|
|
|
|
@title[#:style (with-html5 manual-doc-style)]{@racketmodname[scribble-math]}
|
|
@author[
|
|
@author+email["Jens Axel Søgaard" "jensaxel@soegaard.net"]
|
|
@author+email["Suzanne Soy" "racket@suzanne.soy"]]
|
|
|
|
@defmodule[scribble-math]
|
|
|
|
This library allows typesetting math and Asymptote figures
|
|
in Scribble documents.
|
|
|
|
@(local-table-of-contents #:style 'immediate-only)
|
|
|
|
@section{Typesetting math with @racket[$] and @racket[$$]}
|
|
@defmodule[scribble-math/dollar]
|
|
|
|
@(define title-html5-code
|
|
@scribblecode|{@title[#:style (with-html5 manual-doc-style)]{…}}|)
|
|
|
|
The following functions help with typesetting mathematical
|
|
equations. The main functions are @racket[$] for
|
|
@tech{inline mode} math and @racket[$$] for @tech{display
|
|
mode} math, respectively. The functions @racket[use-katex]
|
|
and @racket[use-mathjax] change the rendering engine used,
|
|
the default being @racket[katex]. To use @racket[katex], it
|
|
is necessary to use
|
|
@title-html5-code or a similar configuration; for more
|
|
details see the documentation of @racket[with-html5].
|
|
|
|
@defproc[($ [str string?] ...) element?]{
|
|
Renders the given strings as @deftech{inline mode} math.
|
|
Inline mode math is typeset as part of the surrounding
|
|
text. Either MathJax or KaTeX is used for the HTML output,
|
|
depending on the current configuration. For the LaTeX
|
|
output, the code is simply passed as-is. For example, when
|
|
using MathJax, @racket[($ "x^2")] renders as
|
|
@(use-mathjax) @${x^2}.
|
|
|
|
The syntax accepted by @racket[$] is a subset of the
|
|
commands supported by LaTeX, and depends on the backend
|
|
used (MathJax should support more commands than KaTeX). For
|
|
details, see their respective documentation.}
|
|
|
|
@defproc[($$ [str string?] ...) element?]{
|
|
Renders the given strings as @deftech{display mode} math.
|
|
Display mode math is typeset alone on its line, and is
|
|
centered. Some symbols like @${\sum} are larger in display
|
|
mode than in @tech{inline mode}, which makes the former better for
|
|
complex equations. Either MathJax or KaTeX is used for the
|
|
HTML output, depending on the current configuration. For
|
|
the LaTeX output, the code is simply passed as-is. For
|
|
example, when using MathJax,
|
|
|
|
@racketblock[($$ "\\sum_{i=0}^n x_i^3")]
|
|
|
|
renders as:
|
|
|
|
@(use-mathjax)
|
|
@$${\sum_{i=0}^n x_i^3}
|
|
|
|
The syntax accepted by @racket[$$] is a subset of the
|
|
commands supported by LaTeX, and depends on the backend
|
|
used (MathJax should support more commands than KaTeX). For
|
|
details, see their respective documentation.}
|
|
|
|
@defproc[(with-html5 [doc-style style?]) style?]{
|
|
Alters the given document style, so that the resulting
|
|
document uses HTML5.
|
|
|
|
This function should be called to alter the
|
|
@racket[#:style] argument for @racket[title] when KaTeX is
|
|
used, as KaTeX is incompatible with the default scribble
|
|
@tt{DOCTYPE} (the HTML 4.01 Transitional loose DTD). The
|
|
scribble document should therefore contain code similar to
|
|
the following:
|
|
|
|
@scribbleblock|{
|
|
@title[#:style (with-html5 manual-doc-style)]{...}
|
|
}|
|
|
|
|
This function works by changing the existing
|
|
@racket[html-defaults] property or adding a new one, so
|
|
that it uses an HTML5
|
|
@tech[#:doc '(lib "scribblings/scribble/scribble.scrbl")]{prefix file}
|
|
(the @tech[#:doc '(lib "scribblings/scribble/scribble.scrbl")]{prefix file}
|
|
contains the @tt{DOCTYPE} line).}
|
|
|
|
@defparam[$-html-handler handler (→ (listof? string?) element?)
|
|
#:value $-katex]{
|
|
A parameter whose value is a function called by @racket[$],
|
|
to transform the math code into HTML. The @racket[$]
|
|
function uses this parameter only when rendering the
|
|
document as HTML.}
|
|
|
|
@defparam[$$-html-handler handler (→ (listof? string?) element?)
|
|
#:value $$-katex]{
|
|
A parameter whose value is a function called by
|
|
@racket[$$], to transform the math code into HTML. The
|
|
@racket[$$] function uses this parameter only when
|
|
rendering the document as HTML. }
|
|
|
|
@defproc[($-katex [math (listof? string?)]) element?]{
|
|
Produces an @racket[element?] which contains the given
|
|
@racket[math] code, so that it is rendered as @tech{inline
|
|
mode} math using KaTeX. More precisely, the resulting
|
|
element uses several scribble properties to add scripts and
|
|
stylesheets to the document. The resulting element also
|
|
uses a specific CSS class so that when the page is loaded
|
|
into a browser, KaTeX can recognise it and render it in
|
|
@tech{inline mode}.
|
|
|
|
@racket[($-katex "x^2")] renders as @$-katex{x^2}.}
|
|
|
|
@defproc[($$-katex [math (listof? string?)]) element?]{
|
|
Produces an @racket[element?] which contains the given
|
|
@racket[math] code, so that it is rendered as @tech{display
|
|
mode} math (centered, alone on its line) using KaTeX. More
|
|
precisely, the resulting element uses several scribble
|
|
properties to add scripts and stylesheets to the document.
|
|
The resulting element also uses a specific CSS class so
|
|
that when the page is loaded into a browser, KaTeX can
|
|
recognise it and render it in @tech{display mode}.
|
|
|
|
@racketblock[($$-katex "\\sum_{i=0}^n x_i^3")]
|
|
|
|
renders as:
|
|
|
|
@$$-katex{\sum_{i=0}^n x_i^3}}
|
|
|
|
@defproc[($-mathjax [math (listof? string?)]) element?]{
|
|
Produces an @racket[element?] which contains the given
|
|
@racket[math] code, so that it is rendered as @tech{inline
|
|
mode} math using MathJax. More precisely, the resulting
|
|
element uses several scribble properties to add scripts and
|
|
stylesheets to the document. The resulting element also
|
|
uses a specific CSS class so that when the page is loaded
|
|
into a browser, MathJax can recognise it and render it in
|
|
@tech{inline mode}.
|
|
|
|
@racket[($-mathjax "x^2")] renders as @$-mathjax{x^2}.}
|
|
|
|
@defproc[($$-mathjax [math (listof? string?)]) element?]{
|
|
Produces an @racket[element?] which contains the given
|
|
@racket[math] code, so that it is rendered as @tech{display
|
|
mode} math (centered, alone on its line) using KaTeX. More
|
|
precisely, the resulting element uses several scribble
|
|
properties to add scripts and stylesheets to the document.
|
|
The resulting element also uses a specific CSS class so
|
|
that when the page is loaded into a browser, MathJax can
|
|
recognise it and render it in @tech{display mode}.
|
|
|
|
@racketblock[($$-mathjax "\\sum_{i=0}^n x_i^3")]
|
|
|
|
renders as:
|
|
|
|
@$$-mathjax{\sum_{i=0}^n x_i^3}}
|
|
|
|
|
|
@defproc[($-tex2svg [math (listof? string?)]) element?]{
|
|
Produces an @racket[element?] which contains the given
|
|
@racket[math] rendered as an HTML SVG literal.
|
|
It is rendered in @tech{inline mode} math using @tt{tex2svg}.
|
|
More precisely, the resulting element uses the @racket[xexpr-property] to
|
|
render the SVG directly to the HTML document.
|
|
This means no new scripts or stylesheets are added to the document.
|
|
It also has no style, so its style cannot be customized.
|
|
|
|
@; @racket[($-tex2svg "x^2")] renders as @$-tex2svg{x^2}.
|
|
|
|
This procedure requires that @code{tex2svg} be installed via
|
|
@code{npm install mathjax-node-cli}.
|
|
|
|
This procedure requires Racket 6.12 or later.}
|
|
|
|
@defproc[($$-tex2svg [math (listof? string?)]) element?]{
|
|
Produces an @racket[element?] which contains the given
|
|
@racket[math] rendered as an HTML SVG literal.
|
|
It is rendered in @tech{display mode} math using @tt{tex2svg}.
|
|
More precisely, the resulting element uses the @racket[xexpr-property] to
|
|
render the SVG directly to the HTML document.
|
|
This means no new scripts or stylesheets are added to the document.
|
|
It also has no style, so its style cannot be customized.
|
|
|
|
|
|
@; @racketblock[($$-tex2svg "\\sum_{i=0}^n x_i^3")]
|
|
|
|
@; renders as:
|
|
|
|
@; @$$-tex2svg{\sum_{i=0}^n x_i^3}
|
|
|
|
This procedure requires that @code{tex2svg} be installed via
|
|
@code{npm install mathjax-node-cli}.
|
|
|
|
This procedure requires Racket 6.12 or later.}
|
|
|
|
@defproc[(use-katex) void?]{
|
|
This shorthand calls @racket[($-html-handler $-katex)]
|
|
and @racket[($$-html-handler $$-katex)]. The mathematical
|
|
formulas passed to @racket[$] and @racket[$$] which appear
|
|
later in the document will therefore be typeset using
|
|
KaTeX.
|
|
|
|
The KaTeX library will be added to the HTML document only
|
|
if it uses the result of one of @racket[$], @racket[$$],
|
|
@racket[$-katex] or @racket[$$-katex]. It is therefore safe
|
|
to call this function in libraries to change the default
|
|
handler, without the risk of adding extra resources to the
|
|
page if the user changes the default before typesetting any
|
|
math.}
|
|
|
|
@defproc[(use-mathjax) void?]{
|
|
This shorthand calls @racket[($-html-handler $-mathjax)]
|
|
and @racket[($$-html-handler $$-mathjax)]. The mathematical
|
|
formulas passed to @racket[$] and @racket[$$] which appear
|
|
later in the document will therefore be typeset using
|
|
MathJax.
|
|
|
|
The MathJax library will be added to the HTML document only
|
|
if i uses the result of one of @racket[$], @racket[$$],
|
|
@racket[$-katex] or @racket[$$-katex]. It is therefore safe
|
|
to call this function in libraries to change the default
|
|
handler, without the risk of adding extra resources to the
|
|
page if the user changes the default before typesetting any
|
|
math.}
|
|
|
|
@defproc[(use-tex2svg) void?]{
|
|
This shorthand calls @racket[($-html-handler $-tex2svg)] and
|
|
@racket[($$-html-handler $$-tex2svg)]. The mathematical formulas passed to
|
|
@racket[$] and @racket[$$] which appear later in the document will therefore be
|
|
typeset using @tt{tex2svg}.
|
|
|
|
No new CSS or JavaScript libraries will be added to the document. Instead, the
|
|
generated HTML document have the math embedded directly an @tt{svg}.
|
|
|
|
This requires that @tt{tex2svg} is installed on the system. You can install it
|
|
globally via @tt{sudo npm install --global mathjax-node-cli} or locally with
|
|
@tt{npm install mathjax-node-cli}. The backend will attempt to find the
|
|
@tt{tex2svg}, preferring local sources. You can set the path manually with
|
|
the parameter @racket[current-tex2svg-path].
|
|
|
|
@tt{tex2svg} will only be used when rendering an HTML document, and only if it
|
|
uses @racket[$] or @racket[$$] to render math. It is therefore safe to call
|
|
this function in libraries to change the default handler.
|
|
|
|
This procedure requires Racket 6.12 or later.}
|
|
|
|
@defparam[current-tex2svg-path path path? #:value #f]{
|
|
A parameter whose value is the path to the @tt{tex2svg} binary.
|
|
This binary is used to transform math code into HTML when using the @tt{tex2svg}
|
|
backend.
|
|
|
|
The functions @racket[$-tex2svg] and @racket[$$-tex2svg] use this parameter only
|
|
when rendering the document as HTML.
|
|
|
|
This parameter requires Racket 6.12 or later.}
|
|
|
|
@defparam[use-external-mathjax URL (or/c #f string?) #:value #f]{
|
|
|
|
A parameter whose value is the URL to the MathJax script
|
|
to use. The URL must be absolute, or relative to the URL
|
|
used to display the document.
|
|
|
|
For example, if the HTML document is accessed via @tt{
|
|
file:///home/user/docs/document1/index.html}, and
|
|
@racket[(use-external-mathjax "../common/MathJax/MathJax.js?config=default")] was
|
|
used, then MathJax will be loaded from @tt{
|
|
file:///home/user/docs/common/MathJax/MathJax.js?config=default}.
|
|
|
|
An URL to a CDN is also valid, but may be a poor choice
|
|
regarding the privacy of your users.
|
|
|
|
This feature is in beta and might not work, please report
|
|
any issue.}
|
|
|
|
@defparam[use-external-katex URLs (or/c #f (list/c string? string?)) #:value #f]{
|
|
|
|
A parameter whose value is a list containing the URL to the
|
|
KaTeX script and the URL to KaTeX CSS to use. The URLs must
|
|
be absolute, or relative to the URL used to display the
|
|
document.
|
|
|
|
For example, if the HTML document is accessed via @tt{
|
|
file:///home/user/docs/document1/index.html}, and
|
|
@racket[(use-external-katex (list "../common/KaTeX/katex.min.js" "../common/KaTeX/katex.min.css"))]
|
|
was used, then the KaTeX script will be loaded from @tt{
|
|
file:///home/user/docs/common/KaTeX/katex.min.js} and the
|
|
KaTeX stylesheet from @tt{
|
|
file:///home/user/docs/common/KaTeX/katex.min.css}.
|
|
|
|
An URL to a CDN is also valid, but may be a poor choice
|
|
regarding the privacy of your users.
|
|
|
|
Please note that using a .js and a .css file which are not
|
|
in the same directory is unsupported (it has not been tested
|
|
and may or may not work).
|
|
|
|
This feature is in beta and might not work, please report
|
|
any issue.}
|
|
|
|
@;@$${\sum_{i=0}ⁿ xᵢ³}
|
|
|
|
When using MathJax, @racket[$] and @racket[$$] wrap their
|
|
content with @racket["$…$"] and @racket["\\[…\\]"]
|
|
respectively, and insert it in an element with the class
|
|
@racket["tex2jax_process"]. MathJax is configured to only
|
|
process elements with this class, so it is safe to use
|
|
@tt{$} signs in the source document. For example, the text
|
|
$\sum x^3$ is typeset as-is, like the rest of the text.
|
|
|
|
When using @tt{tex2svg}, no additional JavaScript processing is done on the
|
|
page, so it is safe to use @tt{$} signs in the source document. For example, the
|
|
text $\sum x^3$ is typeset as-is, like the rest of the text.
|
|
|
|
@section{Drawing figures with Asymptote}
|
|
|
|
@defmodule[scribble-math/asymptote]
|
|
|
|
@defproc[(asymptote [#:cache cache? any/c #t] [str string?] ...+) image?]{
|
|
Renders the figure described by the given strings using
|
|
Asymptote. If @racket[cache?] is @racket[#f], then the
|
|
resulting images are generated into temporary PNG, SVG and
|
|
PDF files using @racket[make-temporary-file]. Otherwise, to
|
|
improve compilation speed, the result is cached in the
|
|
@filepath{asymptote-images} directory, based on a checksum
|
|
of the strings. It is a good idea to clean up the working
|
|
directory after experimenting a lot with a figure, as it
|
|
will be cluttered with stale cached files.
|
|
|
|
If the Asymptote code is dynamically generated, make sure
|
|
that the result is always the same, or use
|
|
@racket[#:cache #f]. Otherwise, each compilation would
|
|
cause a new file to be generated.
|
|
|
|
The @tt{asy} executable must be installed on the
|
|
machine that renders the figures. If the results are
|
|
already cached, then the scribble document can be compiled
|
|
without installing Asymptote.
|
|
|
|
As an example, the code
|
|
|
|
@scribbleblock|{
|
|
@asymptote{
|
|
import drawtree;
|
|
size(4cm, 0);
|
|
TreeNode root = makeNode("let");
|
|
TreeNode bindings = makeNode(root, "bindings");
|
|
TreeNode binding = makeNode(bindings, "binding");
|
|
TreeNode bid = makeNode(binding, "id");
|
|
TreeNode bexpr = makeNode(binding, "expr");
|
|
TreeNode bindingddd = makeNode(bindings, "\vphantom{x}\dots");
|
|
TreeNode body = makeNode(root, "body");
|
|
TreeNode bodyddd = makeNode(root, "\vphantom{x}\dots");
|
|
|
|
draw(root, (0,0));
|
|
shipout(scale(2)*currentpicture.fit());
|
|
}
|
|
}|
|
|
|
|
renders as:
|
|
|
|
@asymptote{
|
|
import drawtree;
|
|
size(4cm, 0);
|
|
TreeNode root = makeNode("let");
|
|
TreeNode bindings = makeNode(root, "bindings");
|
|
TreeNode binding = makeNode(bindings, "binding");
|
|
TreeNode bid = makeNode(binding, "id");
|
|
TreeNode bexpr = makeNode(binding, "expr");
|
|
TreeNode bindingddd = makeNode(bindings, "\vphantom{bg}\dots");
|
|
TreeNode body = makeNode(root, "body");
|
|
TreeNode bodyddd = makeNode(root, "\vphantom{bg}\dots");
|
|
|
|
draw(root, (0,0));
|
|
shipout(scale(2)*currentpicture.fit());
|
|
}
|
|
}
|