pull/9/head
Matthew Butterick 10 years ago
parent 9cd5fb7a06
commit fcf7f89e2e

@ -10,9 +10,7 @@
@(define (at-exp-racket) @(define (at-exp-racket)
@racket[#, @hash-lang[] #, @racketmodname[at-exp] #, @racketidfont{racket}]) @racket[#, @hash-lang[] #, @racketmodname[at-exp] #, @racketidfont{racket}])
@title[#:tag "reader"]{Pollen ◊ commands} @title[#:tag "reader"]{Pollen ◊ command overview}
@italic{Parts of this section were adapted from Matthew Flatt and Eli Barzilay's excellent documentation for Racket's text-processing language, called Scribble◊.}
@section{The golden rule} @section{The golden rule}
@ -54,7 +52,7 @@ A text-mode command has the three possible parts after the @litchar["◊"]:
@itemlist[ @itemlist[
@item{The @italic{command name} appears immediately after the @litchar["◊"]. Typically it's a short word.} @item{The @italic{command name} appears immediately after the @litchar["◊"]. Typically it's a short word.}
@item{The @italic{Racket arguments} appear between square brackets. Pollen is partly an interface to the Racket programming language. These arguments have to be entered using Racket conventions — e.g., a @tt{string of text} needs to be put in quotes as a @code{"string of text"}. If you like programming, you'll end up using these frequently. If you don't, you won't.} @item{The @italic{Racket arguments} appear between square brackets. Pollen is partly an interface to the Racket programming language. These arguments are entered using Racket conventions — e.g., a @tt{string of text} needs to be put in quotes as a @code{"string of text"}. If you like programming, you'll end up using these frequently. If you don't, you won't.}
@item{The @italic{text argument} appears between braces (aka curly brackets). You can put any ordinary text here. Unlike with the Racket arguments, you don't put quotes around the text.} @item{The @italic{text argument} appears between braces (aka curly brackets). You can put any ordinary text here. Unlike with the Racket arguments, you don't put quotes around the text.}
] ]
@ -422,690 +420,214 @@ The value of edge is ◊|edge| pixels}
@racketoutput{The value of edge is 100 pixels} @racketoutput{The value of edge is 100 pixels}
@;--------------------------------------------------------------------
@subsubsection{Inserting a comment} @subsubsection{Inserting a comment}
Two options.
To comment out the rest of a single line, use a lozenge followed by a semicolon @litchar{◊;}.
@subsubsection{lalala} @codeblock|{
#lang pollen
◊span{This is not a comment}
◊span{Nor is this} ◊;span{But this is}
Besides being a Racket identifier, the @nonterm{cmd} part of an }|
@tech{◊-form} can have Racket punctuation prefixes, which will end up
wrapping the @italic{whole} expression.
@scribble-examples|==={
@`',@foo{blah}
@#`#'#,@foo{blah}
}===|
When writing Racket code, this means that @litchar|{@`',@foo{blah}}|
is exactly the same as @litchar|{`@',@foo{blah}}| and
@litchar|{`',@@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).
After the optional punctuation prefix, the @nonterm{cmd} itself is not
limited to identifiers; it can be @italic{any} Racket expression.
@scribble-examples|==={
@(lambda (x) x){blah}
@`(unquote foo){blah}
}===|
In addition, the command can be omitted altogether, which will omit it @racketoutput{@literal{'(span "This is not a comment")} @(linebreak)
from the translation, resulting in an S-expression that usually @literal{'(span "Nor is this")}}
contains, say, just strings:
@scribble-examples|==={ To comment out a multiline block, use the lozengesemicolon signal @litchar{◊;} with curly braces, @litchar{◊;@"{"}like so@litchar{@"}"}.
@{foo bar
baz}
@'{foo bar
baz}
}===|
If the command part begins with a @litchar{;} (with no newline between @codeblock|{
the @litchar["@"] and the @litchar{;}), then the construct is a #lang pollen
comment. There are two comment forms, one for arbitrary-text and ◊;{
possibly nested comments, and another one for line comments: ◊span{This is not a comment}
◊span{Nor is this} ◊;span{But this is}
}
Actually, it's all a comment now
}|
@racketblock[
@#,BNF-seq[@litchar["@;{"] @kleenestar{@nonterm{any}} @litchar["}"]]
@#,BNF-seq[@litchar["@;"] @kleenestar{@nonterm{anything-else-without-newline}}] @racketoutput{@literal{Actually, it's all a comment now}}
]
In the first form, the commented body must still parse correctly; see @;--------------------------------------------------------------------
the description of the body syntax below. In the second form, all @subsection{The Racket arguments}
text from the @litchar["@;"] to the end of the line @italic{and} all
following spaces (or tabs) are part of the comment (similar to
@litchar{%} comments in TeX).
@scribble-examples|==={ The middle part of a text-mode Pollen command contains the @italic{Racket arguments} @litchar{[}between square brackets.@litchar{]} Most often, you'll see these used to pass extra information to commands that operate on text.
@foo{bar @; comment
baz@;
blah}
}===|
Tip: if you use an editor in some Scheme mode without support for For instance, tag functions. Recall from before that any not-yet-defined command name in Pollen is treated as a tag function:
@tech{◊-forms}, balanced comments can be confusing, since the open brace
looks commented out, and the closing one isn't. In such cases it is
useful to ``comment'' out the closing brace too:
@verbatim[#:indent 2]|==={ @codeblock|{
@;{ #lang pollen
... ◊title{The Beginning of the End}
;} }|
}===|
so the editor does not treat the file as having unbalanced @racketoutput{@literal{'(title "The Beginning of the End")}}
parentheses.
If only the @nonterm{cmd} part of an @tech{◊-form} is specified, then the But what if you wanted to add attributes to this tag, so that it comes out like this?
result is the command part only, without an extra set of parenthesis.
This makes it suitable for Racket escapes in body texts. (More on this
below, in the description of the body part.)
@scribble-examples|==={ @racketoutput{@literal{'(title ((class "red")(id "first")) "The Beginning of the End")}}
@foo{x @y z}
@foo{x @(* y 2) z}
@{@foo bar}
}===|
Finally, note that there are currently no special rules for using You can do it with Racket arguments.
@litchar["@"] in the command itself, which can lead to things like:
@scribble-examples|==={ Here's the hard way. You can type out your list of attributes in Racket format and drop them into the brackets as a single argument:
@@foo{bar}{baz}
}===|
@codeblock|{
#lang pollen
◊title['((class "red")(id "first"))]{The Beginning of the End}
}|
@racketoutput{@literal{'(title ((class "red") (id "first")) "The Beginning of the End")}}
But that's a lot of parentheses to think about. So here's the easy way. Anytime you use a tag function, there's a shortcut for inserting attributes. You can enter them as a series of @racket[symbol] / @racket[string] pairs between the Racket-argument brackets. The only caveat is that the symbols have to begin with a quote mark @litchar{'} and end with a colon @litchar{:}. So taken together, they look like this:
Here is one example: @codeblock|{
#lang pollen
◊title['class: "red" 'id: "first"]{The Beginning of the End}
}|
@scribble-examples|==={ @racketoutput{@literal{'(title ((class "red") (id "first")) "The Beginning of the End")}}
@foo{blah blah blah}
}===|
The example shows how an input syntax is read as Racket syntax, not Racket arguments can be any valid Racket expressions. For instance, this will also work:
what it evaluates to. If you want to see the translation of an example
into S-expression form, add a quote in front of it in a
@at-exp-racket[] module. For example, running
@verbatim[#:indent 2]|{ @codeblock|{
#lang at-exp racket #lang pollen
'@foo{blah blah blah} ◊title['class: (format "~a" (* 6 7)) 'id: "first"]{The Beginning of the End}
}| }|
in DrRacket prints the output @racketoutput{@literal{'(title ((class "42") (id "first")) "The Beginning of the End")}}
@nested[#:style 'inset]{@racketresult[(foo "blah blah blah")]}
while omitting the quote Since Pollen commands are really just Racket arguments underneath, you can use those too. Here, we'll define a variable called @tt{name} and use it in the Racket arguments of @tt{title}:
@verbatim[#:indent 2]|{ @codeblock|{
#lang at-exp racket #lang pollen
@foo{blah blah blah} ◊(define name "Brennan")
◊title['class: "red" 'id: ◊name]{The Beginning of the End}
}| }|
triggers a syntax error because @racket[foo] is not bound, and @racketoutput{@literal{'(title ((class "read") (id "Brennan")) "The Beginning of the End")}}
@verbatim[#:indent 2]|{
#lang at-exp racket
(define (foo str) (printf "He wrote ~s.\n" str))
@foo{blah blah blah}
}|
prints the output You can also use this area for @italic{keyword arguments}. Keyword arguments can be used to provide options for a particular Pollen command, to avoid redundancy. Suppose that instead of using the @tt{h1 ... h6} tags, you want to consolidate them into one command called @tt{heading} and select the level separately. You can do this with a keyword, in this case @racket[#:level], which is passed as a Racket argument:
@nested[#:style 'inset]{@racketoutput{He wrote "blah blah blah".}} @codeblock|{
#lang pollen
◊(define (heading #:level which text)
`(,(string->symbol (format "h~a" which)) ,text))
Here are more examples of @tech{◊-forms}: ◊heading[#:level 1]{Major league}
◊heading[#:level 2]{Minor league}
◊heading[#:level 6]{Trivial league}
}|
@scribble-examples|==={ @racketoutput{@literal{'(h1 "Major league")} @(linebreak)
@foo{blah "blah" (`blah'?)} @literal{'(h2 "Minor league")} @(linebreak)
@foo[1 2]{3 4} @literal{'(h6 "Trivial league")}
@foo[1 2 3 4]
@foo[#:width 2]{blah blah}
@foo{blah blah
yada yada}
@foo{
blah blah
yada yada
} }
}===|
As seen in the last example, multiple lines and the newlines that
separate them are parsed to multiple Racket strings. More generally,
a @nonterm{text-body} is made of text, newlines, and nested
@tech{◊-forms}, where the syntax for @tech{◊-forms} is the same whether it's
in a @nonterm{text-body} context as in a Racket context. A
@nonterm{text-body} that isn't an @tech{◊-form} is converted to a string
expression for its @nonterm{parsed-body}; newlines and following
indentations are converted to @racket["\n"] and all-space string
expressions.
@scribble-examples|==={
@foo{bar @baz{3}
blah}
@foo{@b{@u[3] @u{4}}
blah}
@C{while (*(p++))
*p = '\n';}
}===|
The command part of an @tech{◊-form} is optional as well. In that case,
the @tech{◊-form} is read as a list, which usually counts as a function
application, but it also useful when quoted with the usual Racket
@racket[quote]:
@scribble-examples|==={
@{blah blah}
@{blah @[3]}
'@{foo
bar
baz}
}===|
Finally, we can also drop the datum and text parts, which leaves us with
only the command---which is read as is, not within a parenthesized
form. This is not useful when reading Racket code, but it can be used
inside a text block to escape a Racket identifier. A vertical bar
(@litchar{|}) can be used to delimit the escaped identifier when
needed.
@scribble-examples|==={
@foo
@{blah @foo blah}
@{blah @foo: blah}
@{blah @|foo|: blah}
}===|
Actually, the command part can be any Racket expression (that does not
start with @litchar["["], @litchar["{"], or @litchar["|"]), which is
particularly useful with such escapes since they can be used with any
expression.
@scribble-examples|==={
@foo{(+ 1 2) -> @(+ 1 2)!}
@foo{A @"string" escape}
}===|
Note that an escaped Racket string is merged with the surrounding text
as a special case. This is useful if you want to use the special
characters in your string, but escaping braces are not necessary if
they are balanced.
@scribble-examples|==={
@foo{eli@"@"barzilay.org}
@foo{A @"{" begins a block}
@C{while (*(p++)) {
*p = '\n';
}}
}===|
In some cases, a text contains many literal ◊s, which can be
cumbersome to quote individually. For such case, braces have an
alternative syntax: A block of text can begin with a
``@litchar["|{"]'' and terminated accordingly with a
``@litchar["}|"]''. Furthermore, any nested @tech{◊-forms} must begin
with a ``@litchar["|@"]''.
@scribble-examples|==={
@foo|{bar}@{baz}|
@foo|{bar |@x{X} baz}|
@foo|{bar |@x|{@}| baz}|
}===|
In cases when even this is not convenient enough, punctuation
characters can be added between the @litchar{|} and the braces and the
◊ in nested forms. (The punctuation is mirrored for parentheses
and @litchar{<>}s.) With this extension, Pollen syntax can be used as a
``here string'' replacement.
@scribble-examples|==={
@foo|--{bar}@|{baz}--|
@foo|<<{bar}@|{baz}>>|
}===|
On the flip side of this is, how can an ◊ sign be used in Racket
code? This is almost never an issue, because Racket strings and
characters are still read the same, and @litchar["@"] is set as a
non-terminating reader macro so it can be used in Racket identifiers
anywhere except in the first character of an identifier. When
@litchar["@"] must appear as the first character of an identifier, you
must quote the identifier just like other non-standard characters in
normal S-expression syntax: with a backslash or with vertical bars.
@scribble-examples|==={
(define \@email "foo@bar.com")
(define |@atchar| #\@)
}===|
Note that spaces are not allowed before a @litchar{[} or a
@litchar["{"], or they will be part of the following text (or Racket
code). (More on using braces in body texts below.)
@scribble-examples|==={
@foo{bar @baz[2 3] {4 5}}
}===|
Finally, remember that the Pollen is just an alternate for
S-expressions. Identifiers still get their meaning, as in any
Racket code, through the lexical context in which they appear.
Specifically, when the above @tech{◊-form} appears in a Racket expression
context, the lexical environment must provide bindings for
@racket[foo] as a procedure or a macro; it can be defined, required,
or bound locally (with @racket[let], for example).
@; FIXME: unfortunate code duplication
@interaction[
(eval:alts
(let* ([formatter (lambda (fmt)
(lambda args (format fmt (apply string-append args))))]
[bf (formatter "*~a*")]
[it (formatter "/~a/")]
[ul (formatter "_~a_")]
[text string-append])
#,(tt "@text{@it{Note}: @bf{This is @ul{not} a pipe}.}"))
(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}.}))
]
@;-------------------------------------------------------------------- @;--------------------------------------------------------------------
@section{The Datum Part} @subsection{The text argument}
The datum part can contains arbitrary Racket expressions, which The third part of a text-mode Pollen command is the text argument. The text argument @litchar{@"{"}appears between curly braces@litchar{@"}"}. It can contain any text you want. The text argument can also contain other Pollen commands with their own text arguments. And they can contain other Pollen commands ... and so on, all the way down.
are simply stacked before the body text arguments:
@scribble-examples|==={ @codeblock|{
@foo[1 (* 2 3)]{bar} #lang pollen
@foo[@bar{...}]{blah} ◊div{Do it again. ◊div{And again. ◊div{And yet again.}}}
}===| }|
The body part can still be omitted, which is essentially an @racketoutput{@literal{'(div "Do it again. " (div "And again. " (div "And yet again.")))}}
alternative syntax for plain (non-textual) S-expressions:
@scribble-examples|==={ Three small details to know about the text argument.
@foo[bar]
@foo{bar @f[x] baz}
}===|
The datum part can be empty, which makes no difference, except when First, the only character that needs special handling in a text argument is the lozenge @litchar{◊}. A lozenge ordinarily marks a new command. So if you want an actual lozenge to appear in the text, you have to escape it by typing @litchar{◊"◊"}.
the body is omitted. It is more common, however, to use an empty body
for the same purpose.
@scribble-examples|==={ @codeblock|{
@foo[]{bar} #lang pollen
@foo[] ◊definition{This is the lozenge: ◊"◊"}
@foo }|
@foo{}
}===|
The most common use of the datum part is for Racket forms that expect @racketoutput{@literal{'(definition "This is the lozenge: ◊")}}
keyword-value arguments that precede the body of text arguments.
@scribble-examples|==={ Second, the whitespace-trimming policy. Here's the short version: if there's a carriage return at either end of the text argument, it is trimmed, and whitespace at the end of each line is selectively trimmed in an intelligent way. So this text argument, with carriage returns on the ends:
@foo[#:style 'big]{bar}
}===|
@;-------------------------------------------------------------------- @codeblock|{
@section{The Body Part} #lang pollen
◊div{
The syntax of the body part is intended to be as convenient as Roomy!
possible for free text. It can contain almost any text---the only
characters with special meaning is @litchar["@"] for sub-@tech{◊-forms},
and @litchar["}"] for the end of the text. In addition, a
@litchar["{"] is allowed as part of the text, and it makes the
matching @litchar["}"] be part of the text too---so balanced braces
are valid text.
@scribble-examples|==={
@foo{f{o}o}
@foo{{{}}{}}
}===|
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 @racket["\n"] strings
(i.e., they are not merged with other body parts); see also the
information about newlines and indentation below. Spaces are
@italic{not} discarded if they appear after the open @litchar["{"]
(before the closing @litchar["}"]) when there is also text that
follows (precedes) it; specifically, they are preserved in a
single-line body.
@scribble-examples|==={
@foo{bar}
@foo{ bar }
@foo[1]{ bar }
}===|
If @litchar["@"] appears in a body, then it is interpreted as Racket
code, which means that the ◊-reader is applied recursively, and the
resulting syntax appears as part of the S-expression, among other
string contents.
@scribble-examples|==={
@foo{a @bar{b} c}
}===|
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 Racket expression, this makes ◊ a general escape to
arbitrary Racket code.
@scribble-examples|==={
@foo{a @bar c}
@foo{a @(bar 2) c}
}===|
This is particularly useful with strings, which can be used to include
arbitrary text.
@scribble-examples|==={
@foo{A @"}" marks the end}
}===|
Note that the escaped string is (intentionally) merged with the rest
of the text. This works for @litchar["@"] too:
@scribble-examples|==={
@foo{The prefix: @"@".}
@foo{@"@x{y}" --> (x "y")}
}===|
@;-------------------------------------------------------------------- I agree.
@subsection[#:tag "alt-body-syntax"]{Alternative Body Syntax} }
}|
In addition to the above, there is an alternative syntax for the body,
one that specifies a new marker for its end: use @litchar["|{"] for
the opening marker to have the text terminated by a @litchar["}|"].
@scribble-examples|==={
@foo|{...}|
@foo|{"}" follows "{"}|
@foo|{Nesting |{is}| ok}|
}===|
This applies to sub-@tech{◊-forms} too---the @litchar["@"] must be
prefixed with a @litchar{|}:
@scribble-examples|==={
@foo|{Maze
|@bar{is}
Life!}|
@t|{In |@i|{sub|@"@"s}| too}|
}===|
Note that the subform uses its own delimiters, @litchar{{...}} or
@litchar{|{...}|}. This means that you can copy and paste Pollen
text with @tech{◊-forms} freely, just prefix the @litchar["@"] if the
immediate surrounding text has a prefix.
For even better control, you can add characters in the opening
delimiter, between the @litchar{|} and the @litchar["{"].
Characters that are put there (non alphanumeric ASCII characters only,
excluding @litchar["{"] and @litchar["@"]) should also be used for
sub-@tech{◊-forms}, and the end-of-body marker should have these characters
in reverse order with paren-like characters (@litchar{(},
@litchar{[}, @litchar{<}) mirrored.
@scribble-examples|==={
@foo|<<<{@x{foo} |@{bar}|.}>>>|
@foo|!!{X |!!@b{Y}...}!!|
}===|
Finally, remember that you can use an expression escape with a Racket
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.
@;-------------------------------------------------------------------- @racketoutput{@literal{'(div "Roomy!" "\n" "\n" "I agree.")}}
@subsection{Racket Expression Escapes}
In some cases, you may want to use a Racket identifier (or a number or
a boolean etc.) in a position that touches the following text; in
these situations you should surround the escaped Racket expression by
a pair of @litchar{|} characters. The text inside the bars is
parsed as a Racket expression.
@scribble-examples|==={
@foo{foo@bar.}
@foo{foo@|bar|.}
@foo{foo@3.}
@foo{foo@|3|.}
}===|
This form is a generic Racket expression escape, there is no body text
or datum part when you use this form.
@scribble-examples|==={
@foo{foo@|(f 1)|{bar}}
@foo{foo@|bar|[1]{baz}}
}===|
This works for string expressions too, but note that unlike the above,
the string is (intentionally) not merged with the rest of the text:
@scribble-examples|==={
@foo{x@"y"z}
@foo{x@|"y"|z}
}===|
Expression escapes also work with @italic{any} number of expressions,
@scribble-examples|==={
@foo{x@|1 (+ 2 3) 4|y}
@foo{x@|*
*|y}
}===|
It seems that @litchar["@||"] 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.
@scribble-examples|==={
@foo{Alice@||Bob@|
|Carol}
}===|
Note that @litchar["@|{...}|"] can be parsed as either an escape expression or
as the Racket command part of an @tech{◊-form}. The latter is used in this case
(since there is little point in Racket code that uses braces.
@scribble-examples|==={
@|{blah}|
}===|
@;-------------------------------------------------------------------- Yields the same result as this one:
@subsection{Comments}
As noted above, there are two kinds of Pollen comments: @litchar|{@;{...}}| is @codeblock|{
a (nestable) comment for a whole body of text (following the same #lang pollen
rules for @tech{◊-forms}), and @litchar|{@;...}| is a line-comment. ◊div{Roomy!
@scribble-examples|==={ I agree.}
@foo{First line@;{there is still a }|
newline here;}
Second line}
}===|
One useful property of line-comments is that they continue to the end @racketoutput{@literal{'(div "Roomy!" "\n" "\n" "I agree.")}}
of the line @italic{and} all following spaces (or tabs). Using this,
you can get further control of the subforms.
@scribble-examples|==={ For the long version, please see @secref{Spaces, Newlines, and Indentation}.
@foo{A long @;
single-@;
string arg.}
}===|
Note how this is different from using @litchar["@||"]s in that strings
around it are not merged.
@;-------------------------------------------------------------------- Third, within a multiline text argument, newline characters become individual strings that are not merged with adjacent text. So what you end up with is a list of strings, not a single string. That's why in the last example, we got this:
@subsection{Spaces, Newlines, and Indentation}
The Pollen 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 @litchar["{"] and text, or between text and a
@litchar["}"].
@scribble-examples|==={
@foo{bar}
@foo{ bar }
@foo{ bar
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 @racket["\n"] string
@scribble-examples|==={
@foo{bar
}
@foo{
bar
}
@foo{
bar @racketoutput{@literal{'(div "Roomy!" "\n" "\n" "I agree.")}}
} Instead of this:
@foo{
bar
baz @racketoutput{@literal{'(div "Roomy!\n\nI agree.")}}
}
@foo{
}
@foo{
} Under most circumstances, these two tagged X-expressions will behave the same way. The biggest exception is with functions. A function that operates on multiline text arguments needs to be able to handle an indefinite number of strings. For instance, this @tt{jejune} function only accepts a single argument. It will work with a single-line text argument, because that produces a single string:
@foo{ bar
baz }
}===|
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 Racket REPL, you should be aware that
the reader does not know about the ``@litchar{> }'' prompt.)
@scribble-examples|==={
@foo{
bar
baz
blah
}
@foo{
begin
x++;
end}
@foo{
a
b
c}
}===|
If the first string came from the opening @litchar["{"] 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).
@scribble-examples|==={
@foo{bar
baz
bbb}
@foo{ bar
baz
bbb}
@foo{bar
baz
bbb}
@foo{ bar
baz
bbb}
@foo{ bar
baz
bbb}
@text{Some @b{bold
text}, and
more text.}
}===|
Note that each ◊-form is parsed to an S-expression that has its own
indentation. This means that Pollen 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
@litchar/lines|==={
@code{
begin
i = 1, r = 1
@bold{while i < n do
r *= i++
done}
end
}
}===|
a formatter will need to apply the 2-space indentation to the @codeblock|{
rendering of the @racket[bold] body. #lang pollen
◊(define (jejune text)
`(jejune ,text))
◊jejune{Irrational confidence}
}|
Note that to get a first-line text to be counted as a leftmost line, @racketoutput{@literal{'(jejune "Irrational confidence")}}
line and column accounting should be on for the input port
(@racket[use-at-readtable] turns them on for the current input port).
Without this,
@litchar/lines|==={ But watch what happens with a multiline text argument:
@foo{x1
x2
x3}
}===|
will not have 2-space indentations in the parsed S-expression if @codeblock|{
source accounting is not on, but #lang pollen
◊(define (jejune text)
`(jejune ,text))
◊jejune{Deeply
chastened}
}|
@litchar/lines|==={ @racketerror{jejune: arity mismatch;@(linebreak)
@foo{x1 the expected number of arguments does not match the given number@(linebreak)
x2   expected: 1@(linebreak)
x3}   given: 3@(linebreak)
}===|   arguments...:@(linebreak)
   "Deeply"@(linebreak)
   "\n"@(linebreak)
   "chastened"}
will (due to the last line). Pay attention to this, as it can be a The answer is to use a @italic{rest argument} in the function, which takes the ``rest'' of the arguments — however many there may be — and combines them into a single @racket[list]. If we rewrite @tt{jejune} with a rest argument, we can fix the problem:
problem with Racket code, for example:
@codeblock|{
#lang pollen
◊(define (jejune . texts)
`(jejune ,@texts))
◊jejune{Deeply
chastened}
}|
@litchar/lines|==={ @racketoutput{@literal{'(jejune "Deeply" "\n" "chastened")}}
@code{(define (foo x)
(+ x 1))}
}===|
For rare situations where spaces at the beginning (or end) of lines
matter, you can begin (or end) a line with a @litchar["@||"].
@scribble-examples|==={ @section{Further reading}
@foo{
@|| bar @||
@|| baz}
}===|
@; -------------------------------------------------- The Pollen language is a variant of Racket's own text-processing language, called Scribble. So many things that are true about Scribble are also true about Pollen. For the sake of clarity & brevity, I've omitted them from this summary. But if you want the full story:
@(close-eval read-eval)
[insert]
Loading…
Cancel
Save