commit 04836721c3b8a44a0cecdd02528ea7e22fe0c4b0
parent edb25384b7f07514d4d644ccc523e01e57abb893
Author: Eli Barzilay <eli@racket-lang.org>
Date: Sat, 7 Jul 2007 06:27:23 +0000
much revised code, matching doc.txt and tests
svn: r6830
original commit: 11feb6010e5a5ef159d767292f8f2851c0308729
Diffstat:
1 file changed, 444 insertions(+), 249 deletions(-)
diff --git a/collects/scribble/doc.txt b/collects/scribble/doc.txt
@@ -1,32 +1,4 @@
-The _Scribble_ Collection
-=========================
-
-The Scribble collection contains a few libraries that can be used to
-create documents from Scheme. It is made of independently usable
-parts. For example, the reader can be used in any situation that
-requires lots of free-form text, or you can use the rendering portion
-directly to generate documents.
-
-
-Running Scribble
-----------------
-
-To process a Scribble document, use the `scribble' command-line utility
-(use `scribble -h' to see usage information). This is implemented by
-the "run-scribble.ss" module, which can be used directly:
-
-> (render-file input output format)
-
-Renders the given `input' file to the `output' file using the given
-format specification. The input and output files are used as is (no
-suffixes are added). The `output' argument can be #f, which will render
-the input to the current output port. `format' is a symbol that
-specifies the kind of output rendering (use the `scribble' commad to
-find the list of available formatters).
-
-A Scribble document is a MzScheme module file, which provides a
-`content' binding.
-
+(The rest of the Scribble documentation is now a separate manual.)
The Scribble Reader
-------------------
@@ -71,12 +43,16 @@ Informally, the concrete syntax of @-forms is:
where all three parts after "@" are optional, but at least one should
be present. (Note that spaces are not allowed between the three
-parts.) @litchar["@"] is set as a non-terminating reader macro, so it
-can be used as usual in Scheme identifiers unless you want to use it
-as a first character of an identifier; in this case you need to quote
-with a backslash (`\@foo@') or quote the whole identifier with bars
-(`|@foo|'). Of course, "@" is not treated specially in Scheme
-strings, character constants, etc.
+parts.) "@" is set as a non-terminating reader macro, so it can be
+used as usual in Scheme identifiers unless you want to use it as a
+first character of an identifier; in this case you need to quote with
+a backslash (`\@foo@') or quote the whole identifier with bars
+(`|@foo|').
+
+ (define |@foo| '\@bar@baz)
+
+Of course, "@" is not treated specially in Scheme strings, character
+constants, etc.
Roughly, a form matching the above grammar is read as
@@ -87,322 +63,541 @@ input. Thus, the initial <cmd> determines the Scheme code that the
input is translated into. The common case is when <cmd> is a Scheme
identifier, which generates a plain Scheme form.
-A <text-body> is made of character sequences, newlines, and nested
-@-forms. Note that the syntax for @-forms is the same in a
-<text-body> context as in a Scheme context. A <text-body> that isn't
-an @-form is converted to a string expression for its <parsed-body>,
-and newlines are converted to "\n" expressions:
+A <text-body> is made of text, newlines, and nested @-forms. Note
+that the syntax for @-forms is the same in a <text-body> context as in
+a Scheme context. A <text-body> that isn't an @-form is converted to
+a string expression for its <parsed-body>, and newlines are converted
+to "\n" expressions:
@foo{bar baz
blah}
- --is-read-as-->
+ --reads-as-->
(foo "bar baz" "\n" "blah")
@foo{bar @baz[3]
blah}
- --is-read-as-->
- (foo (baz 3) "\n" "blah")
+ --reads-as-->
+ (foo "bar " (baz 3) "\n" "blah")
@foo{bar @baz{3}
blah}
- --is-read-as-->
+ --reads-as-->
(foo "bar " (baz "3") "\n" "blah")
@foo{bar @baz[2 3]{4 5}
blah}
- --is-read-as-->
+ --reads-as-->
(foo "bar " (baz 2 3 "4 5") "\n" "blah")
+Note that spaces are not allowed before a "[" or a "{", or they will
+be part of the following text (or Scheme code). (More on using braces
+in body texts below.)
+
+ @foo{bar @baz[2 3] {4 5}}
+ --reads-as-->
+ (foo "bar " (baz 2 3) " {4 5}")
+
When the above @-forms appear in a Scheme expression context, the
-context must provide bindings for `foo' (as a procedure or macro). To
-just see the read result for an @-form, you can always a Scheme
-`quote':
+lexical environment must provide bindings for `foo' (as a procedure or
+a macro).
- '@foo{bar}
+ (let* ([formatter (lambda (fmt)
+ (lambda args (format fmt (apply string-append args))))]
+ [bf (formatter "*~a*")]
+ [it (formatter "/~a/")]
+ [ul (formatter "_~a_")]
+ [text string-append])
+ @text{@it{Note}: @bf{This is @ul{not} a pipe}.})
+ --> "/Note/: *This is _not_ a pipe*."
-** Concrete Syntax: The Command Part
+If you want to see the expression that is actually being read, you can
+use Scheme's `quote'.
-Besides being a Scheme identifier, the <cmd> part of an @-form can be
-any Scheme expression. The expression can have Scheme punctuation
-prefixes, which will end up wrapping the *whole* expression.
+ '@foo{bar}
- @`',@foo{blah}
+** Concrete Syntax: The Command Part
- --is-read-as-->
+Besides being a Scheme identifier, the <cmd> part of an @-form can
+have Scheme punctuation prefixes, which will end up wrapping the
+*whole* expression.
- `',@(foo "blah")
+ @`',@foo{blah} --reads-as--> `',@(foo "blah")
When writing Scheme code, this means that @`',@foo{blah} is exactly
the same as `@',@foo{blah} and `',@@foo{blah}, but unlike the latter
two, the first construct can appear in body texts with the same
meaning, whereas the other two would not work (see below).
-As mentioned above, the command itself is not limited to a Scheme
-identifier; it can be any Scheme expression.
-
- @(lambda (x) x){blah}
-
- --is-read-as-->
-
- ((lambda (x) x) "blah")
-
-
-
-
+After the optional punctuation prefix, the <cmd> itself is not limited
+to identifiers -- it can be *any* Scheme expression.
+ @(lambda (x) x){blah} --reads-as--> ((lambda (x) x) "blah")
+ @`(unquote foo){blah} --reads-as--> `(,foo "blah")
In addition, the command can be omitted altogether, which will omit it
-from the translation, resulting in an s-expression that usually contains
-just strings:
+from the translation, resulting in an S-expression that usually
+contains, say, just strings:
- @{foo bar --is-read-as--> ("foo bar" "\n" "baz")
+ @{foo bar --reads-as--> ("foo bar" "\n" "baz")
baz}
- @'{foo bar --is-read-as--> '("foo bar" "\n" "baz")
+ @'{foo bar --reads-as--> '("foo bar" "\n" "baz")
baz}
If the command part begins with a ";" (with no newline between the "@"
and the ";"), then the construct is a comment. There are two comment
-forms, one for arbitrary-text and possibly nested comments, and another
-one for a -to-the-end-of-the-line comment:
+forms, one for arbitrary-text and possibly nested comments, and
+another one for a line comments:
- @;{ ...any-text-including-tested-scribble-pieces... }
+ @;{<anything> ...}
- @; <anything-that-doesn't-begin-with-a-brace-to-the-end-of-the-line>
+ @;<anything-else-without-newline>
-Note that the first form is analogous to a "#;" comment: the commented
-body must still parse correctly. Also note that in the second form all
-text from the "@;" to the end of the line and all following
-(non-newline) whitespaces are part of the comment (as with TeX `%'
-comments). For example:
+In the first form, the commented body must still parse correctly; see
+the description of the body syntax below. In the second form, all
+text from the "@;" to the end of the line *and* all following spaces
+(or tabs) are part of the comment (similar to "%" comments in TeX).
- @foo{bar @; comment --is-read-as--> (foo "bar baz")
+ @foo{bar @; comment --reads-as--> (foo "bar baz")
baz}
-Tip: if you're editing in a Scheme-aware editor, it is useful to comment
-out blocks like this:
-
- @;
- {
- ...
- }
-
-or
+Tip: if you're editing in a Scheme-aware editor (like DrScheme or
+Emacs), it is useful to comment out blocks like this:
@;{
...
;}
-otherwise you will probably confuse the editor into treating the file as
-having imbalanced parenthesis.
+so the editor does not treat the file as having unbalanced
+parenthesis.
-If only the command part is specified, then the result is the command
-part only, without an extra set of parenthesis. This makes it suitable
-for Scheme escapes in body texts. More below, in the description of the
-body part.
+If only the <cmd> part of an @-form is specified, then the result is
+the command part only, without an extra set of parenthesis. This
+makes it suitable for Scheme escapes in body texts. (More on this
+below, in the description of the body part.)
-Finally, note that there are no special rules for using "@" in the
-command itself, which can lead to things like:
+ @foo{x @y z} --reads-as--> (foo "x " y " z")
+ @foo{x @(* y 2) z} --reads-as--> (foo "x " (* y 2) " z")
+ @{@foo bar} --reads-as--> (foo " bar")
- @@foo{bar}{baz} --is-read-as--> ((foo "bar") "baz")
+Finally, note that there are currently no special rules for using "@"
+in the command itself, which can lead to things like:
-To use "@" as in plain Scheme code, you need to quote it as you would
-quote other characters, for example:
+ @@foo{bar}{baz} --reads-as--> ((foo "bar") "baz")
- (define |@foo| '\@bar)
+** Concrete Syntax: The Datum Part
-** Concrete Syntax: the body part
+The datum part can contains arbitrary Scheme expressions, which are
+simply stacked before the body text arguments:
-The syntax of the body part is intended to be as convenient as possible
-for writing free text. It can contain almost any text -- the only
-character with special meaning is "@", in addition, braces, "|", and
-backslash can have special meanings but only in a few contexts. As
-described above, the text turns to a sequence of string arguments for
-the resulting form. Spaces at the beginning of lines are discarded (but
-see the information about indentation below), and newlines turn to
-individual "\n" strings. (Spaces are preserved on a single-line text.)
-As part of trying to do the `right thing', an empty line at the
-beginning and at the end are discarded, so
+ @foo[1 (* 2 3)]{bar} --reads-as--> (foo 1 (* 2 3) "bar")
+ @foo[@bar{...}]{blah} --reads-as--> (foo (bar "...") "blah")
- @foo{
- bar --is-read-as--> (foo "bar") <--is-read-as-- @foo{bar}
- }
+The body part can still be omitted, which is essentially an
+alternative syntax for plain (non-textual) S-expressions:
- @foo{ bar } --is-read-as--> (foo " bar ")
+ @foo[bar] --reads-as--> (foo bar)
+ @foo{bar @f[x] baz} --reads-as--> (foo "bar " (f x) " baz")
-If an "@" appears in the input, then it is interpreted as Scheme code,
-which means that the at-reader will be applied recursively, and the
-resulting syntax will appear as an argument, among other string
-contents. For example:
+The datum part can be empty, which makes no difference, except when
+the body is omitted. It is more common, however, to use an empty body
+for the same purpose.
- @foo{a @bar{b} c} --is-read-as--> (foo "a " (bar "b") " c")
+ @foo[]{bar} --reads-as--> (foo "bar")
+ @foo[] --reads-as--> (foo)
+ @foo --reads-as--> foo
+ @foo{} --reads-as--> (foo)
-If the nested "@" construct has only a command -- no body part, then it
-does not appear in a subform. Given that the command part can be any
-Scheme expression, this makes "@" a general escape to arbitrary Scheme
-code:
+The most common use of the datum part is for Scheme forms that expect
+keyword-value arguments that precede the body of text arguments.
- @foo{a @bar c} --is-read-as--> (foo "a " bar " c")
+ @foo[#:style 'big]{bar} --reads-as--> (foo #:style 'big "bar")
- @foo{a @(bar 2) c} --is-read-as--> (foo "a " (bar 2) " c")
+** Concrete Syntax: The Body Part
-In some cases, you may want to use a Scheme identifier (or a number or a
-boolean) in a position that touches other text that can make an
-identifier -- in these situations you should surround the Scheme
-identifier (/number/boolean) by a pair of bar characters. The text
-inside the bars is parsed as a Scheme expression, but if that fails, it
-is used as a quoted identifier -- do not rely on this behavior, and
-avoid using whitespace inside the bars. Also, if bars are used, then no
-body text is used even if they are followed by braces (see the next
-paragraph). Examples:
+The syntax of the body part is intended to be as convenient as
+possible for free text. It can contain almost any text -- the only
+characters with special meaning is "@" for sub forms, and "}" for the
+end of the text. In addition, a "{" is allowed as part of the text,
+and it makes the matching "}" be part of the text too -- so balanced
+braces are valid text.
- @foo{foo @bar foo} --is-read-as--> (foo "foo " bar " foo")
+ @foo{f{o}o} --reads-as--> (foo "f{o}o")
+ @foo{{{}}{}} --reads-as--> (foo "{{}}{}")
- @foo{foo@bar.} --is-read-as--> (foo "foo" bar.)
+As described above, the text turns to a sequence of string arguments
+for the resulting form. Spaces at the beginning and end of lines are
+discarded, and newlines turn to individual "\n" strings (i.e., they
+are not merged with other body parts). (See also the information
+about newlines and indentation below.) Spaces are *not* discarded if
+they appear after the open "{" (before the closing "}") when there is
+also text that follows (precedes) it; specifically, they are preserved
+in a single-line body.
- @foo{foo@|bar|.} --is-read-as--> (foo "foo" bar ".")
+ @foo{bar} --reads-as--> (foo "bar")
+ @foo{ bar } --reads-as--> (foo " bar ")
+ @foo[1]{ bar } --reads-as--> (foo 1 " bar ")
- @foo{foo@3.} --is-read-as--> (foo "foo" 3.0)
+If "@" appears in a body, then it is interpreted as Scheme code, which
+means that the @-reader is applied recursively, and the resulting
+syntax appears as part of the S-expression, among other string
+contents.
- @foo{foo@|3|.} --is-read-as--> (foo "foo" 3 ".")
+ @foo{a @bar{b} c} --reads-as--> (foo "a " (bar "b") " c")
- @foo{foo@|(f 1)|{bar}.} --is-read-as--> (foo "foo" (f 1) "{bar}.")
+If the nested "@" construct has only a command -- no body or datum
+parts -- it will not appear in a subform. Given that the command part
+can be any Scheme expression, this makes "@" a general escape to
+arbitrary Scheme code.
-Braces are only problematic because a "}" is used to mark the end of the
-text. They are therefore allowed, as long as they are balanced. For
-example:
+ @foo{a @bar c} --reads-as--> (foo "a " bar " c")
+ @foo{a @(bar 2) c} --reads-as--> (foo "a " (bar 2) " c")
- @foo{f{o}o} --is-read-as--> (foo "f{o}o")
+This is particularly useful with strings, which can be used to include
+arbitrary text.
-There is also an alternative syntax for the body, one that specifies a
-new marker for the end. To do this, use "|{" for the openning marker,
-optionally with additional characters between them (excluding "{",
-whitespace, and alphanumerics) -- the matching closing marker should be
-the mirrored form of the openning marker (reverse the characters and
-swap round, square, curly, and angle parentheses). For example:
+ @foo{This @"}" is a closing brace}
+ --reads-as-->
+ (foo "This } is a closing brace")
- @foo|{...}| --is-read-as--> (foo "...")
+Note that the escaped string is (intentionally) merged with the rest
+of the text. This works for "@" too:
- @foo|{foo{{{bar}| --is-read-as--> (foo "foo{{{bar")
+ @foo{The command prefix is @"@".}
+ --reads-as-->
+ (foo "The command prefix is @.")
- @foo|<{{foo{{{bar}}>| --is-read-as--> (foo "{foo{{{bar}")
+ @foo{@"@foo{bar}" reads as (foo "bar")}
+ --reads-as-->
+ (foo "@foo{bar} reads as (foo \"bar\")")
-* Concrete Syntax: quoting in body texts
+* Concrete Syntax: Alternative Body Syntax
-To quote braces or "@", precede them with a backslash. Note that this
-is an irregular use of backslash quoting! To use "\@" in your text,
-simply precede it with a backslash. The general rule is that to use N
-backslashes-and-a-special-character, you should precede it with one
-extra backslash. Any other use of a backslash (one that is not followed
-by more back-slashes and a special character) is preserved in the text
-as usual. Examples:
+In addition, there is an alternative syntax for the body, one that
+specifies a new marker for its end: use "|{" for the opening marker to
+have the text terminated by a "}|".
- @foo{b\@ar} --is-read-as--> (foo "b@ar")
- @foo{b\\@ar} --is-read-as--> (foo "b\\@ar")
- @foo{b\\\@ar} --is-read-as--> (foo "b\\\\@ar")
- @foo{b\{\@\@ar} --is-read-as--> (foo "b{@@ar")
- @foo{b\ar} --is-read-as--> (foo "b\\ar")
- @foo{b\\ar} --is-read-as--> (foo "b\\\\ar")
+ @foo|{...}|
+ --reads-as-->
+ (foo "...")
-* Concrete Syntax: newlines and indentation
+ @foo|{close with "}", open with "{"}|
+ --reads-as-->
+ (foo "close with \"}\", open with \"{\"")
-When indentation is used, all-space indentation string syntaxes are
-perpended to the beginning of each line. The rule for adding these
-string is:
-- A spaces-string is added to each line according to its distance from
- the leftmost syntax object;
-- The first string is not prepended with indentation if it appears on
- the first line of output.
-Examples:
+ @foo|{Nesting |{is}| ok}|
+ --reads-as-->
+ (foo "Nesting |{is}| ok")
- @foo{ --is-read-as--> (foo "bar" "\n"
- bar " " "baz" "\n"
- baz "bbb")
- bbb}
+This applies to sub-@-forms too -- the "@" must be prefixed with a
+"|":
- @foo{bar --is-read-as--> (foo "bar" "\n"
- baz " " "baz" "\n"
- bbb} "bbb")
+ @foo|{Maze
+ |@bar{is}
+ Life!}|
+ --reads-as-->
+ (foo "Maze" "\n" (bar "is") "Life!")
- @foo{ bar --is-read-as--> (foo " bar" "\n"
- baz " " "baz" "\n"
- bbb} " " "bbb")
+ @foo|{Works for |@bar|{subforms}| too}|
+ --reads-as-->
+ (foo "Works for " (bar "subforms") " too")
- @foo{bar --is-read-as--> (foo "bar" "\n"
- baz "baz" "\n"
- bbb} "bbb")
+Note that the subform uses its own delimiters, "{...}" or "|{...}|".
+This means that you can copy and paste Scribble text with @-forms
+freely, just prefix the "@" if the immediate surrounding text has a
+prefix.
- @foo{ bar --is-read-as--> (foo " bar" "\n"
- baz "baz" "\n"
- bbb} "bbb")
+For even better control, you can add characters in the opening
+delimiter, between the "|" and the "{". Characters that are put there
+(non alphanumeric ASCII characters only, excluding "{" and "@") should
+also be used for sub-@-forms, and the end-of-body marker should have
+these characters in reverse order with paren-like characters ("(",
+"[", "<") mirrored.
- @foo{ bar --is-read-as--> (foo " bar" "\n"
- baz "baz" "\n"
- bbb} " " "bbb")
+ @foo|<<<{Some @x{more} |@{text}|.}>>>|
+ --reads-as-->
+ (foo "Some @x{more} |@{text}|.")
-Additional notes:
-- You can identify indentation strings at the syntax level by the fact
- that they have the same location information as the following syntax
- object;
-- This mechanism depends on line and column number information
- (`use-at-readtable' turns them on for the current input port);
-- To use this mechanism with nested commands that should preserve
- indentation, you will need to do some additional work since the nested
- use will have only its own indentation;
-- When using it on a command-line, you note that the reader is not aware
- of the "> " prompt, which might lead to confusing results.
+ @foo|!!{Blah |!!@bold{blah}...}!!|
+ --reads-as-->
+ (foo "Blah " (bold "blah") "...")
-[The following is likely to change.]
+Finally, remember that you can use an expression escape with a Scheme
+string for confusing situations. This works well when you only need
+to quote short pieces, and the above works well when you have larger
+multi-line body texts.
-For situations where spaces at the beginning of lines matter (various
-verbatim environments), you should begin a line with a "|". It has no
-other special meaning -- so to use a "|" as the first character in the
-text, simply use another before it.
+* Concrete Syntax: Scheme Expression Escapes
- @code{
- |(define (foo x) --is-read-as--> (code "(define (foo x)" "\n"
- | |error|) " |error|)")
+In some cases, you may want to use a Scheme identifier (or a number or
+a boolean etc.) in a position that touches the following text; in
+these situations you should surround the escaped Scheme expression by
+a pair of "|" characters. The text inside the bars is parsed as a
+Scheme expression.
+
+ @foo{foo@bar.} --reads-as--> (foo "foo" bar.)
+ @foo{foo@|bar|.} --reads-as--> (foo "foo" bar ".")
+ @foo{foo@3.} --reads-as--> (foo "foo" 3.0)
+ @foo{foo@|3|.} --reads-as--> (foo "foo" 3 ".")
+
+This form is a generic Scheme expression escape, there is no body text
+or datum part when you use this form.
+
+ @foo{foo@|(f 1)|{bar}} --reads-as--> (foo "foo" (f 1) "{bar}")
+ @foo{foo@|bar|[1]{baz}} --reads-as--> (foo "foo" bar "[1]{baz}")
+
+This works for string expressions too, but not that unlike the above,
+the string is (intentionally) not merged with the rest of the text:
+
+ @foo{x@"y"z} --reads-as--> (foo "xyz")
+ @foo{x@|"y"|z} --reads-as--> (foo "x" "y" "z")
+
+Expression escapes also work with *any* number of expressions,
+
+ @foo{x@|1 (+ 2 3) 4|y} --reads-as--> (foo "x" 1 (+ 2 3) 4 "y")
+
+ @foo{x@|* --reads-as--> (foo "x" * * "y")
+ *|y}
+
+It seems that "@||" has no purpose -- but remember that these escapes
+are never merged with the surrounding text, which can be useful when
+you want to control the sub expressions in the form.
+
+ @foo{Alice@||Bob@| --reads-as--> (foo "Alice" "Bob" "Carol")
+ |Carol}
+
+Note that "@|{...}|" can be parsed as either an escape expression or
+as a no-command @-form. The latter is used in this case (since there
+is little point in Scheme code that uses braces.
+
+ @|{blah}| --is-read-as--> ("blah")
+
+* Concrete Syntax: Comments
+
+As noted above, there are two kinds of Scribble comments: "@;{...}" is
+a (nestable) comment for a whole body of text (following the same
+rules for @-forms), and "@;..." is a line-comment.
+
+ @foo{First line@;{there is still a
+ newline at this point;}
+ Second line}
+ --reads-as-->
+ (foo "First line" "\n" "Second line")
+
+One useful property of line-comments is that they continue to the end
+of the line *and* all following spaces (or tabs). Using this, you can
+get further control of the subforms.
+
+ @foo{This is @;
+ a pretty long @;
+ single string-@;
+ argument.}
+ --reads-as-->
+ (foo "This is a pretty long single string-argument.")
+
+Note how this is different from using "@||"s in that strings around it
+are not merged.
+
+* Concrete Syntax: Spaces, Newlines, and Indentation
+
+The Scribble syntax treats spaces and newlines in a special way is
+meant to be sensible for dealing with text. As mentioned above,
+spaces at the beginning and end of body lines are discarded, except
+for spaces between a "{" and text, or between text and a "}".
+
+ @foo{bar} --reads-as--> (foo "bar")
+
+ @foo{ bar } --reads-as--> (foo " bar ")
+
+ @foo{ bar --reads-as--> (foo " bar" "\n" "baz ")
+ baz }
+
+A single newline that follows an open brace or precedes a closing brace is
+discarded, unless there are only newlines in the body; other newlines
+are read as a "\n" string
+
+ @foo{bar --reads-as--> (foo "bar")
}
-In other situations, newlines matter -- you might want to avoid a
-newline token in some place. To avoid a newline and still break the
-source line, use a line comment. As in TeX, these will consume text
-up-to and including the end of the line and all following whitespace.
-Example:
+ @foo{
+ bar --reads-as--> (foo "bar")
+ }
- @foo{bar @;
- baz@; --is-read-as--> (foo "bar baz.")
- .}
+ @foo{
+
+ bar --reads-as--> (foo "\n" "bar" "\n")
+
+ }
+
+ @foo{
+ bar
+ --reads-as--> (foo "bar" "\n" "\n" "baz")
+ baz
+ }
+
+ @foo{ --reads-as--> (foo "\n")
+ }
-A "|" that follows this is still used for marking the beginning of the
-text:
+ @foo{
+ --reads-as--> (foo "\n" "\n")
+ }
- @foo{bar @;
- baz@; --is-read-as--> (foo "bar baz .")
- | .}
+ @foo{ bar --reads-as--> (foo " bar" "\n" "baz ")
+ baz }
+
+In the parsed S-expression syntax, a single newline string is used for
+all newlines; you can use `eq?' to identify this line. This can be
+used to identify newlines in the original <text-body>.
+
+ (let ([nl (car @'{
+ })])
+ (for-each (lambda (x) (display (if (eq? x nl) "\n... " x)))
+ @`{foo
+ @,@(list "bar" "\n" "baz")
+ blah})
+ (newline))
+ --prints-->
+ foo
+ ... bar
+ baz
+ ... blah
+
+Spaces at the beginning of body lines do not appear in the resulting
+S-expressions, but the column of each line is noticed, and all-space
+indentation strings are added so the result has the same indentation.
+A indentation string is added to each line according to its distance
+from the leftmost syntax object (except for empty lines). (Note: if
+you try these examples on a mzscheme REPL, you should be aware that
+the reader does not know about the "> " prompt.)
+
+ @foo{ --reads-as--> (foo "bar" "\n"
+ bar "baz" "\n"
+ baz "blah")
+ blah
+ }
-** Concrete Syntax: the keyword-value part
+ @foo{ --reads-as--> (foo "begin" "\n"
+ begin " " "x++;" "\n"
+ x++; "end")
+ end}
+
+ @foo{ --reads-as--> (foo " " "a" "\n"
+ a " " "b" "\n"
+ b "c")
+ c}
+
+If the first string came from the openning "{" line, it is not
+prepended with an indentation (but it can affect the leftmost syntax
+object used for indentation). This makes sense when formatting
+structured code as well as text (see the last example in the following
+block).
+
+ @foo{bar --reads-as--> (foo "bar" "\n"
+ baz " " "baz" "\n"
+ bbb} "bbb")
+
+ @foo{ bar --reads-as--> (foo " bar" "\n"
+ baz " " "baz" "\n"
+ bbb} " " "bbb")
+
+ @foo{bar --reads-as--> (foo "bar" "\n"
+ baz "baz" "\n"
+ bbb} "bbb")
+
+ @foo{ bar --reads-as--> (foo " bar" "\n"
+ baz "baz" "\n"
+ bbb} "bbb")
+
+ @foo{ bar --reads-as--> (foo " bar" "\n"
+ baz "baz" "\n"
+ bbb} " " "bbb")
+
+ @text{Some text@footnote{And a
+ footnote comment.}. More text.}
+ --reads-as-->
+ (text "Some text"
+ (footnote "And a" "\n" "footnote comment.")
+ ". More text.")
+
+Note that each @-form is parsed to an S-expression that has its own
+indentation. This means that Scribble source can be indented like
+code, but if indentation matters then you may need to apply
+indentation of the outer item to all lines of the inner one. For
+example, in
-The keyword-value part can contain arbitrary Scheme expressions, which
-are simply stacked before the body text arguments:
+ @code{
+ begin
+ i = 1, r = 1
+ @bold{while i < n do
+ r *= i++
+ done}
+ end
+ }
+ --reads-as-->
+ (code "begin" "\n"
+ " " "i = 1, r = 1" "\n"
+ " " (bold "while i < n do" "\n"
+ " " "r *= i++" "\n"
+ "done") "\n"
+ "end")
- @foo[1 (* 2 3)]{bar} --is-read-as--> (foo 1 (* 2 3) "bar")
- @foo[@bar{...}]{blah} --is-read-as--> (foo (bar "...") "blah")
+a formatter will need to apply the 2-space indentation to the
+rendering of the `bold' body.
-But there is one change that makes it easy to use for keyword/values:
-(a) "=" is a terminating character in the textual scope, (b) if there is
-a "<identifier>=<expr>" sequence (spaces optional), then it is converted
-to "#:identifier <expr>":
+Note that to get a first-line text to be counted as a leftmost line,
+line and column accounting should be on for the input port
+(`use-at-readtable' turns them on for the current input port).
+Without this,
- @foo[(* 2 3) a=b]{bar} --is-read-as--> (foo (* 2 3) #:a b "bar")
+ @foo{x1
+ x2
+ x3}
-*** How should this be used?
+will not have 2-space indentations in the parsed S-expression if
+source accounting is not on, but
-This facility can be used in any way you want. All you need is to use
-function names that you bind. You can even use quasi-quotes, skipping
-the need for functions, for example:
+ @foo{x1
+ x2
+ x3}
- > (define (important . text) @`b{@u{@big{@,@text}}})
- > (important @`p{This is an important announcement!
- Read it!})
- (b (u (big (p "This is an important announcement!" "\n" "Read it!"))))
+will (due to the last line).
+
+For rare situations where spaces at the beginning (or end) of lines
+matter, you can begin (or end) a line with a "@||".
+
+ @foo{
+ @|| bar @|| --reads-as--> (foo " bar " "\n" " baz")
+ @|| baz}
+
+Finally, you might be need a verbatim-like environment, where the
+parsed body matches exactly the textual source. To make this
+possible, the @-parser uses syntax properties on the resulting syntax
+values. All items that are not physically in the Scribble source --
+newlines and indentation-spaces -- have a 'scribble property. An
+indentation string will have 'indentation as the value of this
+property, and a newline will have a '(newline S) value where S is the
+original newline string including spaces that precede and follow it
+(which includes the indentation for the following item). To implement
+a verbatim environment you need to drop indentation strings, and use
+the original newline strings instead of the single-newline string.
+Here is an example of this.
+
+ (define-syntax (verb stx)
+ (syntax-case stx ()
+ [(_ cmd item ...)
+ #`(cmd .
+ #,(let loop ([items (syntax->list #'(item ...))])
+ (if (null? items)
+ '()
+ (let* ([fst (car items)]
+ [prop (syntax-property fst 'scribble)]
+ [rst (loop (cdr items))])
+ (cond [(not prop) (cons fst rst)]
+ [(eq? prop 'indentation) rst]
+ [else (cons (datum->syntax-object
+ fst (cadr prop) fst)
+ rst)])))))]))
+ @verb[string-append]{
+ foo
+ bar
+ }