text.scrbl (42817B)
1 #lang scribble/doc 2 @(require scribble/manual 3 scribble/core scribble/html-properties scribble/latex-properties 4 (except-in "utils.rkt" splice begin include) 5 (for-label (except-in racket/base begin) 6 scribble/text 7 (only-in scribble/text 8 [begin/text begin] 9 [include/text include]))) 10 @initialize-tests 11 12 @(define (tech/r s) @tech[s #:doc '(lib "scribblings/reference/reference.scrbl")]) 13 @(define scribble-doc '(lib "scribblings/scribble/scribble.scrbl")) 14 @(define @-form @tech[#:doc scribble-doc]{@"@"-forms}) 15 16 @(define-syntax-rule (def-rkt t-id) 17 (begin 18 (require (for-label racket/include)) 19 (define t-id @racket[include]))) 20 @(def-rkt rkt-include) 21 22 @title[#:tag "text" 23 #:style (make-style #f (list (make-tex-addition "shaded.tex") 24 (make-css-addition "shaded.css"))) 25 ]{Text Generation} 26 27 @defmodulelang[scribble/text]{The @racketmodname[scribble/text] 28 language provides everything from @racket[racket/base], 29 @racket[racket/promise], @racket[racket/list], and 30 @racket[racket/string], but with additions and a changed treatment of 31 the module top level to make it suitable as for text generation or a 32 preprocessor language: 33 34 @itemize[ 35 36 @item{The language uses @racket[read-syntax-inside] to read the body 37 of the module, similar to @secref[#:doc scribble-doc "docreader"]. This means that 38 by default, all text is read in as Racket strings; and 39 @seclink[#:doc scribble-doc "reader"]|{@-forms}| can be used to use Racket 40 functions and expression escapes.} 41 42 @item{Values of expressions are printed with a custom @racket[output] 43 function. This function displays most values in a similar way 44 to @racket[display], except that it is more convenient for a 45 textual output.}] 46 47 } 48 49 When @racketmodname[scribble/text] is used via @racket[require] 50 instead of @hash-lang[], then it does not change the printing of 51 values, it does not include the bindings of @racket[racket/base], 52 @racket[include] is provided as @racket[include/text], and 53 @racket[begin] is provided as @racket[begin/text]. 54 55 @; TODO: 56 @; * make all example sections be subsections, 57 @; * add a reference section, 58 @; * a section on "scribble/text.rkt" 59 @; * maybe a section on additional utilities: begin/text 60 61 @;-------------------------------------------------------------------- 62 @section{Writing Text Files} 63 64 The combination of the two features makes text in files in the 65 @racket[scribble/text] language be read as strings, which get printed 66 out when the module is @racket[require]d, for example, when a file is 67 given as an argument to @exec{racket}. (In these example the left 68 part shows the source input, and the right part the printed result.) 69 70 @example|-{#lang scribble/text 71 Programming languages should 72 be designed not by piling 73 feature on top of feature, but 74 blah blah blah. 75 ---***--- 76 Programming languages should 77 be designed not by piling 78 feature on top of feature, but 79 blah blah blah.}-| 80 81 Using @seclink[#:doc scribble-doc "reader"]|{@-forms}|, we can define and use Racket 82 functions. 83 84 @example|-{#lang scribble/text 85 @(require racket/list) 86 @(define Foo "Preprocessing") 87 @(define (3x . x) 88 ;; racket syntax here 89 (add-between (list x x x) " ")) 90 @Foo languages should 91 be designed not by piling 92 feature on top of feature, but 93 @3x{blah}. 94 ---***--- 95 Preprocessing languages should 96 be designed not by piling 97 feature on top of feature, but 98 blah blah blah.}-| 99 100 As demonstrated in this case, the @racket[output] function simply 101 scans nested list structures recursively, which makes them convenient 102 for function results. In addition, @racket[output] prints most values 103 similarly to @racket[display] --- notable exceptions are void and 104 false values which cause no output to appear. This can be used for 105 convenient conditional output. 106 107 @example|-{#lang scribble/text 108 @(define (errors n) 109 (list n 110 " error" 111 (and (not (= n 1)) "s"))) 112 You have @errors[3] in your code, 113 I fixed @errors[1]. 114 ---***--- 115 You have 3 errors in your code, 116 I fixed 1 error.}-| 117 118 Using the scribble @seclink[#:doc scribble-doc "reader"]|{@-forms}| syntax, you can write 119 functions more conveniently too. 120 121 @example|-{#lang scribble/text 122 @(define (errors n) 123 ;; note the use of `unless' 124 @list{@n error@unless[(= n 1)]{s}}) 125 You have @errors[3] in your code, 126 I fixed @errors[1]. 127 ---***--- 128 You have 3 errors in your code, 129 I fixed 1 error.}-| 130 131 Following the details of the scribble reader, you may notice that in 132 these examples there are newline strings after each definition, yet 133 they do not show in the output. To make it easier to write 134 definitions, newlines after definitions and indentation spaces before 135 them are ignored. 136 137 @example|-{#lang scribble/text 138 139 @(define (plural n) 140 (unless (= n 1) "s")) 141 142 @(define (errors n) 143 @list{@n error@plural[n]}) 144 145 You have @errors[3] in your code, 146 @(define fixed 1) 147 I fixed @errors[fixed]. 148 ---***--- 149 You have 3 errors in your code, 150 I fixed 1 error.}-| 151 152 These end-of-line newline strings are not ignored when they follow 153 other kinds of expressions, which may lead to redundant empty lines in 154 the output. 155 156 @example|-{#lang scribble/text 157 @(define (count n str) 158 (for/list ([i (in-range 1 (add1 n))]) 159 @list{@i @str,@"\n"})) 160 Start... 161 @count[3]{Mississippi} 162 ... and I'm done. 163 ---***--- 164 Start... 165 1 Mississippi, 166 2 Mississippi, 167 3 Mississippi, 168 169 ... and I'm done.}-| 170 171 There are several ways to avoid having such empty lines in your 172 output. The simplest way is to arrange for the function call's form 173 to end right before the next line begins, but this is often not too 174 convenient. An alternative is to use a @litchar|{@;}| comment, which 175 makes the scribble reader ignore everything that follows it up to and 176 including the newline. (These methods can be applied to the line that 177 precedes the function call too, but the results are likely to have 178 what looks like erroneous indentation. More about this below.) 179 180 @example|-{#lang scribble/text 181 @(define (count n str) 182 (for/list ([i (in-range 1 (+ n 1))]) 183 @list{@i @str,@"\n"})) 184 Start... 185 @count[3]{Mississippi 186 }... done once. 187 188 Start again... 189 @count[3]{Massachusetts}@; 190 ... and I'm done again. 191 ---***--- 192 Start... 193 1 Mississippi, 194 2 Mississippi, 195 3 Mississippi, 196 ... done once. 197 198 Start again... 199 1 Massachusetts, 200 2 Massachusetts, 201 3 Massachusetts, 202 ... and I'm done again.}-| 203 204 A better approach is to generate newlines only when needed. 205 206 @example|-{#lang scribble/text 207 @(require racket/list) 208 @(define (counts n str) 209 (add-between 210 (for/list ([i (in-range 1 (+ n 1))]) 211 @list{@i @str,}) 212 "\n")) 213 Start... 214 @counts[3]{Mississippi} 215 ... and I'm done. 216 ---***--- 217 Start... 218 1 Mississippi, 219 2 Mississippi, 220 3 Mississippi, 221 ... and I'm done.}-| 222 223 In fact, this is common enough that the @racket[scribble/text] 224 language provides a convenient facility: @racket[add-newlines] is a 225 function that is similar to @racket[add-between] using a newline 226 string as the default separator, except that false and void values are 227 filtered out before doing so. 228 229 @example|-{#lang scribble/text 230 @(define (count n str) 231 (add-newlines 232 (for/list ([i (in-range 1 (+ n 1))]) 233 @list{@i @str,}))) 234 Start... 235 @count[3]{Mississippi} 236 ... and I'm done. 237 ---***--- 238 Start... 239 1 Mississippi, 240 2 Mississippi, 241 3 Mississippi, 242 ... and I'm done.}-| 243 244 @example|-{#lang scribble/text 245 @(define (count n str) 246 (add-newlines 247 (for/list ([i (in-range 1 (+ n 1))]) 248 @(and (even? i) @list{@i @str,})))) 249 Start... 250 @count[6]{Mississippi} 251 ... and I'm done. 252 ---***--- 253 Start... 254 2 Mississippi, 255 4 Mississippi, 256 6 Mississippi, 257 ... and I'm done.}-| 258 259 The separator can be set to any value. 260 261 @example|-{#lang scribble/text 262 @(define (count n str) 263 (add-newlines #:sep ",\n" 264 (for/list ([i (in-range 1 (+ n 1))]) 265 @list{@i @str}))) 266 Start... 267 @count[3]{Mississippi}. 268 ... and I'm done. 269 ---***--- 270 Start... 271 1 Mississippi, 272 2 Mississippi, 273 3 Mississippi. 274 ... and I'm done.}-| 275 276 277 @;-------------------------------------------------------------------- 278 @section{Defining Functions and More} 279 280 (Note: most of the tips in this section are applicable to any code 281 that uses the Scribble @|@-form| syntax.) 282 283 Because the Scribble reader is uniform, you can use it in place of any 284 expression where it is more convenient. (By convention, we use a 285 plain S-expression syntax when we want a Racket expression escape, and 286 an @|@-form| for expressions that render as text, which, in the 287 @racket[scribble/text] language, is any value-producing expression.) 288 For example, you can use an @|@-form| for a function that you define. 289 290 @example|-{#lang scribble/text 291 @(define @bold[text] @list{*@|text|*}) 292 An @bold{important} note. 293 ---***--- 294 An *important* note. 295 }-| 296 297 This is not commonly done, since most functions that operate with text 298 will need to accept a variable number of arguments. In fact, this 299 leads to a common problem: what if we want to write a function that 300 consumes a number of ``text arguments'' rathen than a single 301 ``rest-like'' body? The common solution for this is to provide the 302 separate text arguments in the S-expression part of an @|@-form|. 303 304 @example|-{#lang scribble/text 305 @(define (choose 1st 2nd) 306 @list{Either @1st, or @|2nd|@"."}) 307 @(define who "us") 308 @choose[@list{you're with @who} 309 @list{against @who}] 310 ---***--- 311 Either you're with us, or against us. 312 }-| 313 314 You can even use @|@-form|s with a Racket quote or quasiquote as the 315 ``head'' part to make it shorter, or use a macro to get grouping of 316 sub-parts without dealing with quotes. 317 318 @example|-{#lang scribble/text 319 @(define (choose 1st 2nd) 320 @list{Either @1st, or @|2nd|@"."}) 321 @(define who "us") 322 @choose[@list{you're with @who} 323 @list{against @who}] 324 @(define-syntax-rule (compare (x ...) ...) 325 (add-newlines 326 (list (list "* " x ...) ...))) 327 Shopping list: 328 @compare[@{apples} 329 @{oranges} 330 @{@(* 2 3) bananas}] 331 ---***--- 332 Either you're with us, or against us. 333 Shopping list: 334 * apples 335 * oranges 336 * 6 bananas 337 }-| 338 339 Yet another solution is to look at the text values and split the input 340 arguments based on a specific token. Using @racket[match] can make it 341 convenient --- you can even specify the patterns with @|@-form|s. 342 343 @example|-{#lang scribble/text 344 @(require racket/match) 345 @(define (features . text) 346 (match text 347 [@list{@|1st|@... 348 --- 349 @|2nd|@...} 350 @list{>> Pros << 351 @1st; 352 >> Cons << 353 @|2nd|.}])) 354 @features{fast, 355 reliable 356 --- 357 expensive, 358 ugly} 359 ---***--- 360 >> Pros << 361 fast, 362 reliable; 363 >> Cons << 364 expensive, 365 ugly. 366 }-| 367 368 In particular, it is often convenient to split the input by lines, 369 identified by delimiting @racket["\n"] strings. Since this can be 370 useful, a @racket[split-lines] function is provided. 371 372 @example|-{#lang scribble/text 373 @(require racket/list) 374 @(define (features . text) 375 (add-between (split-lines text) 376 ", ")) 377 @features{red 378 fast 379 reliable}. 380 ---***--- 381 red, fast, reliable. 382 }-| 383 384 Finally, the Scribble reader accepts @emph{any} expression as the head 385 part of an @"@"-form --- even an @"@" form. This makes it possible to 386 get a number of text bodies by defining a curried function, where each 387 step accepts any number of arguments. This, however, means that the 388 number of body expressions must be fixed. 389 390 @example|-{#lang scribble/text 391 @(define ((choose . 1st) . 2nd) 392 @list{Either you're @1st, or @|2nd|.}) 393 @(define who "me") 394 @@choose{with @who}{against @who} 395 ---***--- 396 Either you're with me, or against me. 397 }-| 398 399 400 @;-------------------------------------------------------------------- 401 @section{Using Printouts} 402 403 Because the text language simply displays each toplevel value as the 404 file is run, it is possible to print text directly as part of the 405 output. 406 407 @example|-{#lang scribble/text 408 First 409 @display{Second} 410 Third 411 ---***--- 412 First 413 Second 414 Third}-| 415 416 Taking this further, it is possible to write functions that output 417 some text @emph{instead} of returning values that represent the text. 418 419 @example|-{#lang scribble/text 420 @(define (count n) 421 (for ([i (in-range 1 (+ n 1))]) 422 (printf "~a Mississippi,\n" i))) 423 Start... 424 @count[3]@; avoid an empty line 425 ... and I'm done. 426 ---***--- 427 Start... 428 1 Mississippi, 429 2 Mississippi, 430 3 Mississippi, 431 ... and I'm done.}-| 432 433 This can be used to produce a lot of output text, even infinite. 434 435 @example|-{#lang scribble/text 436 @(define (count n) 437 (printf "~a Mississippi,\n" n) 438 (count (add1 n))) 439 Start... 440 @count[1] 441 this line is never printed! 442 ---***--- 443 Start... 444 1 Mississippi, 445 2 Mississippi, 446 3 Mississippi, 447 4 Mississippi, 448 5 Mississippi, 449 ...}-| 450 451 However, you should be careful not to mix returning values with 452 printouts, as the results are rarely desirable. 453 454 @example|-{#lang scribble/text 455 @list{1 @display{two} 3} 456 ---***--- 457 two1 3}-| 458 459 Note that you don't need side-effects if you want infinite output. 460 The @racket[output] function iterates thunks and (composable) 461 promises, so you can create a loop that is delayed in either form. 462 @; Note: there is some sfs-related problem in racket that makes it not 463 @; run in bounded space, so don't show it for nowx. 464 465 @example|-{#lang scribble/text 466 @(define (count n) 467 (cons @list{@n Mississippi,@"\n"} 468 (lambda () 469 (count (add1 n))))) 470 Start... 471 @count[1] 472 this line is never printed! 473 ---***--- 474 Start... 475 1 Mississippi, 476 2 Mississippi, 477 3 Mississippi, 478 4 Mississippi, 479 5 Mississippi, 480 ...}-| 481 482 483 @;-------------------------------------------------------------------- 484 @section{Indentation in Preprocessed output} 485 486 An issue that can be very important in many text generation applications 487 is the indentation of the output. This can be crucial in some cases, if 488 you're generating code for an indentation-sensitive language (e.g., 489 Haskell, Python, or C preprocessor directives). To get a better 490 understanding of how the pieces interact, you may want to review how the 491 @seclink[#:doc scribble-doc "reader"]|{Scribble reader}| section, but also remember that 492 you can use quoted forms to see how some form is read. 493 494 @example|-{#lang scribble/text 495 @(format "~s" '@list{ 496 a 497 b 498 c}) 499 ---***--- 500 (list "a" "\n" " " "b" "\n" "c")}-| 501 502 The Scribble reader ignores indentation spaces in its body. This is an 503 intentional feature, since you usually do not want an expression to 504 depend on its position in the source. But the question is whether we 505 @emph{can} render some output text with proper indentation. The 506 @racket[output] function achieves that by introducing @racket[block]s. 507 Just like a list, a @racket[block] contains a list of elements, and when 508 one is rendered, it is done in its own indentation level. When a 509 newline is part of a @racket[block]'s contents, it causes the following 510 text to appear with indentation that corresponds to the column position 511 at the beginning of the block. 512 513 In addition, lists are also rendered as blocks by default, so they can 514 be used for the same purpose. In most cases, this makes the output 515 appear ``as intended'' where lists are used for nested pieces of text 516 --- either from a literal @racket[list] expression, or an expression 517 that evaluates to a list, or when a list is passed on as a value; either 518 as a toplevel expression, or as a nested value; either appearing after 519 spaces, or after other output. 520 521 @example|-{#lang scribble/text 522 foo @block{1 523 2 524 3} 525 foo @list{4 526 5 527 6} 528 ---***--- 529 foo 1 530 2 531 3 532 foo 4 533 5 534 6}-| 535 536 @example|-{#lang scribble/text 537 @(define (code . text) 538 @list{begin 539 @text 540 end}) 541 @code{first 542 second 543 @code{ 544 third 545 fourth} 546 last} 547 ---***--- 548 begin 549 first 550 second 551 begin 552 third 553 fourth 554 end 555 last 556 end}-| 557 558 @example|-{#lang scribble/text 559 @(define (enumerate . items) 560 (add-newlines #:sep ";\n" 561 (for/list ([i (in-naturals 1)] 562 [item (in-list items)]) 563 @list{@|i|. @item}))) 564 Todo: @enumerate[@list{Install Racket} 565 @list{Hack, hack, hack} 566 @list{Profit}]. 567 ---***--- 568 Todo: 1. Install Racket; 569 2. Hack, hack, hack; 570 3. Profit.}-| 571 572 @example[#:hidden]|-{ 573 #lang scribble/text 574 @; demonstrates how indentation is preserved inside lists 575 begin 576 a 577 b 578 @list{c 579 d 580 @list{e 581 f 582 g} 583 h 584 i 585 @list{j 586 k 587 l} 588 m 589 n 590 o} 591 p 592 q 593 end 594 ---***--- 595 begin 596 a 597 b 598 c 599 d 600 e 601 f 602 g 603 h 604 i 605 j 606 k 607 l 608 m 609 n 610 o 611 p 612 q 613 end 614 }-| 615 616 @example[#:hidden]|-{ 617 #lang scribble/text 618 619 @list{ 620 a 621 622 b 623 } 624 625 c 626 ---***--- 627 a 628 629 b 630 631 c 632 }-| 633 634 @example[#:hidden]|-{ 635 #lang scribble/text 636 @; indentation works even when coming from a function 637 @(define (((if . c) . t) . e) 638 @list{ 639 if (@c) 640 @t 641 else 642 @e 643 fi}) 644 function foo() { 645 @list{if (1 < 2) 646 something1 647 else 648 @@@if{2<3}{something2}{something3} 649 repeat 3 { 650 @@@if{2<3}{something2}{something3} 651 @@@if{2<3}{ 652 @list{something2.1 653 something2.2} 654 }{ 655 something3 656 } 657 } 658 fi} 659 return 660 } 661 ---***--- 662 function foo() { 663 if (1 < 2) 664 something1 665 else 666 if (2<3) 667 something2 668 else 669 something3 670 fi 671 repeat 3 { 672 if (2<3) 673 something2 674 else 675 something3 676 fi 677 if (2<3) 678 something2.1 679 something2.2 680 else 681 something3 682 fi 683 } 684 fi 685 return 686 } 687 }-| 688 689 @example[#:hidden]|-{ 690 #lang scribble/text 691 @; indentation works with a list, even a single string with a newline 692 @; in a list, but not in a string by itself 693 function foo() { 694 prefix 695 @list{if (1 < 2) 696 something1 697 else 698 @list{something2 699 something3} 700 @'("something4\nsomething5") 701 @"something6\nsomething7" 702 fi} 703 return 704 } 705 @; can be used with a `display', but makes sense only at the top level 706 @; or in thunks (not demonstrated here) 707 @(display 123) foo @list{bar1 708 bar2 709 bar2} 710 ---***--- 711 function foo() { 712 prefix 713 if (1 < 2) 714 something1 715 else 716 something2 717 something3 718 something4 719 something5 720 something6 721 something7 722 fi 723 return 724 } 725 123 foo bar1 726 bar2 727 bar2 728 }-| 729 730 There are, however, cases when you need more refined control over the 731 output. The @racket[scribble/text] language provides a few functions 732 for such cases in addition to @racket[block]. The @racket[splice] 733 function groups together a number of values but avoids introducing a new 734 indentation context. Furthermore, lists are not always rendered as 735 @racket[block]s --- instead, they are rendered as @racket[splice]s when 736 they are used inside one, so you essentially use @racket[splice] to 737 avoid the ``indentation group'' behavior, and @racket[block] to restore 738 it. 739 740 @example|-{#lang scribble/text 741 @(define (blah . text) 742 @splice{{ 743 blah(@block{@text}); 744 }}) 745 start 746 @splice{foo(); 747 loop:} 748 @list{if (something) @blah{one, 749 two}} 750 end 751 ---***--- 752 start 753 foo(); 754 loop: 755 if (something) { 756 blah(one, 757 two); 758 } 759 end 760 }-| 761 762 The @racket[disable-prefix] function disables all indentation 763 printouts in its contents, including the indentation before the body 764 of the @racket[disable-prefix] value itself. It is useful, for 765 example, to print out CPP directives. 766 767 @example|-{#lang scribble/text 768 @(define (((IFFOO . var) . expr1) . expr2) 769 (define (array e1 e2) 770 @list{[@e1, 771 @e2]}) 772 @list{var @var; 773 @disable-prefix{#ifdef FOO} 774 @var = @array[expr1 expr2]; 775 @disable-prefix{#else} 776 @var = @array[expr2 expr1]; 777 @disable-prefix{#endif}}) 778 779 function blah(something, something_else) { 780 @disable-prefix{#include "stuff.inc"} 781 @@@IFFOO{i}{something}{something_else} 782 } 783 ---***--- 784 function blah(something, something_else) { 785 #include "stuff.inc" 786 var i; 787 #ifdef FOO 788 i = [something, 789 something_else]; 790 #else 791 i = [something_else, 792 something]; 793 #endif 794 } 795 }-| 796 797 If there are values after a @racket[disable-prefix] value on the same 798 line, they @emph{will} get indented to the goal column (unless the 799 output is already beyond it). 800 801 @example|-{#lang scribble/text 802 @(define (thunk name . body) 803 @list{function @name() { 804 @body 805 }}) 806 @(define (ifdef cond then else) 807 @list{@disable-prefix{#}ifdef @cond 808 @then 809 @disable-prefix{#}else 810 @else 811 @disable-prefix{#}endif}) 812 813 @thunk['do_stuff]{ 814 init(); 815 @ifdef["HAS_BLAH" 816 @list{var x = blah();} 817 @thunk['blah]{ 818 @ifdef["BLEHOS" 819 @list{@disable-prefix{#}@; 820 include <bleh.h> 821 bleh();} 822 @list{error("no bleh");}] 823 }] 824 more_stuff(); 825 } 826 ---***--- 827 function do_stuff() { 828 init(); 829 # ifdef HAS_BLAH 830 var x = blah(); 831 # else 832 function blah() { 833 # ifdef BLEHOS 834 # include <bleh.h> 835 bleh(); 836 # else 837 error("no bleh"); 838 # endif 839 } 840 # endif 841 more_stuff(); 842 } 843 }-| 844 845 There are cases where each line should be prefixed with some string 846 other than a plain indentation. The @racket[add-prefix] function 847 causes its contents to be printed using some given string prefix for 848 every line. The prefix gets accumulated to an existing indentation, 849 and indentation in the contents gets added to the prefix. 850 851 @example|-{#lang scribble/text 852 @(define (comment . body) 853 @add-prefix["// "]{@body}) 854 @comment{add : int int -> string} 855 char *foo(int x, int y) { 856 @comment{ 857 skeleton: 858 allocate a string 859 print the expression into it 860 @comment{...more work...} 861 } 862 char *buf = malloc(@comment{FIXME! 863 This is bad} 864 100); 865 } 866 ---***--- 867 // add : int int -> string 868 char *foo(int x, int y) { 869 // skeleton: 870 // allocate a string 871 // print the expression into it 872 // // ...more work... 873 char *buf = malloc(// FIXME! 874 // This is bad 875 100); 876 } 877 }-| 878 879 When combining @racket[add-prefix] and @racket[disable-prefix] there 880 is an additional value that can be useful: @racket[flush]. This is a 881 value that causes @racket[output] to print the current indentation and 882 prefix. This makes it possible to get the ``ignored as a prefix'' 883 property of @racket[disable-prefix] but only for a nested prefix. 884 885 @example|-{#lang scribble/text 886 @(define (comment . text) 887 (list flush 888 @add-prefix[" *"]{ 889 @disable-prefix{/*} @text */})) 890 function foo(x) { 891 @comment{blah 892 more blah 893 yet more blah} 894 if (x < 0) { 895 @comment{even more 896 blah here 897 @comment{even 898 nested}} 899 do_stuff(); 900 } 901 } 902 ---***--- 903 function foo(x) { 904 /* blah 905 * more blah 906 * yet more blah */ 907 if (x < 0) { 908 /* even more 909 * blah here 910 * /* even 911 * * nested */ */ 912 do_stuff(); 913 } 914 } 915 }-| 916 917 @example[#:hidden]|-{ 918 #lang scribble/text 919 920 @(begin 921 ;; This is a somewhat contrived example, showing how to use lists 922 ;; and disable-prefix to control the added prefix 923 (define (item . text) 924 ;; notes: the `flush' makes the prefix to that point print so the 925 ;; disable-prefix "* " is printed after it, which overwrites the 926 ;; "| " prefix 927 (list flush (add-prefix "| " (disable-prefix "* ") text))) 928 ;; note that a simple item with spaces is much easier: 929 (define (simple . text) @list{* @text})) 930 931 start 932 @item{blah blah blah 933 blah blah blah 934 @item{more stuff 935 more stuff 936 more stuff} 937 blah blah blah 938 blah blah blah} 939 @simple{more blah 940 blah blah} 941 end 942 ---***--- 943 start 944 * blah blah blah 945 | blah blah blah 946 | * more stuff 947 | | more stuff 948 | | more stuff 949 | blah blah blah 950 | blah blah blah 951 * more blah 952 blah blah 953 end 954 }-| 955 956 957 @;-------------------------------------------------------------------- 958 @section{Using External Files} 959 960 Using additional files that contain code for your preprocessing is 961 trivial: the source text is still source code in a module, so you can 962 @racket[require] additional files with utility functions. 963 964 @example|-{#lang scribble/text 965 @(require "itemize.rkt") 966 Todo: 967 @itemize[@list{Hack some} 968 @list{Sleep some} 969 @list{Hack some 970 more}] 971 ---***--- itemize.rkt 972 #lang racket 973 (provide itemize) 974 (define (itemize . items) 975 (add-between (map (lambda (item) 976 (list "* " item)) 977 items) 978 "\n")) 979 ---***--- 980 Todo: 981 * Hack some 982 * Sleep some 983 * Hack some 984 more 985 }-| 986 987 Note that the @seclink[#:doc scribble-doc "at-exp-lang"]{@racket[at-exp] language} can 988 often be useful here, since such files need to deal with texts. Using 989 it, it is easy to include a lot of textual content. 990 991 @example|-{#lang scribble/text 992 @(require "stuff.rkt") 993 Todo: 994 @itemize[@list{Hack some} 995 @list{Sleep some} 996 @list{Hack some 997 more}] 998 @summary 999 ---***--- stuff.rkt 1000 #lang at-exp racket/base 1001 (require racket/list) 1002 (provide (all-defined-out)) 1003 (define (itemize . items) 1004 (add-between (map (lambda (item) 1005 @list{* @item}) 1006 items) 1007 "\n")) 1008 (define summary 1009 @list{If that's not enough, 1010 I don't know what is.}) 1011 ---***--- 1012 Todo: 1013 * Hack some 1014 * Sleep some 1015 * Hack some 1016 more 1017 If that's not enough, 1018 I don't know what is. 1019 }-| 1020 1021 Of course, the extreme side of this will be to put all of your content 1022 in a plain Racket module, using @|@-form|s for convenience. However, 1023 there is no need to use the text language in this case; instead, you can 1024 @racket[(require scribble/text)], which will get all of the bindings 1025 that are available in the @racket[scribble/text] language. Using 1026 @racket[output], switching from a preprocessed files to a Racket file is 1027 very easy ---- choosing one or the other depends on whether it is more 1028 convenient to write a text file with occasional Racket expressions or 1029 the other way. 1030 1031 @example|-{#lang at-exp racket/base 1032 (require scribble/text racket/list) 1033 (define (itemize . items) 1034 (add-between (map (lambda (item) 1035 @list{* @item}) 1036 items) 1037 "\n")) 1038 (define summary 1039 @list{If that's not enough, 1040 I don't know what is.}) 1041 (output 1042 @list{ 1043 Todo: 1044 @itemize[@list{Hack some} 1045 @list{Sleep some} 1046 @list{Hack some 1047 more}] 1048 @summary 1049 }) 1050 ---***--- 1051 Todo: 1052 * Hack some 1053 * Sleep some 1054 * Hack some 1055 more 1056 If that's not enough, 1057 I don't know what is. 1058 }-| 1059 1060 However, you might run into a case where it is desirable to include a 1061 mostly-text file from a @racket[scribble/text] source file. It might be 1062 because you prefer to split the source text to several files, or because 1063 you need to use a template file that cannot have a @litchar{#lang} 1064 header (for example, an HTML template file that is the result of an 1065 external editor). In these cases, the @racket[scribble/text] language 1066 provides an @racket[include] form that includes a file in the 1067 preprocessor syntax (where the default parsing mode is text). 1068 1069 @example|-{#lang scribble/text 1070 @(require racket/list) 1071 @(define (itemize . items) 1072 (list 1073 "<ul>" 1074 (add-between 1075 (map (lambda (item) 1076 @list{<li>@|item|</li>}) 1077 items) 1078 "\n") 1079 "</ul>")) 1080 @(define title "Todo") 1081 @(define summary 1082 @list{If that's not enough, 1083 I don't know what is.}) 1084 1085 @include["template.html"] 1086 ---***--- template.html 1087 <html> 1088 <head><title>@|title|</title></head> 1089 <body> 1090 <h1>@|title|</h1> 1091 @itemize[@list{Hack some} 1092 @list{Sleep some} 1093 @list{Hack some 1094 more}] 1095 <p><i>@|summary|</i></p> 1096 </body> 1097 </html> 1098 ---***--- 1099 <html> 1100 <head><title>Todo</title></head> 1101 <body> 1102 <h1>Todo</h1> 1103 <ul><li>Hack some</li> 1104 <li>Sleep some</li> 1105 <li>Hack some 1106 more</li></ul> 1107 <p><i>If that's not enough, 1108 I don't know what is.</i></p> 1109 </body> 1110 </html> 1111 }-| 1112 1113 (Using @racket[require] with a text file in the @racket[scribble/text] 1114 language will not work as intended: the language will display the text 1115 is when the module is invoked, so the required file's contents will be 1116 printed before any of the requiring module's text does. If you find 1117 yourself in such a situation, it is better to switch to a 1118 Racket-with-@"@"-expressions file as shown above.) 1119 1120 @;FIXME: add more text on `restore-prefix', `set-prefix', `with-writer' 1121 1122 @;FIXME: add this to the reference section 1123 @;@defform[(include filename)]{ 1124 @; 1125 @;Preprocess the @racket[filename] using the same syntax as 1126 @;@racket[scribble/text]. This is similar to using @racket[load] in a 1127 @;namespace that can access names bound in the current file so included 1128 @;code can refer to bindings from the including module. Note, however, 1129 @;that the including module cannot refer to names that are bound the 1130 @;included file because it is still a plain racket module---for such 1131 @;uses you should still use @racket[require] as usual.} 1132 1133 1134 @; Two random tests 1135 @example[#:hidden]|-{ 1136 #lang scribble/text 1137 1138 @define[name]{Racket} 1139 1140 Suggested price list for "@name" 1141 1142 @; test mutual recursion, throwing away inter-definition spaces 1143 @; <-- this is needed to get only one line of space above 1144 @(define (items-num) 1145 (length items)) 1146 1147 @(define average 1148 (delay (/ (apply + (map car items)) (length items)))) 1149 1150 @(define items 1151 (list @list[99]{Home} 1152 @list[149]{Professional} 1153 @list[349]{Enterprize})) 1154 1155 @(for/list ([i items] [n (in-naturals)]) 1156 @list{@|n|. @name @cadr[i] edition: $@car[i].99 1157 @||})@; <-- also needed 1158 1159 Total: @items-num items 1160 Average price: $@|average|.99 1161 ---***--- 1162 Suggested price list for "Racket" 1163 1164 0. Racket Home edition: $99.99 1165 1. Racket Professional edition: $149.99 1166 2. Racket Enterprize edition: $349.99 1167 1168 Total: 3 items 1169 Average price: $199.99 1170 }-| 1171 @example[#:hidden]|-{ 1172 #lang scribble/text 1173 1174 --*-- 1175 @(define (angled . body) (list "<" body ">")) 1176 @(define (shout . body) @angled[(map string-upcase body)]) 1177 @define[z]{blah} 1178 1179 blah @angled{blah @shout{@z} blah} blah 1180 1181 @(define-syntax-rule @twice[x] 1182 (list x ", " x)) 1183 1184 @twice{@twice{blah}} 1185 1186 @include{inp1} 1187 1188 @(let ([name "Eli"]) (let ([foo (include "inp2")]) (list foo "\n" foo))) 1189 Repeating yourself much? 1190 ---***--- inp1 1191 Warning: blah overdose might be fatal 1192 ---***--- inp2 1193 @(define (foo . xs) (bar xs)) 1194 @(begin (define (isname) @list{is @foo{@name}}) 1195 (define-syntax-rule (DEF x y) (define x y))) 1196 @(DEF (bar x) (list z " " x)) 1197 @(define-syntax-rule (BEG x ...) (begin x ...)) 1198 @(BEG (define z "zee")) 1199 1200 My name @isname 1201 @DEF[x]{Foo!} 1202 1203 ... and to that I say "@x", I think. 1204 1205 ---***--- 1206 --*-- 1207 blah <blah <BLAH> blah> blah 1208 1209 blah, blah, blah, blah 1210 1211 Warning: blah overdose might be fatal 1212 1213 My name is zee Eli 1214 ... and to that I say "Foo!", I think. 1215 My name is zee Eli 1216 ... and to that I say "Foo!", I think. 1217 Repeating yourself much? 1218 }-| 1219 1220 @;-------------------------------------------------------------------- 1221 @section{Text Generation Functions} 1222 1223 @defthing[outputable/c contract?]{ 1224 1225 A contract that (in principle) corresponds to value that can be output 1226 by @racket[output]. Currently, however, this contract accepts all 1227 values (to avoid the cost of checking at every boundary). 1228 1229 @history[#:added "1.1"]} 1230 1231 @defproc[(output [v outputable/c] [port output-port? (current-output-port)]) void?]{ 1232 1233 Outputs values to @racket[port] as follows for each kind of @racket[v]: 1234 1235 @itemlist[ 1236 1237 @item{@tech/r{strings}, @tech/r{byte strings}, @tech/r{symbols}, 1238 @tech/r{paths}, @tech/r{keywords}, @tech/r{numbers}, and 1239 @tech/r{characters}: converts the value to a string along the 1240 same lines as @racket[display], and then passes the string to 1241 the @deftech{current writer}, which is initially 1242 @racket[write-string]} 1243 1244 @item{@|void-const|, @racket[#f], or @racket[null]: no output} 1245 1246 @item{@tech/r{list}: output depends on the current mode, which is 1247 initially @tech{splice mode}: 1248 1249 @itemlist[ 1250 1251 @item{@deftech{block mode}: each item in order, using the 1252 starting column as the @deftech{current 1253 indentation} (which starts out empty)} 1254 1255 @item{@deftech{splice mode}: outputs each item in order} 1256 1257 ]} 1258 1259 @item{@racket[(block _v2 ...)]: outputs each @racket[_v2] in @tech{block mode}.} 1260 1261 @item{@racket[(splice _v2 ...)]: outputs each @racket[_v2] in @tech{splice mode}.} 1262 1263 @item{@racket[(set-prefix _pfx _v2 ...)]: sets the @deftech{current 1264 prefix}, which is initially empty, to @racket[_pfx] while 1265 outputting each @racket[_v2].} 1266 1267 @item{@racket[(add-prefix _pfx _v2 ...)]: sets the @tech{current 1268 prefix} to by adding @racket[_pfx] while outputting each 1269 @racket[_v2].} 1270 1271 @item{@racket[(disable-prefix _v2 ...)]: sets the @tech{current 1272 prefix} to empty while outputting each @racket[_v2].} 1273 1274 @item{@racket[(restore-prefix _v2 ...)]: rewinds the 1275 @tech{current prefix} by one enclosing adjustments while 1276 outputting each @racket[_v2].} 1277 1278 @item{@racket[flush]: outputs the @tech{current indentation} and @tech{current prefix}.} 1279 1280 @item{@racket[(with-writer _writer _v2 ...)]: sets the @tech{current writer} 1281 to @racket[_writer] with outputting each @racket[_v2].} 1282 1283 @item{@tech/r{promise}: outputs the result of @racket[(force v)]} 1284 1285 @item{@tech/r{box}: outputs the result of @racket[(unbox v)]} 1286 1287 @item{procedure of 0 arguments: outputs the result of @racket[(v)]} 1288 1289 ] 1290 1291 Any other kind of @racket[v] triggers an exception.} 1292 1293 1294 @defproc[(block [v outputable/c] ...) outputable/c]{ 1295 1296 Produces a value that outputs each @racket[v] in @tech{block mode}.} 1297 1298 @defproc[(splice [v outputable/c] ...) outputable/c]{ 1299 1300 Produces a value that outputs each @racket[v] in @tech{splice mode}.} 1301 1302 @deftogether[( 1303 @defproc[(disable-prefix [v outputable/c] ...) outputable/c] 1304 @defproc[(restore-prefix [v outputable/c] ...) outputable/c] 1305 @defproc[(add-prefix [pfx (or/c string? exact-nonnegative-integer?)] [v outputable/c] ...) outputable/c] 1306 @defproc[(set-prefix [pfx (or/c string? exact-nonnegative-integer?)] [v outputable/c] ...) outputable/c] 1307 )]{ 1308 1309 Produces a value that outputs with an adjusted @tech{current prefix}. 1310 An integer as a prefix is equivalent to a string with as many space 1311 characters.} 1312 1313 1314 @defthing[flush void?]{ 1315 1316 A value that outputs as the @tech{current indentation} plus @tech{current prefix}.} 1317 1318 1319 @defproc[(with-writer [writer (or/c (->* (string? output-port?) 1320 (exact-nonnegative-integer?) 1321 any/c) 1322 #f)] 1323 [v outputable/c] ...) 1324 outputable/c]{ 1325 1326 Produces a value that outputs with an adjusted @tech{current writer}, 1327 where @racket[#f] indicates @racket[write-string].} 1328 1329 1330 @defproc[(add-newlines [items list?] [#:sep sep an/y "\n"]) list?]{ 1331 1332 Like @racket[add-between], but first removes @racket[#f] and @|void-const| 1333 elements of @racket[items].} 1334 1335 1336 @defproc[(split-lines [items list?]) (listof list?)]{ 1337 1338 Converts @racket[items] to a list of lists, where consecutive 1339 non-@racket["\n"] values are kept together in a nested list, and 1340 @racket["\n"] values are dropped.} 1341 1342 1343 @defform[(include/text maybe-char path-spec) 1344 #:grammar ([maybe-char code:blank 1345 (code:line #:command-char command-char)])]{ 1346 1347 Like @rkt-include from @racketmodname[racket/include], but reads the 1348 file at @racket[path-spec] in the same way as for 1349 @racketmodname[scribble/text]. If @racket[command-char] is supplied, 1350 then it replaces @litchar["@"] as the escape character. 1351 1352 The @racketmodname[scribble/text] language via @hash-lang[] provides 1353 @racket[include/text] as @racket[include].} 1354 1355 @defform[(begin/text form ...)]{ 1356 1357 Like @racket[begin], but the results of expression @racket[forms] are 1358 collected into a list that is returned as the result of the 1359 @racket[begin/list] form. 1360 1361 The @racketmodname[scribble/text] language via @hash-lang[] provides 1362 @racket[begin/text] as @racket[begin].}