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 }