www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

scribble-math.scrbl (15550B)


      1 #lang scribble/manual
      2 @require[@for-label[scribble-math
      3                     racket/base
      4                     scribble/core]
      5          @for-syntax[racket/base
      6                      syntax/parse]
      7          scribble-math]
      8 
      9 
     10 @(define-syntax scribbleblock
     11    (syntax-parser
     12      [(_ (~optional (~seq #:keep-lang-line? keep-lang))
     13          str ...+)
     14       #`(codeblock
     15          #:keep-lang-line? #,(if (attribute keep-lang) #'keep-lang #'#f)
     16          "#lang scribble/base" "\n"
     17          str ...)]))
     18 
     19 @(define-syntax scribblecode
     20    (syntax-parser
     21      [(_ str ...+)
     22       #`(code #:lang "scribble/base"
     23               str ...)]))
     24 
     25 @(use-mathjax)
     26 
     27 @title[#:style (with-html5 manual-doc-style)]{@racketmodname[scribble-math]}
     28 @author[
     29  @author+email["Jens Axel Søgaard" "jensaxel@soegaard.net"]
     30  @author+email["Suzanne Soy" "racket@suzanne.soy"]]
     31 
     32 @defmodule[scribble-math]
     33 
     34 This library allows typesetting math and Asymptote figures
     35 in Scribble documents.
     36 
     37 @(local-table-of-contents #:style 'immediate-only)
     38 
     39 @section{Typesetting math with @racket[$] and @racket[$$]}
     40 @defmodule[scribble-math/dollar]
     41 
     42 @(define title-html5-code
     43    @scribblecode|{@title[#:style (with-html5 manual-doc-style)]{…}}|)
     44 
     45 The following functions help with typesetting mathematical
     46 equations. The main functions are @racket[$] for
     47 @tech{inline mode} math and @racket[$$] for @tech{display
     48  mode} math, respectively. The functions @racket[use-katex]
     49 and @racket[use-mathjax] change the rendering engine used,
     50 the default being @racket[katex]. To use @racket[katex], it
     51 is necessary to use
     52 @title-html5-code or a similar configuration; for more
     53 details see the documentation of @racket[with-html5].
     54 
     55 @defproc[($ [str string?] ...) element?]{
     56  Renders the given strings as @deftech{inline mode} math.
     57  Inline mode math is typeset as part of the surrounding
     58  text. Either MathJax or KaTeX is used for the HTML output,
     59  depending on the current configuration. For the LaTeX
     60  output, the code is simply passed as-is. For example, when
     61  using MathJax, @racket[($ "x^2")] renders as
     62  @(use-mathjax) @${x^2}.
     63 
     64  The syntax accepted by @racket[$] is a subset of the
     65  commands supported by LaTeX, and depends on the backend
     66  used (MathJax should support more commands than KaTeX). For
     67  details, see their respective documentation.}
     68 
     69 @defproc[($$ [str string?] ...) element?]{
     70  Renders the given strings as @deftech{display mode} math. 
     71  Display mode math is typeset alone on its line, and is
     72  centered. Some symbols like @${\sum} are larger in display
     73  mode than in @tech{inline mode}, which makes the former better for
     74  complex equations. Either MathJax or KaTeX is used for the
     75  HTML output, depending on the current configuration. For
     76  the LaTeX output, the code is simply passed as-is. For
     77  example, when using MathJax,
     78  
     79  @racketblock[($$ "\\sum_{i=0}^n x_i^3")]
     80 
     81  renders as:
     82 
     83  @(use-mathjax)
     84  @$${\sum_{i=0}^n x_i^3}
     85 
     86  The syntax accepted by @racket[$$] is a subset of the
     87  commands supported by LaTeX, and depends on the backend
     88  used (MathJax should support more commands than KaTeX). For
     89  details, see their respective documentation.}
     90 
     91 @defproc[(with-html5 [doc-style style?]) style?]{
     92  Alters the given document style, so that the resulting
     93  document uses HTML5.
     94 
     95  This function should be called to alter the 
     96  @racket[#:style] argument for @racket[title] when KaTeX is
     97  used, as KaTeX is incompatible with the default scribble 
     98  @tt{DOCTYPE} (the HTML 4.01 Transitional loose DTD). The
     99  scribble document should therefore contain code similar to
    100  the following:
    101  
    102  @scribbleblock|{
    103   @title[#:style (with-html5 manual-doc-style)]{...}
    104   }|
    105 
    106  This function works by changing the existing 
    107  @racket[html-defaults] property or adding a new one, so
    108  that it uses an HTML5
    109  @tech[#:doc '(lib "scribblings/scribble/scribble.scrbl")]{prefix file}
    110  (the @tech[#:doc '(lib "scribblings/scribble/scribble.scrbl")]{prefix file}
    111  contains the @tt{DOCTYPE} line).}
    112 
    113 @defparam[$-html-handler handler (→ (listof? string?) element?)
    114           #:value $-katex]{
    115  A parameter whose value is a function called by @racket[$],
    116  to transform the math code into HTML. The @racket[$]
    117  function uses this parameter only when rendering the
    118  document as HTML.}
    119 
    120 @defparam[$$-html-handler handler (→ (listof? string?) element?)
    121           #:value $$-katex]{
    122  A parameter whose value is a function called by 
    123  @racket[$$], to transform the math code into HTML. The 
    124  @racket[$$] function uses this parameter only when
    125  rendering the document as HTML. }
    126 
    127 @defproc[($-katex [math (listof? string?)]) element?]{
    128  Produces an @racket[element?] which contains the given 
    129  @racket[math] code, so that it is rendered as @tech{inline
    130   mode} math using KaTeX. More precisely, the resulting
    131  element uses several scribble properties to add scripts and
    132  stylesheets to the document. The resulting element also
    133  uses a specific CSS class so that when the page is loaded
    134  into a browser, KaTeX can recognise it and render it in 
    135  @tech{inline mode}.
    136 
    137  @racket[($-katex "x^2")] renders as @$-katex{x^2}.}
    138 
    139 @defproc[($$-katex [math (listof? string?)]) element?]{
    140  Produces an @racket[element?] which contains the given 
    141  @racket[math] code, so that it is rendered as @tech{display
    142   mode} math (centered, alone on its line) using KaTeX. More
    143  precisely, the resulting element uses several scribble
    144  properties to add scripts and stylesheets to the document.
    145  The resulting element also uses a specific CSS class so
    146  that when the page is loaded into a browser, KaTeX can
    147  recognise it and render it in @tech{display mode}.
    148 
    149  @racketblock[($$-katex "\\sum_{i=0}^n x_i^3")]
    150 
    151  renders as:
    152 
    153  @$$-katex{\sum_{i=0}^n x_i^3}}
    154 
    155 @defproc[($-mathjax [math (listof? string?)]) element?]{
    156  Produces an @racket[element?] which contains the given 
    157  @racket[math] code, so that it is rendered as @tech{inline
    158   mode} math using MathJax. More precisely, the resulting
    159  element uses several scribble properties to add scripts and
    160  stylesheets to the document. The resulting element also
    161  uses a specific CSS class so that when the page is loaded
    162  into a browser, MathJax can recognise it and render it in 
    163  @tech{inline mode}.
    164 
    165  @racket[($-mathjax "x^2")] renders as @$-mathjax{x^2}.}
    166 
    167 @defproc[($$-mathjax [math (listof? string?)]) element?]{
    168  Produces an @racket[element?] which contains the given 
    169  @racket[math] code, so that it is rendered as @tech{display
    170   mode} math (centered, alone on its line) using KaTeX. More
    171  precisely, the resulting element uses several scribble
    172  properties to add scripts and stylesheets to the document.
    173  The resulting element also uses a specific CSS class so
    174  that when the page is loaded into a browser, MathJax can
    175  recognise it and render it in @tech{display mode}.
    176 
    177  @racketblock[($$-mathjax "\\sum_{i=0}^n x_i^3")]
    178 
    179  renders as:
    180 
    181  @$$-mathjax{\sum_{i=0}^n x_i^3}}
    182 
    183 
    184 @defproc[($-tex2svg [math (listof? string?)]) element?]{
    185  Produces an @racket[element?] which contains the given
    186  @racket[math] rendered as an HTML SVG literal.
    187  It is rendered in @tech{inline mode} math using @tt{tex2svg}.
    188  More precisely, the resulting element uses the @racket[xexpr-property] to
    189  render the SVG directly to the HTML document.
    190  This means no new scripts or stylesheets are added to the document.
    191  It also has no style, so its style cannot be customized.
    192 
    193 @; @racket[($-tex2svg "x^2")] renders as @$-tex2svg{x^2}.
    194 
    195  This procedure requires that @code{tex2svg} be installed via
    196  @code{npm install mathjax-node-cli}.
    197 
    198  This procedure requires Racket 6.12 or later.}
    199 
    200 @defproc[($$-tex2svg [math (listof? string?)]) element?]{
    201  Produces an @racket[element?] which contains the given
    202  @racket[math] rendered as an HTML SVG literal.
    203  It is rendered in @tech{display mode} math using @tt{tex2svg}.
    204  More precisely, the resulting element uses the @racket[xexpr-property] to
    205  render the SVG directly to the HTML document.
    206  This means no new scripts or stylesheets are added to the document.
    207  It also has no style, so its style cannot be customized.
    208 
    209 
    210 @; @racketblock[($$-tex2svg "\\sum_{i=0}^n x_i^3")]
    211 
    212 @; renders as:
    213 
    214 @; @$$-tex2svg{\sum_{i=0}^n x_i^3}
    215 
    216  This procedure requires that @code{tex2svg} be installed via
    217  @code{npm install mathjax-node-cli}.
    218 
    219  This procedure requires Racket 6.12 or later.}
    220 
    221 @defproc[(use-katex) void?]{
    222  This shorthand calls @racket[($-html-handler $-katex)]
    223  and @racket[($$-html-handler $$-katex)]. The mathematical
    224  formulas passed to @racket[$] and @racket[$$] which appear
    225  later in the document will therefore be typeset using
    226  KaTeX.
    227 
    228  The KaTeX library will be added to the HTML document only
    229  if it uses the result of one of @racket[$], @racket[$$], 
    230  @racket[$-katex] or @racket[$$-katex]. It is therefore safe
    231  to call this function in libraries to change the default
    232  handler, without the risk of adding extra resources to the
    233  page if the user changes the default before typesetting any
    234  math.}
    235 
    236 @defproc[(use-mathjax) void?]{
    237  This shorthand calls @racket[($-html-handler $-mathjax)]
    238  and @racket[($$-html-handler $$-mathjax)]. The mathematical
    239  formulas passed to @racket[$] and @racket[$$] which appear
    240  later in the document will therefore be typeset using
    241  MathJax.
    242 
    243  The MathJax library will be added to the HTML document only
    244  if i uses the result of one of @racket[$], @racket[$$], 
    245  @racket[$-katex] or @racket[$$-katex]. It is therefore safe
    246  to call this function in libraries to change the default
    247  handler, without the risk of adding extra resources to the
    248  page if the user changes the default before typesetting any
    249  math.}
    250 
    251 @defproc[(use-tex2svg) void?]{
    252  This shorthand calls @racket[($-html-handler $-tex2svg)] and
    253  @racket[($$-html-handler $$-tex2svg)]. The mathematical formulas passed to
    254  @racket[$] and @racket[$$] which appear later in the document will therefore be
    255  typeset using @tt{tex2svg}.
    256 
    257  No new CSS or JavaScript libraries will be added to the document. Instead, the
    258  generated HTML document have the math embedded directly an @tt{svg}.
    259 
    260  This requires that @tt{tex2svg} is installed on the system. You can install it
    261  globally via @tt{sudo npm install --global mathjax-node-cli} or locally with
    262  @tt{npm install mathjax-node-cli}. The backend will attempt to find the
    263  @tt{tex2svg}, preferring local sources. You can set the path manually with
    264  the parameter @racket[current-tex2svg-path].
    265 
    266  @tt{tex2svg} will only be used when rendering an HTML document, and only if it
    267  uses @racket[$] or @racket[$$] to render math. It is therefore safe to call
    268  this function in libraries to change the default handler.
    269 
    270  This procedure requires Racket 6.12 or later.}
    271 
    272 @defparam[current-tex2svg-path path path? #:value #f]{
    273  A parameter whose value is the path to the @tt{tex2svg} binary.
    274  This binary is used to transform math code into HTML when using the @tt{tex2svg}
    275  backend.
    276  
    277  The functions @racket[$-tex2svg] and @racket[$$-tex2svg] use this parameter only
    278  when rendering the document as HTML.
    279 
    280  This parameter requires Racket 6.12 or later.}
    281 
    282 @defparam[use-external-mathjax URL (or/c #f string?) #:value #f]{
    283                                                        
    284  A parameter whose value is the URL to the MathJax script
    285  to use. The URL must be absolute, or relative to the URL
    286  used to display the document.
    287 
    288  For example, if the HTML document is accessed via @tt{
    289   file:///home/user/docs/document1/index.html}, and
    290  @racket[(use-external-mathjax "../common/MathJax/MathJax.js?config=default")] was
    291  used, then MathJax will be loaded from @tt{
    292   file:///home/user/docs/common/MathJax/MathJax.js?config=default}.
    293 
    294  An URL to a CDN is also valid, but may be a poor choice
    295  regarding the privacy of your users.
    296 
    297  This feature is in beta and might not work, please report
    298  any issue.}
    299 
    300 @defparam[use-external-katex URLs (or/c #f (list/c string? string?)) #:value #f]{
    301                                                        
    302  A parameter whose value is a list containing the URL to the
    303  KaTeX script and the URL to KaTeX CSS to use. The URLs must
    304  be absolute, or relative to the URL used to display the
    305  document.
    306 
    307  For example, if the HTML document is accessed via @tt{
    308   file:///home/user/docs/document1/index.html}, and
    309  @racket[(use-external-katex (list "../common/KaTeX/katex.min.js" "../common/KaTeX/katex.min.css"))]
    310  was used, then the KaTeX script will be loaded from @tt{
    311   file:///home/user/docs/common/KaTeX/katex.min.js} and the
    312  KaTeX stylesheet from @tt{
    313   file:///home/user/docs/common/KaTeX/katex.min.css}.
    314 
    315  An URL to a CDN is also valid, but may be a poor choice
    316  regarding the privacy of your users.
    317 
    318  Please note that using a .js and a .css file which are not
    319  in the same directory is unsupported (it has not been tested
    320  and may or may not work).
    321 
    322  This feature is in beta and might not work, please report
    323  any issue.}
    324 
    325 @;@$${\sum_{i=0}ⁿ xᵢ³}
    326 
    327 When using MathJax, @racket[$] and @racket[$$] wrap their
    328 content with @racket["$…$"] and @racket["\\[…\\]"]
    329 respectively, and insert it in an element with the class 
    330 @racket["tex2jax_process"]. MathJax is configured to only
    331 process elements with this class, so it is safe to use
    332 @tt{$} signs in the source document. For example, the text
    333 $\sum x^3$ is typeset as-is, like the rest of the text.
    334 
    335 When using @tt{tex2svg}, no additional JavaScript processing is done on the
    336 page, so it is safe to use @tt{$} signs in the source document. For example, the
    337 text $\sum x^3$ is typeset as-is, like the rest of the text.
    338 
    339 @section{Drawing figures with Asymptote}
    340 
    341 @defmodule[scribble-math/asymptote]
    342 
    343 @defproc[(asymptote [#:cache cache? any/c #t] [str string?] ...+) image?]{
    344  Renders the figure described by the given strings using
    345  Asymptote. If @racket[cache?] is @racket[#f], then the
    346  resulting images are generated into temporary PNG, SVG and
    347  PDF files using @racket[make-temporary-file]. Otherwise, to
    348  improve compilation speed, the result is cached in the 
    349  @filepath{asymptote-images} directory, based on a checksum
    350  of the strings. It is a good idea to clean up the working
    351  directory after experimenting a lot with a figure, as it
    352  will be cluttered with stale cached files.
    353 
    354  If the Asymptote code is dynamically generated, make sure
    355  that the result is always the same, or use 
    356  @racket[#:cache #f]. Otherwise, each compilation would
    357  cause a new file to be generated.
    358 
    359  The @tt{asy} executable must be installed on the
    360  machine that renders the figures. If the results are
    361  already cached, then the scribble document can be compiled
    362  without installing Asymptote.
    363 
    364  As an example, the code
    365  
    366  @scribbleblock|{
    367   @asymptote{
    368    import drawtree;
    369    size(4cm, 0);
    370    TreeNode root = makeNode("let");
    371    TreeNode bindings = makeNode(root, "bindings");
    372    TreeNode binding = makeNode(bindings, "binding");
    373    TreeNode bid = makeNode(binding, "id");
    374    TreeNode bexpr = makeNode(binding, "expr");
    375    TreeNode bindingddd = makeNode(bindings, "\vphantom{x}\dots");
    376    TreeNode body = makeNode(root, "body");
    377    TreeNode bodyddd = makeNode(root, "\vphantom{x}\dots");
    378 
    379    draw(root, (0,0));
    380    shipout(scale(2)*currentpicture.fit());
    381   }
    382  }|
    383  
    384  renders as:
    385  
    386  @asymptote{
    387   import drawtree;
    388   size(4cm, 0);
    389   TreeNode root = makeNode("let");
    390   TreeNode bindings = makeNode(root, "bindings");
    391   TreeNode binding = makeNode(bindings, "binding");
    392   TreeNode bid = makeNode(binding, "id");
    393   TreeNode bexpr = makeNode(binding, "expr");
    394   TreeNode bindingddd = makeNode(bindings, "\vphantom{bg}\dots");
    395   TreeNode body = makeNode(root, "body");
    396   TreeNode bodyddd = makeNode(root, "\vphantom{bg}\dots");
    397 
    398   draw(root, (0,0));
    399   shipout(scale(2)*currentpicture.fit());
    400  }
    401 }