@italic{Parts of this section were adapted from Matthew Flatt and Eli Barzilay's excellent documentation for Racket's text-processing language, called Scribble◊.}
@title[#:tag "reader"]{Pollen ◊ command overview}
@section{The golden rule}
@ -54,7 +52,7 @@ A text-mode command has the three possible parts after the @litchar["◊"]:
@itemlist[
@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.}
]
@ -422,690 +420,214 @@ The value of edge is ◊|edge| pixels}
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.
Tip: if you use an editor in some Scheme mode without support for
@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:
For instance, tag functions. Recall from before that any not-yet-defined command name in Pollen is treated as a tag function:
@verbatim[#:indent 2]|==={
@;{
...
;}
}===|
@codeblock|{
#lang pollen
◊title{The Beginning of the End}
}|
so the editor does not treat the file as having unbalanced
parentheses.
@racketoutput{@literal{'(title "The Beginning of the End")}}
If only the @nonterm{cmd} part of an @tech{◊-form} is specified, then the
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.)
But what if you wanted to add attributes to this tag, so that it comes out like this?
@scribble-examples|==={
@foo{x @y z}
@foo{x @(* y 2) z}
@{@foo bar}
}===|
@racketoutput{@literal{'(title ((class "red")(id "first")) "The Beginning of the End")}}
Finally, note that there are currently no special rules for using
@litchar["@"] in the command itself, which can lead to things like:
You can do it with Racket arguments.
@scribble-examples|==={
@@foo{bar}{baz}
}===|
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:
@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|==={
@foo{blah blah blah}
}===|
@racketoutput{@literal{'(title ((class "red") (id "first")) "The Beginning of the End")}}
The example shows how an input syntax is read as Racket syntax, not
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
Racket arguments can be any valid Racket expressions. For instance, this will also work:
@verbatim[#:indent 2]|{
#lang at-exp racket
'@foo{blah blah blah}
@codeblock|{
#lang pollen
◊title['class: (format "~a" (* 6 7)) 'id: "first"]{The Beginning of the End}
@racketoutput{@literal{'(title ((class "42") (id "first")) "The Beginning of the End")}}
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]|{
#lang at-exp racket
@foo{blah blah blah}
@codeblock|{
#lang pollen
◊(define name "Brennan")
◊title['class: "red" 'id: ◊name]{The Beginning of the End}
}|
triggers a syntax error because @racket[foo] is not bound, and
@verbatim[#:indent 2]|{
#lang at-exp racket
(define (foo str) (printf "He wrote ~s.\n" str))
@foo{blah blah blah}
}|
@racketoutput{@literal{'(title ((class "read") (id "Brennan")) "The Beginning of the End")}}
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".}}
The datum part can contains arbitrary Racket expressions, which
are simply stacked before the body text arguments:
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.
@scribble-examples|==={
@foo[1 (* 2 3)]{bar}
@foo[@bar{...}]{blah}
}===|
@codeblock|{
#lang pollen
◊div{Do it again. ◊div{And again. ◊div{And yet again.}}}
}|
The body part can still be omitted, which is essentially an
alternative syntax for plain (non-textual) S-expressions:
Three small details to know about the text argument.
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.
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{◊"◊"}.
@scribble-examples|==={
@foo[]{bar}
@foo[]
@foo
@foo{}
}===|
@codeblock|{
#lang pollen
◊definition{This is the lozenge: ◊"◊"}
}|
The most common use of the datum part is for Racket forms that expect
keyword-value arguments that precede the body of text arguments.
@racketoutput{@literal{'(definition "This is the lozenge: ◊")}}
@scribble-examples|==={
@foo[#:style 'big]{bar}
}===|
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:
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{
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:
bar
@racketoutput{@literal{'(div "Roomy!" "\n" "\n" "I agree.")}}
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
}
}===|
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:
a formatter will need to apply the 2-space indentation to the
rendering of the @racket[bold] body.
@codeblock|{
#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,
line and column accounting should be on for the input port
(@racket[use-at-readtable] turns them on for the current input port).
But watch what happens with a multiline text argument:
will not have 2-space indentations in the parsed S-expression if
source accounting is not on, but
@codeblock|{
#lang pollen
◊(define (jejune text)
`(jejune ,text))
◊jejune{Deeply
chastened}
}|
@litchar/lines|==={
@foo{x1
x2
x3}
}===|
@racketerror{jejune: arity mismatch;@(linebreak)
the expected number of arguments does not match the given number@(linebreak)
expected: 1@(linebreak)
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
problem with Racket code, for example:
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:
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: