bkyk8rc3zvpnsf5inmcqq4n3k98cv6hj-my-site-hyper-literate-git.test.suzanne.soy-0.0.1

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

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].}