documentation edits

pull/58/head
Matthew Butterick 9 years ago
parent 5d44a17379
commit 5f9fd6bd19

@ -7,11 +7,11 @@ A summary of the key components & concepts of the Pollen publishing system and h
@section[#:tag "the-book-is-a-program"]{The book is a program}
This is the core design principle of Pollen. Consistent with this principle, Pollen adopts the habits of software development in its functionality, workflow, and project management.
This is the core design principle of Pollen. Consistent with this principle, Pollen adopts the habits of software development in its functionality, workflow, and project structure.
@itemlist[
@item{@bold{You are a programmer.} Don't panic. But let's just admit it — if your book is a program, then you are, in part, programming it. You don't have to know any programming to start using Pollen. But you'll have to be willing to learn a few programming ideas. (Those who have programmed other template-based HTML generators may have to forget a few things.)}
@item{@bold{You are a programmer.} Don't panic. But let's just admit it — if your book is a program, then you are, in part, programming it. You don't have to know any programming to start using Pollen. But you'll have to be willing to learn a few programming ideas. (And those who have used other template-based HTML generators may have to forget a few things.)}
@item{@bold{A Pollen project consists of source files + static files.} A @italic{source file} is a file that can be compiled to produce certain output. A @italic{static file} is usable as it stands (e.g., an SVG file or webfont). Generally, the textual content of your book will live in source files, and other elements will be static files.}
@ -28,7 +28,7 @@ This is the core design principle of Pollen. Consistent with this principle, Pol
@item{@bold{The Pollen language is based on Scribble.} Scribble is a variant of the Racket language that flips the usual programming syntax: instead of code with embedded textual content, a Scribble source file is text with embedded code (an idea borrowed from @link["https://en.wikipedia.org/wiki/TeX"]{TeX}). The Pollen language is adapted from Scribble. So most things that are true about Scribble are also true about Pollen (see @other-doc['(lib "scribblings/scribble/scribble.scrbl")]).}
@item{@bold{The Pollen language is divided into dialects.} The Pollen dialects share a common syntax and structure. But they're different in details that makes them better adapted to certain types of source files (for instance, one dialect of Pollen understands Markdown; the others don't). Use whichever suits the task at hand.}
@item{@bold{The Pollen language is a set of dialects.} The Pollen dialects share a common syntax and structure. But they're different in details that makes them better adapted to certain types of source files (for instance, one dialect of Pollen understands Markdown; the others don't). Use whichever suits the task at hand.}
]
@ -41,7 +41,7 @@ The Pollen development environment has three main pieces: the DrRacket code edit
@item{@bold{Edit source files with DrRacket.} DrRacket is Racket's GUI code editor. Sure, you can also use a generic text editor. But DrRacket lets you immediately run your source and see if it works.}
@item{@bold{Preview & test web pages with the Pollen project server.} Pollen has a built-in development web server called the @italic{project server}. After you start the project server, you can preview your web pages within any web browser, allowing you to test them with maximum accuracy.}
@item{@bold{Preview & test web pages with the Pollen project server.} Pollen has a built-in development web server called the @defterm{project server}. After you start the project server, you can preview your web pages within any web browser, allowing you to test them with maximum accuracy.}
@item{@bold{Write the docs.} The project server can recognize and render Scribble files, so you can use it as a previewing tool while you're writing your documentation.}
@ -53,7 +53,7 @@ The Pollen development environment has three main pieces: the DrRacket code edit
@section{A special data structure for HTML}
Unlike other programming languages, Pollen (and Racket) internally represent HTML with something called an @italic{X-expression}. An X-expression is simply a list that represents what in HTML is called an @italic{element}, meaning a thing with an opening tag, a closing tag, and content in between. Like HTML elements, X-expressions can be nested. Unlike HTML elements, X-expressions have no closing tag, they use parentheses to denote the start and end, and text elements are put inside quotes.
Unlike other programming languages, Pollen (and Racket) internally represent HTML with something called @secref["X-expressions" #:doc '(lib "pollen/scribblings/pollen.scrbl")]. An X-expression is simply a list that represents an HTML @defterm{element}, meaning a thing with an opening tag, a closing tag, and content in between. Like HTML elements, X-expressions can be nested. Unlike HTML elements, X-expressions have no closing tag, they use parentheses to denote the start and end, and text elements are put inside quotes.
For example, consider this HTML element:
@ -63,7 +63,7 @@ As a Racket X-expression, this would be written:
@nested[#:style 'code-inset]{@verbatim{(body (h1 "Hello world") (p "Nice to " (i "see") " you."))}}
More will be said about X-expressions. But a couple advantages should be evident already. First, without the redundant angle brackets, the X-expression is more readable than the equivalent HTML. Second, an X-expression is preferable to representing HTML as a simple string, because it preserves the internal structure of the element.
More will be said about X-expressions. But a couple advantages should be evident already. First, without the redundant angle brackets, the X-expression is arguably more readable than the equivalent HTML. Second, an X-expression is preferable to treating HTML as a simple string, because it preserves the internal structure of the element.
@section{Pollen command syntax}
@ -73,16 +73,17 @@ As mentioned above, a Pollen source file is not code with text embedded in it, b
@itemlist[
@item{@bold{If you can write text, you can program in Pollen.} Really. As you already found out in the @secref["quick-tour"], this is a valid Pollen program:
@racketmod[pollen
Hello world: how are you on this fine summer day?]
}
@codeblock{
#lang pollen
Hello world: how are you on this fine summer day?
}}
@item{@bold{Commands start with ◊.} A simple rule: if a piece of text starts with @litchar{◊}, it's treated as a command; otherwise it's treated as ordinary text.}
@item{@bold{Write commands in text mode or Racket mode.} Commands can use two equivalent notation systems: either Pollen's text-mode command syntax, or standard Racket syntax.}
@item{@bold{Everything in Racket is in Pollen too.} This isn't some dimwit ``template language.'' Racket is a fully provisioned programming language, and every Racket function is available in Pollen.}
@item{@bold{Everything in Racket is in Pollen too.} Pollen isn't a watered-down ``template language.'' Racket is a fully provisioned programming language, and every Racket function is available in Pollen.}
]
@ -95,7 +96,7 @@ The @italic{preprocessor} is the simplest processing mode in Pollen.
@item{@bold{Text output.} The preprocessor scans the source for any Pollen commands, resolves them, and outputs the whole file as text.}
@item{@bold{Work with any text file.} I hope this blows your mind a teeny bit. You can use the preprocessor with HTML, CSS, Markdown, JavaScript, XML, SVG, or any other text-based file (including source files of other programming languages).}
@item{@bold{Work with any text file.} You can use the preprocessor with HTML, CSS, Markdown, JavaScript, XML, SVG, or any other text-based file (including source files of other programming languages). I hope this blows your mind a teeny bit.}
@item{@bold{Start quickly.} Because it works with any text file, the preprocessor is an easy way to try out Pollen, because you can mix it into your workflow on an existing project, or even just one file.}
@ -103,17 +104,17 @@ The @italic{preprocessor} is the simplest processing mode in Pollen.
@section{Templated source files}
If you want to apply a particular page format to multiple sources of content — as you would in a book — you can use Pollen @italic{templates}.
If you want to apply a particular page format to multiple sources of content — as you would in a book — you can use Pollen @defterm{templates}.
@itemlist[
@item{@bold{Templates can be any format.} Usually Pollen templates will be HTML. But they don't have to be.}
@item{@bold{Markdown support.} Pollen has a built-in Markdown parser, so you can import Markdown sources into a Pollen publication.}
@item{@bold{Markdown authoring mode.} Pollen has a built-in Markdown parser, so you can import Markdown sources into a Pollen publication.}
@item{@bold{Custom markup.} Pollen's markup mode allows you the freedom to define your own markup tags and attach behavior to them.}
@item{@bold{Pollen markup.} Pollen markup allows you the freedom to define your own markup tags and attach behavior to them.}
@item{@bold{Mix source types.} Every text source is converted to an X-expression before going into a template. So it's fine to have multiple kinds of text source in one project.}
@item{@bold{Mix source types.} Every text source is converted to an X-expression before going into a template. So it's fine to have multiple dialects of source files in one project.}
]
@ -121,7 +122,7 @@ If you want to apply a particular page format to multiple sources of content —
@section{Pagetrees}
Similar to a table of contents, a @italic{pagetree} is a special Pollen source file that gets turned into a hierarchical list of pages.
Similar to a table of contents, a @defterm{pagetree} is a special Pollen source file that gets turned into a hierarchical list of pages.
@itemlist[

@ -52,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 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{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 @code{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.}
]
@ -157,7 +157,7 @@ In Pollen, you'll typically use the command name for one of four purposes:
@item{To invoke a tag function.}
@item{To invoke another function.}
@item{To insert the value of a variable.}
@item{To insert a @tt{meta} value.}
@item{To insert a @code{meta} value.}
@item{To insert a comment.}
]
@ -185,7 +185,7 @@ To streamline markup, Pollen doesn't restrict you to a certain set of tags, nor
The one restriction is that you can't invent names for tags that are already being used for other commands. For instance, @tt{map} is a name permanently reserved by the Racket function @racket[map]. It's also a rarely-used HTML tag. But gosh, you really want to use it. Problem is, if you invoke it directly, Pollen will think you mean the other @racket[map]:
The one restriction is that you can't invent names for tags that are already being used for other commands. For instance, @code{map} is a name permanently reserved by the Racket function @racket[map]. It's also a rarely-used HTML tag. But gosh, you really want to use it. Problem is, if you invoke it directly, Pollen will think you mean the other @racket[map]:
@codeblock{
@ -218,7 +218,7 @@ Use the @racket[define] command to create your own function for a command name.
@repl-output{'(strong "Fancy Sauce, $1")}
We can define @tt{strong} to do something else, like add to the text:
We can define @code{strong} to do something else, like add to the text:
@codeblock{
#lang pollen
@ -228,7 +228,7 @@ We can define @tt{strong} to do something else, like add to the text:
@repl-output{'(strong "Hey! Listen up! Fancy Sauce, $1")}
The replacement function has to accept any arguments that might get passed along, but it doesn't have to do anything with them. For instance, this function definition won't work because @tt{strong} is going to get a text argument that it's not defined to handle:
The replacement function has to accept any arguments that might get passed along, but it doesn't have to do anything with them. For instance, this function definition won't work because @code{strong} is going to get a text argument that it's not defined to handle:
@codeblock{
#lang pollen
@ -243,7 +243,7 @@ the expected number of arguments does not match the given number
  arguments...:
    "Fancy Sauce, $1"}
Whereas in this version, @tt{strong} accepts an argument called @tt{text}, but then ignores it:
Whereas in this version, @code{strong} accepts an argument called @code{text}, but then ignores it:
@codeblock|{
#lang pollen
@ -267,7 +267,7 @@ You aren't limited to functions you define. Any function from Racket, or any Rac
@repl-output{'(range 1 20)}
Hold on — that's not what we want. Where's the list of numbers? The problem here is that we didn't explicitly import the @racketmodname[racket/list] library, which contains the definition for @racket[range]. (If you need to find out what library contains a certain function, the Racket documentation will tell you.) Without @racketmodname[racket/list], Pollen just thinks we're trying to use @tt{range} as a tag function (and if we had been, then @repl-output{'(range 1 20)} would've been the right result).
Hold on — that's not what we want. Where's the list of numbers? The problem here is that we didn't explicitly import the @racketmodname[racket/list] library, which contains the definition for @racket[range]. (If you need to find out what library contains a certain function, the Racket documentation will tell you.) Without @racketmodname[racket/list], Pollen just thinks we're trying to use @code{range} as a tag function (and if we had been, then @repl-output{'(range 1 20)} would've been the right result).
We fix this by using the @racket[require] command to bring in the @racketmodname[racket/list] library, which contains the @racket[range] we want:
@ -293,7 +293,7 @@ Of course, you can also invoke Racket functions indirectly, by attaching them to
Let's return to the problem that surfaced in the last section — the fact that some command names can't be used as tag functions because they're already being used for other things. You can work around this by defining your own tag function with a non-conflicting name.
For instance, suppose we want to use @tt{map} as a tag even though Racket is using it for its own function called @racket[map]. First, we invent a command name that doesn't conflict. Let's call it @code{my-map}. As you learned above, Pollen will treat a new command name as a tag function by default:
For instance, suppose we want to use @code{map} as a tag even though Racket is using it for its own function called @racket[map]. First, we invent a command name that doesn't conflict. Let's call it @code{my-map}. As you learned above, Pollen will treat a new command name as a tag function by default:
@codeblock|{
#lang pollen
@ -303,7 +303,7 @@ For instance, suppose we want to use @tt{map} as a tag even though Racket is usi
@repl-output{'(my-map "How I would love this to be a map.")}
But @code{my-map} is not the tag we want. We need to define @code{my-map} to be a tag function for @tt{map}. We can do this with the Pollen helper @racket[make-default-tag-function]. That function lives in @racket[pollen/tag], so we @racket[require] that too:
But @code{my-map} is not the tag we want. We need to define @code{my-map} to be a tag function for @code{map}. We can do this with the Pollen helper @racket[make-default-tag-function]. That function lives in @racket[pollen/tag], so we @racket[require] that too:
@codeblock|{
@ -365,7 +365,7 @@ The value of zam is ◊zam
@margin-note{In an unsaved DrRacket file, or a file without a special Pollen source extension, the @tt{#lang pollen} designation invokes the Pollen preprocessor by default. You can explicitly invoke preprocessor mode by starting a file with @tt{#lang pollen/pre}. See also @secref["Preprocessor___pp_extension_"].}
If the variable holds a container datatype (like a @racket[list], @racket[hash], or @racket[vector]), Pollen will produce the Racket text representation of the item. Here, @tt{zam} is a @racket[list] of integers:
If the variable holds a container datatype (like a @racket[list], @racket[hash], or @racket[vector]), Pollen will produce the Racket text representation of the item. Here, @code{zam} is a @racket[list] of integers:
@codeblock|{
#lang pollen
@ -386,7 +386,7 @@ The value of zam is ◊string-join[(map number->string zam)]{ and }
@repl-output{The value of zam is 1 and 2 and 3}
Pollen will still produce an error if you try to convert an esoteric value to a string. Here, @tt{zam} is the addition function (@racket[+]):
Pollen will still produce an error if you try to convert an esoteric value to a string. Here, @code{zam} is the addition function (@racket[+]):
@codeblock|{
#lang pollen
@ -412,7 +412,7 @@ This time, the file will produce an error:
One special case to know about. In the examples above, there's a word space between the variable and the other text. But suppose you need to insert a variable into text so that there's no space in between. The simple ◊ notation won't work, because it won't be clear where the variable name ends and the text begins.
For instance, suppose we want to use a variable @tt{edge} next to the string @tt{px}:
For instance, suppose we want to use a variable @code{edge} next to the string @code{px}:
@codeblock|{
#lang pollen
@ -422,7 +422,7 @@ p { margin-left: ◊edgepx; }
@errorblock{Pollen decoder: can't convert #<procedure:...t/pollen/tag.rkt:6:2> to string}
The example fails because Pollen reads the whole string after the @litchar{◊} as the single variable name @tt{edgepx}. Since @tt{edgepx} isn't defined, it's treated as a tag function, and since Pollen can't convert a function to a string, we get an error.
The example fails because Pollen reads the whole string after the @litchar{◊} as the single variable name @code{edgepx}. Since @code{edgepx} isn't defined, it's treated as a tag function, and since Pollen can't convert a function to a string, we get an error.
In these situations, surround the variable name with vertical bars @litchar{◊|}like so@litchar{|} to explicitly indicate where the variable name ends. The bars are not treated as part of the name, nor are they included in the result. Once we do that, we get what we intended:
@ -456,7 +456,7 @@ Metas are not a foundational abstraction. They're just a convenience — a place
@margin-note{Pollen occasionally uses metas. For instance, the @racket[get-template-for] function will look in the metas of a source file to see if a template is explicitly specified. The @racket[pollen/template] module also contains functions for working with metas, such as @racket[select-from-metas].}
To insert a meta, use the standard command syntax for inserting a tag with an attribute pair, but use the special @tt{meta} name:
To insert a meta, use the standard command syntax for inserting a tag with an attribute pair, but use the special @code{meta} name:
@codeblock{
#lang pollen
@ -474,16 +474,16 @@ When you mark a meta like this, two things happen. First, when you run the file,
'(some-tag ((key "value")) "Another normal tag")
}
@margin-note{If your @tt{meta} includes a text argument between curly braces — or any other arguments aside from the initial keyvalue pair — they will be ignored.}
@margin-note{If your @code{meta} includes a text argument between curly braces — or any other arguments aside from the initial keyvalue pair — they will be ignored.}
Second, the meta is collected into a hash table that is exported with the name @tt{metas}. To see this hash table, run the file above in DrRacket, then move to the interactions window and type @exec{metas} at the prompt:
Second, the meta is collected into a hash table that is exported with the name @code{metas}. To see this hash table, run the file above in DrRacket, then move to the interactions window and type @exec{metas} at the prompt:
@terminal{
> metas
'#hash((here-path . "unsaved-editor167056") (dog . "Roxy"))
}
The only key that's automatically defined in every meta table is @tt{here-path}, which is the absolute path to the source file. (Here, because the file hasn't been saved, you'll see the @tt{unsaved-editor...} name instead.)
The only key that's automatically defined in every meta table is @code{here-path}, which is the absolute path to the source file. (Here, because the file hasn't been saved, you'll see the @code{unsaved-editor...} name instead.)
Still, you can override this too:
@ -503,7 +503,7 @@ When you run this code, the result will be the same as before, but this time the
'#hash((dog . "Roxy") (here-path . "nowhere"))
}
It doesn't matter how many metas you put in a source file or where you put them. They'll all be extracted and put into the @tt{metas} hash table. The order of the metas is not preserved (because order is not preserved in a hash table). But if you have two metas with the same key, the later one will supersede the earlier one:
It doesn't matter how many metas you put in a source file or where you put them. They'll all be extracted and put into the @code{metas} hash table. The order of the metas is not preserved (because order is not preserved in a hash table). But if you have two metas with the same key, the later one will supersede the earlier one:
@codeblock{
#lang pollen
@ -582,7 +582,7 @@ Here's the hard way. You can type out your list of attributes in Racket format a
@repl-output{'(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:
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 symbolstring 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:
@codeblock|{
#lang pollen
@ -600,7 +600,7 @@ Racket arguments can be any valid Racket expressions. For instance, this will al
@repl-output{'(title ((class "42") (id "first")) "The Beginning of the End")}
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}:
Since Pollen commands are really just Racket arguments underneath, you can use those too. Here, we'll define a variable called @code{name} and use it in the Racket arguments of @code{title}:
@codeblock|{
#lang pollen
@ -610,7 +610,7 @@ Since Pollen commands are really just Racket arguments underneath, you can use t
@repl-output{'(title ((class "read") (id "Brennan")) "The Beginning of the End")}
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:
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 @code{h1 ... h6} tags, you want to consolidate them into one command called @code{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:
@codeblock|{
#lang pollen
@ -685,7 +685,7 @@ Instead of this:
@repl-output{'(div "Roomy!\n\nI agree.")}
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:
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 @code{jejune} function only accepts a single argument. It will work with a single-line text argument, because that produces a single string:
@codeblock|{
#lang pollen
@ -715,7 +715,7 @@ the expected number of arguments does not match the given number
   "\n"
   "chastened"}
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 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 @code{jejune} with a rest argument, we can fix the problem:
@codeblock|{
#lang pollen
@ -731,4 +731,4 @@ The answer is to use a @italic{rest argument} in the function, which takes the `
@section{Further reading}
The Pollen language is a variant of Racket's own text-processing language, called Scribble. Thus, 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, see @secref["reader" #:doc '(lib "scribblings/scribble/scribble.scrbl")] in the Scribble documentation.
The Pollen language is a variant of Racket's own text-processing language, called Scribble. Thus, most things that can be done with Scribble syntax can also be done with Pollen syntax. For the sake of clarity & brevity, I've only shown you the highlights here. But if you want the full story, see @secref["reader" #:doc '(lib "scribblings/scribble/scribble.scrbl")] in the Scribble documentation.

@ -43,7 +43,7 @@ This function doesn't do much on its own. Rather, it provides the hooks upon whi
Recall that in Pollen, all @secref["tags-are-functions"]. By default, the @racket[_tagged-xexpr] from a source file is tagged with @racket[root]. So the typical way to use @racket[decode] is to attach your decoding functions to it, and then define @racket[root] to invoke your @racket[decode] function. Then it will be automatically applied to every @racket[doc] during compile.
For instance, here's how @racket[decode] is attached to @racket[root] in @italic{Butterick's Practical Typography}. There's not much to it —
For instance, here's how @racket[decode] is attached to @racket[root] in @link["http://practicaltypography.com"]{@italic{Butterick's Practical Typography}}. There's not much to it —
@racketblock[
(define (root . items)

@ -23,7 +23,7 @@ Pollen handles six kinds of source files:
@bold{Scribble}, with file extension @code[(format ".~a" world:scribble-source-ext)].
For each kind of Pollen source file, the corresponding output file is generated by removing the extension from the name of the source file. So the preprocessor source file @code["default.css.pp"] would become @code["default.css"]. Scribble files work differently — the corresponding output file is the source file but with an @racket[html] extension rather than @racket[scrbl]. So @code["pollen.scrbl"] would become @code["pollen.html"].
For each kind of Pollen source file, the corresponding output file is generated by removing the extension from the name of the source file. So the preprocessor source file @filepath{default.css.pp} would become @filepath{default.css}. Scribble files work differently — the corresponding output file is the source file but with an @filepath{html} extension rather than @filepath{scrbl}. So @filepath["pollen.scrbl"] would become @filepath["pollen.html"].
@deftogether[
(@defproc[

@ -16,9 +16,9 @@
The Pollen language is divided into variants, or @italic{dialects}, that are tailored to suit each of the core source formats.
These dialects can be invoked one of two ways: either by invoking a specific dialect in the first line of the file (also known as the @litchar{#lang} line), or by using the generic @litchar{#lang pollen} as the first line, and then the correct dialect will be automatically selected based on the source file extension.
These dialects can be invoked one of two ways: either by invoking a specific dialect in the first line of the file (also known as the @tt{#lang} line), or by using the generic @tt{#lang pollen} as the first line, and then the correct dialect will be automatically selected based on the source file extension.
If the @litchar{#lang} line specifies a dialect different from the one specified by the file extension, the @litchar{#lang} line will take precedence.
If the @tt{#lang} line specifies a dialect different from the one specified by the file extension, the @tt{#lang} line will take precedence.
For ease of use, the behavior of the Pollen language departs from the standard Racket language in several ways. The differences are noted below.
@ -40,11 +40,11 @@ There are no undefined commands in Pollen. If a command has not already been def
By default, every Pollen source file exports two identifiers, which you can access by using the source file with @racket[require]:
@racket['doc] contains the output of the file. The type of output depends on the source format (documented below).
@racket[doc] contains the output of the file. The type of output depends on the source format (documented below).
@racket['metas] is a hash of keyvalue pairs with extra information that is extracted from the source. These @racket['metas] will always contain the key @racket['here-path], which returns a string representation of the full path to the source file. Beyond that, the only @racket['metas] are the ones that are specified within the source file (see the source formats below for more detail on how to specify metas).
@racket[metas] is a hash of keyvalue pairs with extra information that is extracted from the source. These @racket[metas] will always contain the key @racket['here-path], which returns a string representation of the full path to the source file. Beyond that, the only @racket[metas] are the ones that are specified within the source file (see the source formats below for more detail on how to specify metas).
@margin-note{The Pollen rendering system relies on these two identifiers, but otherwise doesn't care how they're generated. Meaning, the code inside your Pollen source file could be @litchar{#lang racket} or @litchar{#lang whatever}. As long as you manually @racket[provide] those two identifiers and follow the usual file-naming convention, your source file will be usable.}
@margin-note{The Pollen rendering system relies on these two identifiers, but otherwise doesn't care how they're generated. Meaning, the code inside your Pollen source file could be @tt{#lang racket} or @tt{#lang whatever}. As long as you manually @racket[provide] those two identifiers and follow the usual file-naming convention, your source file will be usable.}
@bold{How is this different from Racket?} In Racket, you must explicitly @racket[define] and then @racket[provide] any values you want to export.
@ -55,9 +55,9 @@ Any value or function that is defined within the source file using @racket[defin
@bold{How is this different from Racket?} In Racket, you must explicitly @racket[provide] any values you want to export. Unlike Racket, every Pollen source file impliedly uses @racket[(provide (all-defined-out))].
@subsection{The @code{@(format "~a" world:directory-require)} file}
@subsection{The @filepath{directory-require.rkt} file}
If a file called @code{@(format "~a" world:directory-require)} exists in the same directory with a source file, it's automatically imported when the source file is compiled.
If a file called @filepath{directory-require.rkt} exists in the same directory with a source file, it's automatically imported when the source file is compiled.
@bold{How is this different from Racket?} In Racket, you must explicitly import files using @racket[require].
@ -74,7 +74,7 @@ _...source...
_...source...
]
When no dialect is explicitly specified by either the @litchar{#lang} line or the file extension, Pollen will default to using the preprocessor dialect. For instance, this file will be treated as preprocessor source:
When no dialect is explicitly specified by either the @tt{#lang} line or the file extension, Pollen will default to using the preprocessor dialect. For instance, this file will be treated as preprocessor source:
@racketmod[#:file "test.yyz" pollen
_...source...
@ -99,7 +99,7 @@ _...source...
_...source...
]
The output of the Markdown dialect, provided by @racket['doc], is a tagged X-expression.
The output of the Markdown dialect, provided by @racket[doc], is a tagged X-expression.
@subsection{Markup (@(format ".~a" world:markup-source-ext) extension)}
@ -115,7 +115,7 @@ _...source...
_...source...
]
The output of the Pollen markup dialect, provided by @racket['doc], is a tagged X-expression.
The output of the Pollen markup dialect, provided by @racket[doc], is a tagged X-expression.
@subsection{Pagetree (@(format ".~a" world:pagetree-source-ext) extension)}
@ -133,14 +133,14 @@ _...source...
The output of the pagetree dialect, provided by @racket['doc], is a @racket[pagetree?] that is checked for correctness using @racket[validate-pagetree].
The output of the pagetree dialect, provided by @racket[doc], is a @racket[pagetree?] that is checked for correctness using @racket[validate-pagetree].
@section{Utility formats}
These aren't source formats because they don't contain a @litchar{#lang pollen} line. But for convenience, they get special handling by the Pollen project server.
These aren't source formats because they don't contain a @tt{#lang pollen} line. But for convenience, they get special handling by the Pollen project server.
@ -151,6 +151,6 @@ Scribble files are recognized by the project server and can be compiled and prev
@subsection{Null (@(format ".~a" world:null-source-ext) extension)}
Files with the null extension are simply rendered as a copy of the file without the extension, so @code{index.html.p} becomes @code{index.html}.
Files with the null extension are simply rendered as a copy of the file without the extension, so @filepath{index.html.p} becomes @filepath{index.html}.
This can be useful you're managing your project with git. Most likely you'll want to ignore @code{*.html} and other file types that are frequently regenerated by the project server. But if you have isolated static files — for instance, a @code{index.html} that doesn't have source associated with it — they'll be ignored too. You can cure this problem by appending the null extension to these static files, so they'll be tracked in your source system without actually being source files.
This can be useful you're managing your project with git. Most likely you'll want to ignore @filepath{*.html} and other file types that are frequently regenerated by the project server. But if you have isolated static files — for instance, a @filepath{index.html} that doesn't have source associated with it — they'll be ignored too. You can cure this problem by appending the null extension to these static files, so they'll be tracked in your source system without actually being source files.

@ -10,11 +10,14 @@
@link["http://download.racket-lang.org/"]{Install Racket}, which includes DrRacket.
From the command line, install Pollen:
@verbatim{raco pkg install pollen}
Linux and Mac users: update your @envvar{PATH} to include @filepath{/path-to-new-racket-directory/bin/}. Then you'll have access to @exec{raco} (see @other-doc['(lib "scribblings/raco/raco.scrbl")]).
After that, you can update the package from the command line:
@verbatim{raco pkg update pollen}
Mac users who haven't done this before: @link["http://architectryan.com/2012/10/02/add-to-the-path-on-mac-os-x-mountain-lion/"]{these instructions} are simple and accurate.
Windows users, I'll trust you to convert @exec{raco} into the appropriate command for your system — assuming defaults, it's likely to be @filepath{C:\Program Files\Racket\raco} (include the surrounding quotes in the command).
Then, from the command line, install Pollen:
@commandline{raco pkg install pollen}
Windows users, I'll trust you to convert @tt{raco} into the appropriate command for your system — assuming defaults, it's likely to be @tt{"C:\Program Files\Racket\raco"} (include the surrounding quotes in the command).
After that, you can update the package from the command line:
@commandline{raco pkg update pollen}

@ -331,7 +331,7 @@ Return the pagenode immediately after @racket[_p]. For @racket[next*], return al
[pagetree pagetree?])
list?
]
Convert @racket[_pagetree] to a simple list. Equivalent to a pre-order depth-first traversal of @racket[_pagetree].
Convert @racket[_pagetree] to a simple list. Uses @racket[flatten], and is thus equivalent to a pre-order depth-first traversal of @racket[_pagetree].
@defproc[
(in-pagetree?

@ -17,7 +17,7 @@
Pollen is a publishing system that helps authors create beautiful and functional web-based books. Pollen includes tools for writing, designing, programming, testing, and publishing.
I used Pollen to create my book @link["http://practicaltypography.com"]{Butterick's Practical Typography}. Sure, go take a look. Is it better than the last digital book you encountered? Yes it is. Would you like your book to look like that? If so, keep reading.
I used Pollen to create my book @link["http://practicaltypography.com"]{@italic{Butterick's Practical Typography}}. Sure, go take a look. Is it better than the last digital book you encountered? Yes it is. Would you like your book to look like that? If so, keep reading.
At the core of Pollen is an argument:
@itemlist[#:style 'unordered

@ -1,6 +1,6 @@
#lang scribble/manual
@(require "mb-tools.rkt" (for-label racket))
@(require "mb-tools.rkt" (for-label racket pollen/template))
@title[#:tag "quick-tour"]{Quick tour}
@ -15,7 +15,7 @@ Open a new document. Change the top line to:
#lang pollen
}
The first line of every Pollen source file will start with @tt{#lang pollen}.
The first line of every Pollen source file will start with @code{#lang pollen}.
@section{Running a source file}
@ -33,7 +33,7 @@ Click the @onscreen{Run} button. In the interactions window, you'll see the resu
Not bad. I think Pollen just won the @link["http://en.wikipedia.org/wiki/List_of_Hello_world_program_examples"]{Hello World Tournament}.
You can work with Pollen source files in any text editor. The key advantage of DrRacket is that you can preview the results by running the file.
You can work with Pollen source files in any text editor, including Emacs or Sublime Text. The key advantage of DrRacket is that you can preview the results by running the file.
Try editing your source file:
@ -51,7 +51,7 @@ Breakfast in America
Take the Long Way Home
}
We won't do it a third time. You get the point — any plain text is valid within a Pollen source file, and gets printed as is. You never have to perform the incantations of typical programming languages:
We won't do it a third time. You get the point — any plain text is valid within a Pollen source file, and gets printed as typed. What you write is what you get. You never have to perform the incantations often required by other programming languages:
@terminal{
print "Hello world"
@ -59,12 +59,10 @@ document.write('Hello world');
printf("Hello world");
}
In Pollen, what you write is what you get.
@section{Naming, saving, and rendering a source file}
Save this file with the name @tt{hello.txt.pp} in any convenient directory. The desktop is fine.
Save this file as @filepath{hello.txt.pp} in any convenient directory. The desktop is fine.
Open a terminal window and issue two commands:
@ -72,9 +70,9 @@ Open a terminal window and issue two commands:
> cd [directory containing your file]
> raco pollen render hello.txt.pp}
@margin-note{Windows users, I'll trust you to convert @tt{raco} into the appropriate command for your system — assuming defaults, it's likely to be @tt{"C:\Program Files\Racket\raco"} (include the surrounding quotes in the command).}
@margin-note{Windows users, I'll trust you to convert @exec{raco} into the appropriate command for your system — assuming defaults, it's likely to be @filepath{C:\Program Files\Racket\raco} (include the surrounding quotes in the command).}
After a moment, a new file will appear called @tt{hello.txt}. Let's see what's in it:
After a moment, a new file will appear called @filepath{hello.txt}. Let's see what's in it:
@terminal{
> cat hello.txt
@ -87,14 +85,14 @@ You've just learned three things:
@itemlist[
@item{Pollen commands in the terminal begin with @tt{raco pollen}, followed by a specific command (in this case @tt{render}) and sometimes an argument (in this case @tt{hello.txt.pp}).}
@item{Pollen commands in the terminal begin with @exec{raco pollen}, followed by a specific command (in this case @exec{render}) and sometimes an argument (in this case @exec{hello.txt.pp}).}
@item{The @tt{render} command takes the ouput from your source file — meaning, the result you previewed in DrRacket in the previous step — and saves it to another file.}
@item{The @exec{render} command takes the ouput from your source file — meaning, the result you previewed in DrRacket in the previous step — and saves it to another file.}
@item{The name of the output file is the same as the source file, minus the Pollen source extension. So @tt{hello.txt.pp} becomes @tt{hello.txt}.}
@item{The name of the output file is the same as the source file, minus the Pollen source extension. So @filepath{hello.txt.pp} is rendered to a file called @filepath{hello.txt}.}
]
Try editing the text in the @tt{hello.txt.pp} source file and running @tt{raco pollen render hello.txt.pp} again. The old @tt{hello.txt} will be replaced with a new one showing your changes. And so you've learned a fourth thing:
Try editing the text in @filepath{hello.txt.pp} and running @commandline{raco pollen render hello.txt.pp} again. The old @filepath{hello.txt} will be replaced with a new one showing your changes. Thus, now you've learned a fourth thing:
@itemlist[
@item{Pollen works by rendering output files from source files. Output files can be overwritten. Therefore, you should only make edits to your source files.}
@ -103,9 +101,9 @@ Try editing the text in the @tt{hello.txt.pp} source file and running @tt{raco p
@section{The project server}
You've just learned two ways to see the output of a Pollen source file — first, you ran it in DrRacket. Then, you rendered it to an output file.
You just saw two ways to view the output of a Pollen source file — first, you ran it in DrRacket. Second, you rendered it to an output file.
Now here's a third: the Pollen project server. Here's how you start it. Return to your terminal window and issue two commands:
Now here's a third: the Pollen project server. To start the project server, return to your terminal and issue two commands:
@terminal{
> cd [directory containing your hello.txt.pp file]
@ -120,9 +118,9 @@ Project server is http://localhost:8080 (Ctrl-C to exit)
Project dashboard is http://localhost:8080/index.ptree
Ready to rock}
Open a web browser and point it at @link-tt{http://localhost:8080/index.ptree}. The top of the window will say @tt{Project root}. Below that will be a listing of the files in the directory.
Open a web browser and point it at @link-tt{http://localhost:8080/index.ptree}. The top line of the window will say @tt{Project root} and show the name of the starting directory. Below that will be a listing of the files in the directory.
Among them will be @tt{hello.txt}, with a greyed-out @tt{.pp} extension. Click on it, and you'll be taken to @link-tt{http://localhost:8080/hello.txt}, where you'll see:
Among them will be @filepath{hello.txt}, with a greyed-out @filepath{.pp} extension. Click on it, and you'll be taken to @link-tt{http://localhost:8080/hello.txt}, where you'll see:
@terminal{
Goodbye Stranger
@ -147,7 +145,7 @@ Mean Street
Panama
Hear About It Later}
Notice what happened — the Pollen project server dynamically regenerated the output file (@tt{hello.txt}) from the source file (@tt{hello.txt.pp}) after you edited the source. If you like, try making some more changes to @tt{hello.txt.pp}, and reloading the browser to see the updates in @tt{hello.txt}.
Notice what happened — the Pollen project server dynamically regenerated the output file (@filepath{hello.txt}) from the source file (@filepath{hello.txt.pp}) after you edited the source. If you like, try making some more changes to @filepath{hello.txt.pp}, and reloading the browser to see the updates in @filepath{hello.txt}.
@section{Intermission}
@ -160,7 +158,7 @@ For the rest of this tutorial, I recommend keeping two windows on screen: a web-
A @italic{preprocessor} is a tool for making systematic, automated changes to a source file before the main processing happens. A preprocessor can also be used to add programming logic to files that otherwise don't support it.
For instance, HTML. In DrRacket, create a new file called @tt{margin.html.pp} in your project directory:
For instance, HTML. In DrRacket, create a new file called @filepath{margin.html.pp} in your project directory:
@fileblock["margin.html.pp"
@codeblock{
@ -170,11 +168,11 @@ For instance, HTML. In DrRacket, create a new file called @tt{margin.html.pp} in
</body>
}]
The ``@tt{.pp}'' file extension — which you saw before, with @tt{hello.txt.pp} — stands for ``Pollen preprocessor.'' You can use the Pollen preprocessor with any text-based file by inserting @tt{#lang pollen} as the first line, and adding the @tt{.pp} file extension.
The @filepath{.pp} file extension — which you saw before, with @filepath{hello.txt.pp} — stands for ``Pollen preprocessor.'' You can use the Pollen preprocessor with any text-based file by inserting @code{#lang pollen} as the first line, and adding the @filepath{.pp} file extension.
But for now, go to your @link["http://localhost:8080/index.ptree"]{project dashboard} and click on @link["http://localhost:8080/margin.html"]{@tt{margin.html}}. You should see a black box containing the text ``5em is the inset.''
But for now, go to your @link["http://localhost:8080/index.ptree"]{project dashboard} and click @link["http://localhost:8080/margin.html"]{@filepath{margin.html}}. You should see a black box containing the text ``5em is the inset.''
Let's suppose you want to change the inset to 30%. Without a preprocessor, you'd have to search & replace each value. But with a preprocessor, you can move the inset value into a variable, and update it from that one location. So first, introduce a variable called @tt{my-inset} by using the @racket[define] command:
Suppose you want to change the inset to 30%. Without a preprocessor, you'd have to search & replace each value. But with a preprocessor, you can move the inset value into a variable, and update it from that one location. So first, introduce a variable called @code{my-inset} by using the @racket[define] command:
@fileblock["margin.html.pp"
@codeblock{
@ -185,16 +183,16 @@ Let's suppose you want to change the inset to 30%. Without a preprocessor, you'd
</body>
}]
The ◊ character is called a @italic{lozenge}. In Pollen, the lozenge is a special character that marks anything Pollen should interpret as a command (rather than plain text).
The @code{} character is called a @italic{lozenge}. In Pollen, the lozenge is a special character used to denote anything that Pollen should interpret as a command (rather than plain text).
How to type a lozenge:
@margin-note{How to type a lozenge:
@(linebreak)@bold{Mac}: option + shift + V
@(linebreak)@bold{Windows}: holding down alt, type 9674 on the num pad
@(linebreak)@bold{Ubuntu}: ctrl + shift + U, then 25CA
@(linebreak)@bold{Ubuntu}: ctrl + shift + U, then 25CA}
The whole command @tt{◊define[my-inset]{30%}} means ``create a variable called @tt{my-inset} and give it the value @tt{30%}.''
Thus, the command @code{◊define[my-inset]{30%}} means ``create a variable called @code{my-inset} and give it the value @code{30%}.''
Then put the variable into the HTML like so, this time using the ◊ character with the variable name in the two places the value appears:
Now you can insert the variable into the HTML like so, this time using the ◊ character with the variable name in the two places the value needs to appear:
@fileblock["margin.html.pp"
@codeblock{
@ -205,17 +203,17 @@ Then put the variable into the HTML like so, this time using the ◊ character w
</body>
}]
Now reload @link["http://localhost:8080/margin.html"]{@tt{margin.html}}. You'll see that the size of the margin has changed (because of the change to the @tt{style} attribute) and so has the text of the HTML. If you like, try editing @tt{my-inset} with different values and reloading the page. You can also try using @racket[define] to create another variable (for instance, to change the color of the box border).
Now reload @link["http://localhost:8080/margin.html"]{@filepath{margin.html}}. You'll see that the size of the margin has changed (because of the change to the @code{style} attribute) and so has the text of the HTML. If you like, try editing @code{my-inset} with different values and reloading the page. You can also try using @racket[define] to create another variable (for instance, to change the color of the box border).
Still, this is the tiniest tip of the iceberg. The Pollen preprocessor gives you access to everything in the Racket programming language — including math functions, text manipulation, and so on.
Still, this is the tiniest tip of the iceberg. The Pollen preprocessor gives you access to everything in the Racket programming language — including string manipulation, math functions, and so on.
@section{Markdown mode}
When used as a preprocessor, Pollen's rule is that what you write is what you get. But if you're targeting HTML, who wants to type out all those @tt{<tedious>tags</tedious>}? You can make Pollen do the heavy lifting by using it as a source decoder.
When used as a preprocessor, Pollen's rule is that what you write is what you get. But if you're targeting HTML, who wants to type out all those @code{<tedious>tags</tedious>}? You can make Pollen do the heavy lifting by using an @defterm{authoring mode}.
For instance, Markdown mode. Markdown is a simplified @link["https://daringfireball.net/projects/markdown/"]{notation system} for HTML. You can use Pollen's Markdown decoder by inserting @tt{#lang pollen} as the first line, and adding the @tt{.pmd} file extension.
For instance, Markdown authoring mode. Markdown is a simplified @link["https://daringfireball.net/projects/markdown/"]{notation system} for HTML. You can use Markdown authoring mode in Pollen by inserting @tt{#lang pollen} as the first line, and adding the @filepath{.pmd} file extension.
Try it. In DrRacket, create a file with the following lines and save it as @tt{downtown.html.pmd}:
Try it. In DrRacket, create a file with the following lines and save it as @filepath{downtown.html.pmd}:
@fileblock["downtown.html.pmd"
@codeblock{
@ -229,7 +227,7 @@ Pollen + Markdown
+ [search for Racket](https://google.com/search?q=racket)
}]
As before, go to the @link["http://localhost:8080/index.ptree"]{dashboard} for the project server. This time, click the link for @link["http://localhost:8080/downtown.html"]{@tt{downtown.html}}. You'll see something like this:
As before, go to the @link["http://localhost:8080/index.ptree"]{dashboard} for the project server. This time, click the link for @link["http://localhost:8080/downtown.html"]{@filepath{downtown.html}}. You'll see something like this:
@browser{
@ -241,9 +239,9 @@ As before, go to the @link["http://localhost:8080/index.ptree"]{dashboard} for t
}
As usual, you're welcome to edit @tt{downtown.html.pmd} and then refresh the web browser to see the changes.
As usual, you're welcome to edit @filepath{downtown.html.pmd} and then refresh the web browser to see the changes.
In Markdown mode, you can still embed Pollen commands within the source as you did in preprocessor mode. Just keep in mind that your commands need to produce valid Markdown (as opposed to raw HTML). For instance, use @tt{define} to create a variable called @tt{metal}, and insert it into the Markdown:
In Markdown authoring mode, you can still embed Pollen commands within the source as you did in preprocessor mode. Just keep in mind that your commands need to produce valid Markdown (as opposed to raw HTML). For instance, use @racket[define] to create a variable called @code{metal}, and insert it into the Markdown:
@fileblock["downtown.html.pmd"
@codeblock{
@ -258,7 +256,7 @@ Pollen + ◊metal
+ [search for ◊metal](https://google.com/search?q=◊metal)
}]
Refresh @link["http://localhost:8080/downtown.html"]{@tt{downtown.html}} in the browser:
Refresh @link["http://localhost:8080/downtown.html"]{@filepath{downtown.html}} in the browser:
@browser{
@bold{@larger{Pollen + Plutonium}}
@ -269,18 +267,21 @@ Refresh @link["http://localhost:8080/downtown.html"]{@tt{downtown.html}} in the
}
Pollen is handling two tasks here: interpreting the commands in the source, and then converting the Markdown to HTML. But what if you wanted to use Pollen as a preprocessor that outputs a Markdown file? No problem — just change the source name from @tt{downtown.html.pmd} to @tt{downtown.md.pp}. Changing the extension from @tt{.pmd} to @tt{.pp} switches Pollen from Markdown mode back to preprocessor mode. And changing the base name from @tt{downtown.html} to @tt{downtown.md} updates the name of the output file.
Pollen is handling two tasks here: interpreting the commands in the source, and then converting the Markdown to HTML. (For more, see @secref["Markdown_authoring_mode"
#:doc '(lib "pollen/scribblings/pollen.scrbl")].)
But what if you wanted to use Pollen as a preprocessor that outputs a Markdown file? No problem — just change the source name from @filepath{downtown.html.pmd} to @filepath{downtown.md.pp}. Changing the extension from @filepath{.pmd} to @filepath{.pp} switches Pollen from Markdown mode back to preprocessor mode. And changing the base name from @filepath{downtown.html} to @filepath{downtown.md} updates the name of the output file.
@section{Markup mode}
@section{Pollen markup}
If all you need to do is produce basic HTML, Markdown is great. But if you need to do semantic markup or other kinds of custom markup, it's not flexible enough.
In that case, you can use Pollen markup mode. To use Pollen markup, insert @tt{#lang pollen} as the first line of your source file, and add a @tt{.pm} file extension.
In that case, you can use another Pollen authoring mode, called @defterm{Pollen markup}. To use Pollen markup, insert @code{#lang pollen} as the first line of your source file, and add a @filepath{.pm} file extension.
Compared to Markdown mode, Pollen markup mode is wide open. Markdown mode gives you a limited set of formatting tools (i.e., the ones supported by Markdown). But in markup mode, you can use any tags you want. Markdown mode decodes the source in a fixed way (i.e., with the Markdown decoder). But markup mode lets you build any decoder you want.
Compared to Markdown authoring mode, Pollen markup is wide open. Markdown authoring mode limits you to the formatting commands supported by Markdown. With Pollen markup, by contrast, you can use any tags you want. Markdown mode decodes the source in a fixed way (i.e., with the Markdown decoder). But Pollen markup lets you build any decoder you want.
Let's convert our Markdown example into Pollen markup. Marking up content is simple: insert the lozenge character (@tt{◊}) followed by the name of the tag (@tt{◊tag}), followed by the content of the tag in curly braces (@tt{◊tag{content}}). In DrRacket, create a new file called @tt{uptown.html.pm} as follows:
To see how this works, let's convert our Markdown example into Pollen markup. Marking up content is simple: insert the lozenge character (@code{◊}) followed by the name of the tag (@code{◊tag}), followed by the content of the tag in curly braces (@code{◊tag{content}}). In DrRacket, create a new file called @filepath{uptown.html.pm} as follows:
@ -295,7 +296,7 @@ Let's convert our Markdown example into Pollen markup. Marking up content is sim
◊item{◊link["https://google.com/search?q=racket"]{search for Racket}}
}}]
Go to the @link["http://localhost:8080/index.ptree"]{project dashboard} and click on @link["http://localhost:8080/uptown.html"]{@tt{uptown.html}}. You'll see something like this:
Go to the @link["http://localhost:8080/index.ptree"]{project dashboard} and click on @link["http://localhost:8080/uptown.html"]{@filepath{uptown.html}}. You'll see something like this:
@browser{
Pollen markup You @bold{wanted} it — you @italic{got} it. https://google.com/search?q=racketsearch for Racket
@ -303,9 +304,9 @@ Pollen markup You @bold{wanted} it — you @italic{got} it. https://google.com/
That's not right. What happened?
We marked up the source using a combination of standard HTML tags (@tt{strong}, @tt{em}) and nonstandard ones (@tt{headline}, @tt{items}, @tt{item}, @tt{link}). This is valid Pollen markup. (In fact, if you look at @link["http://localhost:8080/out/markup.html"]{the generated source}, you'll see that they didn't disappear.) But since we're targeting HTML, we need to convert our custom tags into valid HTML tags.
We marked up the source using a combination of standard HTML tags (@code{strong}, @code{em}) and nonstandard ones (@code{headline}, @code{items}, @code{item}, @code{link}). This is valid Pollen markup. (In fact, if you look at @link["http://localhost:8080/out/markup.html"]{the generated source}, you'll see that they didn't disappear.) But since we're targeting HTML, we need to convert our custom tags into valid HTML tags.
For that, we'll make a special file called @tt{directory-require.rkt}. This is a file in the standard Racket language that provides helper functions to decode the source. The definitions won't make sense yet. But this is the quick tour, so all you need to do is copy, paste, and save:
For that, we'll make a special file called @filepath{directory-require.rkt}. This is a file in the standard Racket language that provides helper functions to decode the source. The definitions won't make sense yet. But this is the quick tour, so all you need to do is copy, paste, and save:
@fileblock["directory-require.rkt"
@codeblock{
@ -319,7 +320,7 @@ For that, we'll make a special file called @tt{directory-require.rkt}. This is a
(define (link url text) `(a [[href ,url]] ,text))
}]
Return to the @link["http://localhost:8080/index.ptree"]{project dashboard} and click on @link["http://localhost:8080/uptown.html"]{@tt{uptown.html}}. Now you'll get the right result:
Return to the @link["http://localhost:8080/index.ptree"]{project dashboard} and click on @link["http://localhost:8080/uptown.html"]{@filepath{uptown.html}}. Now you'll get the right result:
@browser{
@bold{@larger{Pollen markup}}
@ -329,17 +330,18 @@ Return to the @link["http://localhost:8080/index.ptree"]{project dashboard} and
       • @link["https://google.com/search?q=racket"]{search for Racket}
}
Markup mode takes a little more effort to set up. But it also allows you more flexibility. If you want to do semantic markup, or convert your source into multiple output formats, or handle complex page layouts — it's the way to go.
Pollen markup takes a little more effort to set up. But it also allows you more flexibility. If you want to do semantic markup, or convert your source into multiple output formats, or handle complex page layouts — it's the way to go. (For more, see @seclink["Writing_with_Pollen_markup"
#:doc '(lib "pollen/scribblings/pollen.scrbl")].)
@section{Templates}
The HTML pages we just made looked pretty dull. For the last stop on the quick tour, let's fix that.
Pollen source files that are written in Markdown or markup mode (i.e., @tt{.pmd} or @tt{.pm} files) are rendered with a @italic{template}. A template is not a standalone Pollen source file. It's a file of the output type — e.g., CSS, HTML, XML — where you put the stuff that needs to be consistent between output files. The template also contains @italic{template variables} that mark where values from the Pollen source file should be inserted.
Pollen source files that are written in an authoring mode (i.e., @filepath{.pmd} or @filepath{.pm} files) are rendered with a @defterm{template}. A template is not a standalone Pollen source file. It's a file of the output type — e.g., CSS, HTML, XML — where you put the stuff that needs to be consistent between output files. The template also contains @defterm{template variables} that mark where values from the Pollen source file should be inserted.
When it needs a template, Pollen first looks for a file in the project directory named @tt{template.[output extension of source]}. For @tt{uptown.html.pm}, the output extension will be @tt{.html}, thus Pollen will look for @tt{template.html}.
When it needs a template, Pollen first looks for a file in the project directory named @filepath{template.[output extension of source]}. Thus, for @filepath{uptown.html.pm}, the output extension will be @filepath{.html}, and Pollen will first look for @filepath{template.html}.
So let's create @tt{template.html}. Make a new file that with the following lines and save it to the same directory as @tt{uptown.html.pm}:
So let's create @filepath{template.html}. Make a new file that with the following lines and save it to the same directory as @filepath{uptown.html.pm}:
@fileblock["template.html"
@codeblock{
@ -353,9 +355,9 @@ This file is ◊here
</div></body></html>
}]
This is a simple HTML file that should look familiar, except for the two template variables. The first, @tt{here}, contains the name of the current source file. As before, the lozenge character marks it as a Pollen command rather than text, so you write it as @tt{◊here}. The other command, @tt{◊->html{◊doc}}, takes the content from the source file, which is contained in a variable called @tt{doc}, and converts it to HTML with a Pollen function called @tt{->html}.
This is a simple HTML file that should look familiar, except for the two template variables. The first, @code{here}, contains the name of the current source file. As before, the lozenge character marks it as a Pollen command rather than text, so you write it as @code{◊here}. The other command, @code{◊->html{◊doc}}, takes the content from the source file, which is contained in a variable called @code{doc}, and converts it to HTML with a Pollen function called @racket[->html].
Go back to your web browser and reload @link["http://localhost:8080/uptown.html"]{@tt{uptown.html}}. (Or @link["http://localhost:8080/downtown.html"]{@tt{downtown.html}} — both will work.) The page will be rendered with the new @tt{template.html}. As before, you can edit the template or the source and the project server will dynamically update the output file.
Return to your web browser and reload @link["http://localhost:8080/uptown.html"]{@filepath{uptown.html}}. (Or @link["http://localhost:8080/downtown.html"]{@filepath{downtown.html}} — both will work.) The page will be rendered with the new @filepath{template.html}. As before, you can edit the template or the source and the project server will dynamically update the output file.
@section{PS for Scribble users}
@ -365,7 +367,7 @@ Pollen can also be used as a dynamic preview server for Scribble files. From you
> cd [directory containing your Scribble files]
> raco pollen start}
On the @link["http://localhost:8080/index.ptree"]{project dashboard}, you'll see your @tt{filename.scrbl} files listed as @tt{filename.html}. This may not represent the ultimate structure of your Scribble project — you may end up combining multiple Scribble source files into one HTML file, or making multiple HTML files from one Scribble source — but it's handy for checking your work as you go.
On the @link["http://localhost:8080/index.ptree"]{project dashboard}, you'll see your @filepath{filename.scrbl} files listed as @filepath{filename.html}. By clicking on these names, you can get a preview rendering of the Scribble source file. This may not represent the ultimate structure of your Scribble project — you may end up combining multiple Scribble source files into one HTML file, or making multiple HTML files from one Scribble source — but it's handy for checking your work as you go.
@ -379,14 +381,16 @@ Now you've seen the key features of Pollen. What do you think?
@item{@italic{``What about pairing a Python template system and Python web server?''} Good idea. I even tried it. But Python template systems don't offer you Python — they offer you limited dialects that aren't very Pythonic. Also, Python's handing of XML-ish data is cumbersome.}
@item{@italic{``Haven't you heard of Jekyll?''} Yes. If everything you need to write is expressible in Markdown, it's great. If you need more than that, you're stuck.}
@item{@italic{``Haven't you heard of Jekyll?''} Yes. If everything you need to write is expressible in Markdown, it's great. If you need more than that, you're stuck. (See also @seclink["The_case_against_Markdown"]{my objections to Markdown for books}.)}
@item{@italic{``Sounds a lot like LaTeX. Why not use that?''} Also a good idea. LaTeX gets a lot of things right. But it wasn't designed for web publishing.}
@item{@italic{``Eh, there are plenty of adequate options. Why should I learn a system written in Racket, which I've never used?''} A salient objection. It's also the question I asked myself before I committed to Racket. But publishing systems that are author- or designer-friendly tend to be programmer-hostile, and vice versa. Racket is the only language I found that could meet my requirements.}
@item{@italic{``Eh, there are plenty of adequate options. Why should I learn a system written in Racket, which I've never used?''} A salient objection. It's also the question I asked myself before I committed to Racket. But publishing systems that are author- or designer-friendly tend to be programmer-hostile, and vice versa. Racket is the only language I found that could meet my requirements. (For more about the benefits of Racket, see @link["http://practicaltypography.com/why-racket-why-lisp.html"]{Why Racket? Why Lisp?})}
]
But don't take my word for it. The rest of this documentation will show you the useful and sophisticated things you can do with Pollen. If there's another tool that suits you better, great. Keep in mind that I didn't make Pollen because I'm a programmer. I'm a writer who wants to make electronic books that are better than the ones we have now. And for that, I needed a better tool.
But don't take my word for it. The rest of this documentation will show you the useful and sophisticated things you can do with Pollen. If there's another tool that suits you better, great. Keep in mind that I didn't make Pollen because I'm a programmer. I'm a writer who wants to make electronic books that are better than the ones we have now. And for that, I needed a better tool.
Now I have it.

@ -1,6 +1,6 @@
#lang scribble/manual
@(require scribble/eval pollen/world (for-label racket pollen/world))
@(require "mb-tools.rkt" scribble/eval pollen/world (for-label racket pollen/world))
@(define my-eval (make-base-eval))
@(my-eval `(require pollen pollen/file))
@ -9,7 +9,7 @@
@title[#:tag "raco-pollen"]{Using @exec{raco pollen}}
Racket provides centralized command-line options through @racket[raco] (short for @code{racket command}, see @other-doc['(lib "scribblings/raco/raco.scrbl")]).
Racket provides centralized command-line options through @exec{raco} (short for @exec{racket command}, see @other-doc['(lib "scribblings/raco/raco.scrbl")]).
Once you install Pollen, you can access the following Pollen-specific commands through @racket[raco] using the subcommand @exec{raco pollen}.
@ -17,20 +17,24 @@ Once you install Pollen, you can access the following Pollen-specific commands t
Open a terminal window and type:
@verbatim{
@terminal{
> raco pollen test}
If @racket[raco pollen] is installed correctly, you'll see:
@verbatim{raco pollen is installed correctly}
@terminal{raco pollen is installed correctly}
But if you get:
@verbatim{raco: Unrecognized command: pollen}
@terminal{raco: Unrecognized command: pollen}
You'll need to fix the problem before proceeding, most likely by reinstalling Pollen (see @racket[Installation]).
You'll need to fix the problem before proceeding, most likely by reinstalling Pollen (see @secref["Installation" #:doc '(lib "pollen/scribblings/pollen.scrbl")]).
@margin-note{Pro tip: I have an alias in my @racketfont{.bash_profile} like so: @racketfont{alias polcom=@literal{'}raco pollen@literal{'}}}
If your error is like this:
@terminal{Unrecognized command: raco}
You have a deeper problem with your Racket installation (often a misconfiguration of @code{PATH}).
@section{@racket[raco pollen]}
@ -49,18 +53,18 @@ This command can be invoked with two optional arguments.
@racket[raco pollen start _path] will start the project server in @racket[_path] rather than the current directory.
@verbatim{
@terminal{
> raco pollen start ~/path/to/project/}
@racket[raco pollen start _path _port] will start the project server in @racket[_path] using @racket[_port] rather than @racket[world:current-server-port]. This is useful if you want to have multiple project servers running simultaneously.
@verbatim{
@terminal{
> raco pollen start ~/path/to/project/
> raco pollen start ~/path/to/project/scribblings 8088}
If you want to start in the current directory but with a different port, use @litchar{.} as the path:
@verbatim{
@terminal{
> raco pollen start . 8088}
@section{@racket[raco pollen render]}
@ -73,7 +77,7 @@ This command can be invoked with extra arguments.
Alternatively, the command can take a variable number of path arguments. @racket[raco pollen render _path...] will render only the paths specified in @racket[_path...]. Consistent with the usual command-line idiom, this can be a single path, a list of paths, or a pattern:
@verbatim{
@terminal{
> raco pollen render foo.html.pm
> raco pollen render foo.html.pm bar.html.pm zam.css.pp
> raco pollen render *.html.pm}

@ -16,11 +16,11 @@
[source-path complete-path?]
[template-path (or/c #f complete-path?) #f])
bytes?]
Renders @racket[_source-path]. The rendering behavior depends on the type of source file:
Renders @racket[_source-path]. The rendering behavior depends on the type of source file (for details, see @secref["File_formats" #:doc '(lib "pollen/scribblings/pollen.scrbl")]):
A [pollen/pre] file is rendered without a template.
A @racketmodname[pollen/pre] file is rendered without a template.
A [pollen/markup] or [pollen/markdown] file is rendered with a template. If no template is provided with @racket[_template-path], Pollen finds one using @racket[get-template-for].
A @racketmodname[pollen/markup] or @racketmodname[pollen/markdown] file is rendered with a template. If no template is specified with @racket[_template-path], Pollen tries to find one using @racket[get-template-for].
Be aware that rendering with a template uses @racket[include-template] within @racket[eval]. For complex pages, it can be slow the first time. Caching is used to make subsequent requests faster.
@ -79,6 +79,9 @@ Find a template file for @racket[_source-path], with the following priority:
@item{If this key doesn't exist, or if it points to a nonexistent file, look for a default template in the project directory with the name @code[(format "~a.[output extension]" world:default-template-prefix)]. Meaning, if @racket[_source-path] is @code[(format "intro.html.~a" world:markup-source-ext)], the output path would be @code["intro.html"], so the default template would be @code[(format "~a.html" world:default-template-prefix)].}
@item{If this file doesn't exist, use the fallback template as a last resort.}]
@item{If this file doesn't exist, use the fallback template as a last resort. (See @secref["Templates"
#:tag-prefixes '("tutorial-2")
#:doc '(lib "pollen/scribblings/pollen.scrbl")].)}
]
This function is called when a template is needed, but a @racket[_template-path] argument is missing (for instance, in @racket[render] or @racket[render-to-file]).

@ -6,7 +6,7 @@
I created Pollen to overcome limitations & frustrations I repeatedly encountered with existing web-publishing tools.
If you agree with my characterization of those problems, then you'll probably like the solution that Pollen offers. If not, you probably won't.
If you agree with my characterization of those problems, then you'll probably like the solution that Pollen offers. If not, then you probably won't.
@section{Web development and its discontents}
@ -14,13 +14,13 @@ I made my first web page in 1994, shortly after the web was invented. I opened m
If you weren't around then, you didn't miss much. Everything about the web was horrible: the web browsers, the computers running the browsers, the dial-up connections feeding the browsers, and of course HTML itself. At that point, the desktop-software experience was already slick and refined. By comparison, using the web felt like banging rocks together.
That's no longer true. The web is now more than 20 years old. During that time, most parts of the web have improved dramatically — for instance, the connections are faster, the browsers are more sophisticated, the screens have more pixels.
That's no longer true. The web is now more than 20 years old. During that time, most parts of the web have improved dramatically — for instance, the connections are faster, the browsers are more sophisticated, and the screens have more pixels.
But one part has not improved: the way we make web pages. Over the years, tools promising to simplify HTML development have come and mostly gone — from @link["http://www.macobserver.com/reviews/pagemill2.shtml"]{PageMill} to @link["http://www.adobe.com/products/dreamweaver.html"]{Dreamweaver} to @link["http://wordpress.org"]{WordPress} to @link["http://jekyllrb.com"]{Jekyll}. Meanwhile, true web jocks have remained loyal to the original HTML power tool: the humble text editor.
But one part hasn't improved much: the way we make web pages. Over the years, tools promising to simplify web development have come and mostly gone — from @link["http://www.macobserver.com/reviews/pagemill2.shtml"]{PageMill} to @link["http://www.adobe.com/products/dreamweaver.html"]{Dreamweaver} to @link["http://wordpress.org"]{WordPress} to @link["http://jekyllrb.com"]{Jekyll}. Meanwhile, true web jocks have remained loyal to the original HTML power tool: the humble text editor.
In one way, this makes sense. Web pages are mostly made of text-based data — HTML, CSS, JavaScript, and so on — and the simplest way to mainpulate this data is with a text editor. While HTML and CSS are @link["http://programmers.stackexchange.com/questions/28098/why-does-it-matter-that-html-and-css-are-not-programming-languages"]{not} programming languages, they lend themselves to semantic and logical structure that's most easily expressed by editing them as text. Furthermore, text-based editing makes debugging and performance improvements easier.
But text-based editing is also limited. Though the underlying description of a web page is notionally human-readable, it's optimized to be readable by other software — namely, web browsers. HTML markup in particular is verbose and easily mistyped. And isn't it fatally dull to manage all the boilerplate, like surrounding every paragraph with @code{<p>...</p>}? Yes, it is.
But text-based editing is also limited. Though the underlying description of a web page is notionally human-readable, it's optimized to be readable by other software — namely, web browsers. HTML in particular is verbose and easily mistyped. And isn't it fatally dull to manage all the boilerplate, like surrounding every paragraph with @code{<p>...</p>}? Yes, it is.
For these reasons, much of web development should lend itself to @italic{abstraction} & @italic{automation}. Abstraction means consolidating repetitive, complex patterns into simpler, parameterized forms. Automation means avoiding the manual drudgery of generating the output files. But in practice, tools that enable this abstraction & automation have been slow to arrive, and most have come hobbled with unacceptable deficiencies.
@ -34,15 +34,15 @@ On the early web, the text-editing model was appealingly precise and quick. On s
@section{``Now you have two problems''}
What followed was a steady stream of products, frameworks, tools, and content management systems that claimed to bring a programming model to web development. Some were better than others. But none of them displaced the text editor as the preferred tool of web developers.
What followed was a steady stream of products, frameworks, tools, and content management systems that claimed to bring a programming model to web development. Some were better than others. But none of them displaced the text editor as the preferred tool of web developers. And none of them matched the power and flexibility you get from any reasonable programming language.
Why not? All these tools promised a great leap forward in solving the web-development problem. In practice, they simply redistributed the pain. I needn't bore you with enumerating the deficiencies of specific tools, because they've tended to fail in the same thematic ways:
Why not? These tools always promised a great leap forward in solving the web-development problem. In practice, however, they simply redistributed the pain. I needn't bore you by enumerating the deficiencies of specific tools, because they've tended to fail in the thematic ways:
@itemlist[
@item{@bold{No native data structure for HTML.} Core to any programming model is data structures. Good data structures make processing easy; bad ones make it hard. Even though HTML has a @link["http://www.w3.org/TR/html401/struct/global.html"]{well documented} format, rarely has it been handled within a programming system with a native, intuitive data structure. Instead, it's either been treated as a string (wrong), a tree (also wrong), or some magical parsed object. This has made working with HTML in programming environments needlessly difficult.}
@item{@bold{No native data structure for HTML.} Core to any programming model is data structures. Good data structures make processing easy; bad ones make it hard. Even though HTML has a @link["http://www.w3.org/TR/html401/struct/global.html"]{well documented} format, rarely has it been handled within a programming system with a native, intuitive data structure. Instead, it's either been treated as a string (wrong), a tree (also wrong), or some magical parsed object (really wrong). This has made working with HTML in programming environments needlessly difficult.}
@item{@bold{Mandatory separation of code, presentation, and content.} This principle has often been @link["http://alistapart.com/article/separationdilemma/"]{held out} as an ideal in web development. But it's also counterintuitive, because an HTML page naturally contains all three. If you want to separate them, your tools should let you. But if you don't, your tools shouldn't make you.}
@item{@bold{Mandatory separation of code, presentation, and content.} This principle has often been @link["http://alistapart.com/article/separationdilemma/"]{held out} as an ideal in web development. But it's also counterintuitive, because an HTML page naturally contains all three. If you want to separate them, your tools should let you. But if you don't, your tools shouldn't force you.}
@item{@bold{Compromised template languages.} It seems like every programming language has at least 10 templating systems for HTML, all of which require you to learn a new ``template language'' that offers the worst of both worlds: fewer features and different syntax than the underlying language.}
@ -57,7 +57,7 @@ I've tried a lot of these tools over the years. Some I liked. Some I didn't. Inv
In 2008, I launched a website called @link["http://typographyforlawyers.com"]{@italic{Typography for Lawyers}}. Initially, I'd conceived of it as a book. Then I thought ``no one's going to publish that.'' So it became a website, that I aimed to make as book-like as possible. But hand-editing wasn't going to be enough.
So I used @link["http://wordpress.org"]{WordPress}. The major chore became scraping out all the crap that typically lives in blog templates. Largely because of this, people @link["http://ma.tt/2010/04/typography-for-lawyers/"]{liked the site}, because it was simpler & cleaner than the usual WordPress website.
So I used @link["http://wordpress.org"]{WordPress}. The major chore became scraping out all the crap that typically lives in blog templates. It ended up looking simpler & cleaner than the usual WordPress website. Largely because of this, people @link["http://ma.tt/2010/04/typography-for-lawyers/"]{liked it}.
Eventually, a publisher offered to release it as @link["http://typo.la/amzn"]{a paperback}, which came out in 2010.
@ -75,7 +75,7 @@ Did it work? Sort of. Source code went in; web pages came out. But it was also c
I had come across Racket while researching languages suitable for HTML/XML processing. I had unexpectedly learned about the @link["http://www.defmacro.org/ramblings/lisp.html"]{secret kinship} of XML and Lisp: though XML is not a programming language, it uses a variant of Lisp syntax. Thus Lisp languages are particularly adept at handling XMLish structures. That was interesting.
After comparing some of the Lisp & Scheme variants, Racket stood out because it had a text-based dialect called Scribble. Scribble could be used to embed code within textual content. That was interesting too. Among other things, this meant Scribble could be used as a general-purpose preprocessor. So I thought I'd see if I could add it to Pollen.
After comparing some of the Lisp & Scheme variants, @link["http://practicaltypography.com/why-racket-why-lisp.html"]{Racket stood out} because it had a text-based dialect called Scribble. Scribble could be used to embed code within textual content. That was interesting too. Among other things, this meant Scribble could be used as a general-purpose preprocessor. So I thought I'd see if I could add it to Pollen.
It worked. So well, in fact, that I started thinking about whether I could reimplement other parts of Pollen in Racket. Then I started thinking about reimplementing all of it in Racket.
@ -102,20 +102,14 @@ Pollen addresses the deficiencies I experienced with other tools:
@itemlist[
@item{@bold{Yes, we have a native data structure for HTML.} Racket represents HTML structures as @italic{X-expressions}, which are a variant of the standard Racket data structure, called @italic{S-expressions}. In other words, not only is there a native representation for HTML, everything in the language is represented this way.}
@item{@bold{Yes, we have a native data structure for HTML.} Racket represents HTML structures as @secref["X-expressions" #:doc '(lib "pollen/scribblings/pollen.scrbl")], which are a variant of the standard Racket data structure, called @italic{S-expressions}. In other words, not only is there a native representation for HTML, but it's represented the same way as everything else in the language.}
@item{@bold{Flexible blending of code, presentation, and content.} Pollen is a text-based language. So a Pollen source file might have no code at all. But as a dialect of Scribble & Racket, if you want to mix code with content, you can.}
@item{@bold{No template language.} It's not necessary, because you can use the whole Racket language, and all the usual Racket syntax, in every Pollen file.}
@item{@bold{No template language.} It's not necessary, because in every Pollen file, you can use the whole Racket language, and all the usual Racket syntax.}
@item{@bold{Shallow learning curve.} You don't need to do a lot of setup and configuration to start doing useful work with Pollen. Programmers and non-programmers can easily collaborate. Yes, I concede that if you plan to get serious, you'll need to learn some Racket. I don't think you'll regret it.}
]
@section[#:tag "why-racket-why-lisp"]{Further reading}
In @link["http://practicaltypography.com/why-racket-why-lisp.html"]{@italic{Why Racket? Why Lisp?}}, I explain why Racket was the right tool for this job.

@ -1,6 +1,6 @@
#lang scribble/manual
@(require scribble/eval pollen/cache pollen/world (for-label racket (except-in pollen #%module-begin) pollen/render xml pollen/pagetree sugar txexpr))
@(require scribble/eval pollen/cache pollen/world (for-label racket (except-in pollen #%module-begin) pollen/render xml pollen/pagetree sugar/coerce txexpr))
@(define my-eval (make-base-eval))
@(my-eval `(require pollen pollen/template xml))
@ -11,7 +11,7 @@
Convenience functions for templates. These are automatically imported into the @racket[eval] environment when rendering with a template (see @racket[render]).
This module also provides everything from @racket[sugar/coerce/value].
This module also provides everything from @racketmodname[sugar/coerce].
@defproc[
(->html

@ -1,6 +1,6 @@
#lang scribble/manual
@(require (for-label pollen/world) "mb-tools.rkt")
@(require (for-label pollen/world racket) "mb-tools.rkt")
@title[#:tag "first-tutorial"]{First tutorial}
@ -24,7 +24,7 @@ If you want the shortest possible introduction to Pollen, try the @secref["quick
I'm going to assume that you've already installed Racket and Pollen. If not, do that now.
I'm also going to assume you know the basics of using a command line to run programs and navigate the file system using commands like @tt{cd} and @tt{ls}. On Mac OS X, your command-line program is called Terminal; on Windows it's the Windows Command Processor.
I'm also going to assume you know the basics of using a command line to run programs and navigate the file system using commands like @exec{cd} and @exec{ls}. On Mac OS X, your command-line program is called Terminal; on Windows it's the Windows Command Processor.
@section{The relationship of Racket & Pollen}
@ -60,7 +60,7 @@ Launch DrRacket. Start a new file. The code in the file will look like this:
#lang racket
}
Within the main window, you should also see an @italic{interactions window}, which shows the output of the current file, and starts out looking something like this (details, like the version number, will vary):
Within the main window, you should also see an @defterm{interactions window}, which shows the output of the current file, and starts out looking something like this (details, like the version number, will vary):
@terminal{
Welcome to DrRacket, version 6.0.1.6--2013-11-26(-/f) [3m].
@ -72,9 +72,9 @@ If you don't see the interactions window, select @menuitem["View"
@subsection{Setting the @tt{#lang} line}
The first line of every Racket source file, and every Pollen source file, is called the @italic{@tt{#lang} line}. The @tt{#lang} line identifies the language used to interpret the rest of the file.
The first line of every Racket source file, and every Pollen source file, is called the @defterm{@tt{#lang} line}. The @tt{#lang} line identifies the language used to interpret the rest of the file.
@margin-note{For more about the @tt{#lang} line, see @secref["hash-languages" #:doc '(lib "scribblings/guide/guide.scrbl")]. BTW, it's pronounced @italic{hash lang}.}
@margin-note{For more about the @tt{#lang} line, see @secref["hash-languages" #:doc '(lib "scribblings/guide/guide.scrbl")]. BTW, @tt{#lang} is pronounced @italic{hash-lang}.}
When you start a new Pollen source file in DrRacket, you'll need to change the @tt{#lang} line to the Pollen language. The simplest way is to change the first line to this:
@ -90,7 +90,7 @@ Language: pollen; memory limit: 1000 MB.
>
}
Notice that the language is now reported as @tt{pollen}. If you like, change the @tt{#lang} line to this:
Notice that the language is now reported as @code{pollen}. If you like, change the @tt{#lang} line to this:
@nested[#:style 'code-inset]{@verbatim{
#lang pollenxyz}}
@ -100,7 +100,7 @@ Then click @onscreen["Run"] again. DrRacket will print an error:
@errorblock{Module Language: invalid module text
standard-module-name-resolver: collection not found ...}
Why? Because there's no language called @tt{pollenxyz}. Switch it back to @tt{pollen} and let's move on.
Why? Because there's no language called @code{pollenxyz}. Switch it back to @code{pollen} and let's move on.
@subsection{Putting in the text of the poem}
@ -139,19 +139,21 @@ This shows you something important: by default, any plain text in a Pollen sourc
File naming in Pollen is consequential.
Ultimately, every Pollen source file in your project will be @italic{rendered} into an output file. Each Pollen source file corresponds to one output file. @bold{The name of this output file will be the name of the source file minus the Pollen source extension.} So a source file called @tt{file.txt.pp} will become @tt{file.txt}.
Ultimately, every Pollen source file in your project will be @defterm{rendered} into an output file. Each Pollen source file corresponds to one output file. @bold{The name of this output file will be the name of the source file minus the Pollen source extension.} So a source file called @filepath{file.txt.pp} will become @filepath{file.txt}.
Thus, to build the name of a source file, we take the name we want for the output file and add the appropriate Pollen file extension. Different Pollen source files use different extensions — but more about that later. For now, the extension you'll use for your source is @tt{.pp}.
Thus, to derive the name of a source file, we 1) take the name we want for the output file and 2) append the appropriate Pollen file extension. Different Pollen source files use different extensions — but more about that later. For now, the extension you'll use for your source is @filepath{.pp}.
In this case, let's say we want to end up with a file called @tt{poem.html}. Therefore, the name of our source file needs to be:
In this case, let's say we want to end up with a file called @filepath{poem.html}. Therefore, the name of our source file needs to be:
the output name @tt{poem.html} + the source extension @tt{.pp} = @tt{poem.html.pp}
the output name @filepath{poem.html}
@(linebreak)+ the source extension @filepath{.pp}
@(linebreak)= @filepath{poem.html.pp}
(If you want to name the file @tt{something-else.html.pp}, be my guest. There's no magic associated with the prefix.)
(If you want to name the file @filepath{something-else.html.pp}, be my guest. There's no special meaning associated with the prefix of a source file, only the suffixes.)
@margin-note{You're welcome to change the name of your source files from the desktop. On Mac OS X and Windows, however, the desktop interface often hides file extensions, so check the properties of the file afterward to make sure you got the name you expected.}
In a convenient location (e.g., your home directory or the desktop) create a new directory for your project called @tt{tutorial}. In this new directory, save your DrRacket file as @tt{poem.html.pp}.
In a convenient location (e.g., your home directory or the desktop) create a new directory for your project called @code{tutorial}. In this new directory, save your DrRacket file as @filepath{poem.html.pp}.
@fileblock["/path/to/tutorial/poem.html.pp" @codeblock{
#lang pollen
@ -169,7 +171,7 @@ The project server is a web server built into Pollen. Just as DrRacket lets you
@image/rp["project-server.png" #:scale 0.7]
``Why can't I just open the HTML files directly in my browser?'' If you want to keep making web pages the way we did in 1996, go ahead. But that approach has several shortcomings. First, when you open files directly in your browser, you're cruising the local filesystem, and absolute URLs (the kind that start with a @litchar{/}) won't work. Second, if you want to test your website on devices other than your own machine — well, you can't. Third, you have to render your HTML files in advance, whereas the project server is clever about doing this dynamically.
``Why can't I just open the HTML files directly in my browser?'' If you want to keep making web pages the way we did in 1996, go ahead. But that approach has several shortcomings. First, when you open files directly in your browser, you're accessing the local filesystem, and absolute URLs — the kind that start with a @litchar{/} — won't work. Second, you have to render your HTML files in advance, whereas the project server is clever about doing this dynamically. Third, if you want to test your website on devices other than your own machine — sorry, you can't.
So use the project server.
@ -179,22 +181,22 @@ A note about security. The project server isn't intended for real-world use, but
@subsection{Starting the project server with @tt{raco pollen}}
Before we start the project server, a word about the @tt{raco pollen} command.
Before we start the project server, a word about the @exec{raco pollen} command.
When you installed Racket, Racket installed a utility program called @tt{raco}. This name is short for @bold{Ra}cket @bold{co}mmand, and @tt{raco} acts as a hub for — you guessed it — Racket commands. You used it when you first installed Pollen:
When you installed Racket, Racket installed a utility program called @exec{raco}. This name is short for @bold{Ra}cket @bold{co}mmand, and @exec{raco} acts as a hub for — you guessed it — Racket commands. You used it when you first installed Pollen:
@terminal{
> raco pkg install pollen
}
The first argument after @tt{raco} is the subcommand. For instance, @tt{raco pkg ...} lets you install, update, and remove packages like so:
The first argument after @exec{raco} is the subcommand. For instance, @exec{raco pkg ...} lets you install, update, and remove packages like so:
@terminal{
> raco pkg update pollen
> raco pkg remove pollen
}
Likewise, @tt{raco pollen} lets you issue commands relevant to Pollen, like starting the project server. (See @secref["raco-pollen"] for a full description of available commands.)
Likewise, @exec{raco pollen} lets you issue commands relevant to Pollen, like starting the project server. (See @secref["raco-pollen"] for a full description of available commands.)
Now we'll start the project server. Go to your command line and enter the following:
@ -202,7 +204,7 @@ Now we'll start the project server. Go to your command line and enter the follow
> cd /path/to/tutorial
> raco pollen start}
@margin-note{Windows users, I'll trust you to convert @tt{raco} into the appropriate command for your system — assuming defaults, it's likely to be @tt{"C:\Program Files\Racket\raco"} (include the surrounding quotes in the command).}
@margin-note{Windows users, I'll trust you to convert @exec{raco} into the appropriate command for your system — assuming defaults, it's likely to be @exec{"C:\Program Files\Racket\raco"} (include the surrounding quotes in the command).}
After a moment, you'll see a startup message like this:
@ -215,7 +217,7 @@ Ready to rock}
@italic{Project root} means the directory that the project server was started in, and which it's treating as its root directory. Any absolute URLs (i.e., those beginning with @litchar{/}) will resolve into this directory. So a URL like @tt{/styles.css} will impliedly become @tt{/path/to/tutorial/styles.css}.
If you use the bare command @tt{raco pollen start}, the project server will start in the current directory. But if you want to start the project server elsewhere, you can add that directory as an argument like this:
If you use the bare command @exec{raco pollen start}, the project server will start in the current directory. But if you want to start the project server elsewhere, you can add that directory as an argument like this:
@terminal{
> raco pollen start /some/other/path
@ -223,9 +225,9 @@ If you use the bare command @tt{raco pollen start}, the project server will star
The next line of the startup message tells you that the web address of the project server is @tt{http://localhost:8080}. This is the address you put into your web browser to test your project. If you're unfamiliar with this style of URL, @tt{localhost} refers to your own machine, and @tt{8080} is the network port where the project server will respond to browser requests.
If you want to access the project server from a different machine, you can't use @tt{localhost}. But you can use the IP address of the machine running the project server (e.g., @tt{http://192.168.1.10:8080}) or any name for that machine available through local DNS (e.g., @tt{http://mb-laptop:8080}).
If you want to access the project server from a different machine, you can't use @tt{localhost}. But you can use the IP address of the machine running the project server (e.g., @tt{http://192.168.1.10:8080}) or any name for that machine available through local DNS (e.g., @tt{http://my-laptop:8080}).
Though port @tt{8080} is the default, you can start the project server on any port you like by adding it as an argument to @tt{raco pollen start}:
Though port @tt{8080} is the default, you can start the project server on any port you like by adding it as an argument to @exec{raco pollen start}:
@terminal{
> raco pollen start /path/to/tutorial
@ -251,13 +253,13 @@ Your terminal window will report status and error messages from the project serv
@subsection{Using the dashboard}
For each directory in your project, starting at the top, the project server displays a @italic{dashboard} in your web browser. The dashboard gives you an overview of the files in the directory, and links to view them.
For each directory in your project, starting at the top, the project server displays a @defterm{dashboard} in your web browser. The dashboard gives you an overview of the files in the directory, and links to view them.
The address of the top-level dashboard is @tt{http://localhost:8080/index.ptree}. Other dashboards follow the same pattern (e.g., @tt{http://localhost:8080/path/to/dir/index.ptree}.)
Note that the dashboard is @bold{not} at @tt{http://localhost:8080/} or its equivalent, @tt{http://localhost:8080/index.html}. Why? So it doesnt interfere with any @tt{index.html} that you may want to put in your project.
Thus, @tt{index.ptree}. The @tt{.ptree} extension is short for @italic{pagetree}. In Pollen, a pagetree is a hierarchical list of pages. We'll do more with pagetrees in a later tutorial. For now, just be aware that to generate the dashboard, the project server will first look for an actual @tt{index.ptree} file in each directory. If it doesn't find one, it will generate a pagetree from a listing of files in the directory.
Thus, the dashboard relies on a different file, called @filepath{index.ptree}. The @filepath{.ptree} extension is short for @defterm{pagetree}. In Pollen, a pagetree is a hierarchical list of pages. We'll do more with pagetrees in a later tutorial. For now, just be aware that to generate the dashboard, the project server will first look for an actual @filepath{index.ptree} file in each directory. If it doesn't find one, it will generate a pagetree from a listing of files in the directory.
Let's look at the root-level dashboard for our project. First, make sure your project server is running:
@ -272,25 +274,25 @@ You should see something like this:
@image/rp["dashboard.png"]
The top line tells us that we're in the root directory of the project. We didn't make an explicit @tt{index.ptree} file, so the project server just shows us a directory listing.
The top line tells us that we're in the root directory of the project. We didn't make an explicit @filepath{index.ptree} file, so the project server just shows us a directory listing.
@subsection{Source files in the dashboard}
We see the only file, @tt{poem.html.pp}. Note that the @tt{.pp} extension is grayed out. The dashboard automatically consolidates references to source and output files into a single entry. What this entry says is ``The directory contains a source file in @tt{.pp} format for the output file @tt{poem.html}.''
We see the only file, @filepath{poem.html.pp}. Note that the @filepath{.pp} extension is grayed out. The dashboard automatically consolidates references to source and output files into a single entry. What this entry says is ``The directory contains a source file in @filepath{.pp} format for the output file @filepath{poem.html}.''
Every source-file entry in the dashboard has three links. The first link is attached to the filename itself, and takes you to a preview of the output file. If the output file doesn't yet exist — as is the case here — it will be dynamically rendered. (This is true whether you click its name in the dashboard, or link to it from another page.) So click the filename. You'll see in your web browser:
@browser{
The margin is 42em. The border is red. The padding is 15em. The border is too.}
Granted, this is a boring web page. The main point here is that you're seeing the @italic{output} from your source file, which didn't exist before. Notice that the address bar says @tt{http://localhost:8080/poem.html}, not @tt{poem.html.pp}. And if you look in your @tt{tutorial} directory, you'll see a new file called @tt{poem.html}.
Granted, this is a boring web page. The main point here is that you're seeing the @italic{output} from your source file, which didn't exist before. Notice that the address bar says @tt{http://localhost:8080/poem.html}, not @tt{poem.html.pp}. And if you look in your @tt{tutorial} directory, you'll see a new file called @filepath{poem.html}.
In other words, when you clicked on the filename link in the dashboard, Pollen rendered the output file from your source file and saved it in your project directory. As promised earlier, the name of the output file (@tt{poem.html}) is the name of the source file (@tt{poem.html.pp}) minus the Pollen extension (@tt{.pp}).
In other words, when you clicked on the filename link in the dashboard, Pollen rendered the output file from your source file and saved it in your project directory. As promised earlier, the name of the output file (@filepath{poem.html}) is the name of the source file (@filepath{poem.html.pp}) minus the Pollen extension (@filepath{.pp}).
If you go back to the dashboard and click on the filename link again, you'll see the same output file. If the source file hasn't changed, Pollen will just show you the output file that's already been rendered.
But if you like, open your @tt{poem.html.pp} source file in DrRacket, edit the first two lines, and save the file:
But if you like, open your @filepath{poem.html.pp} source file in DrRacket, edit the first two lines, and save the file:
@fileblock["/path/to/tutorial/poem.html.pp" @codeblock|{
#lang pollen
@ -333,25 +335,25 @@ For now, the files are identical except for the @tt{#lang} line. But let's chang
@section{Working with the preprocessor}
Pollen can operate in several processing modes. One of these is @italic{preprocessor} mode. A preprocessor is a tool for making systematic, automated changes to a file, often in contemplation of further processing (hence the @italic{pre-}). You can use the Pollen preprocessor this way. Or you can just use it on its own, and leave your files in a finished state.
Pollen can operate in several processing modes. One of these is @defterm{preprocessor} mode. A preprocessor is a tool for making systematic, automated changes to a file, often in contemplation of further processing (hence the @defterm{pre-}). You can use the Pollen preprocessor this way. Or you can just use it on its own, and leave your files in a finished state.
That's how we'll use it in this tutorial. We'll build out our @tt{poem.html.pp} source file so that it exits the preprocessor as a legit HTML file.
That's how we'll use it in this tutorial. We'll build out our @filepath{poem.html.pp} source file so that when it exits the preprocessor, we'll have a legit HTML file.
@subsection{Setting up a preprocessor source file}
The file extension of a Pollen source file tells Pollen what kind of processing to apply to it. The ``@tt{.pp}'' file extension stands for ``Pollen preprocessor.'' You can use the preprocessor with any text-based file by:
The file extension of a Pollen source file tells Pollen what kind of processing to apply to it. The @filepath{.pp} file extension stands for ``Pollen preprocessor.'' You can use the preprocessor with any text-based file by:
@itemlist[
@item{inserting @tt{#lang pollen} as the first line,}
@item{adding the @tt{.pp} file extension,}
@item{adding the @filepath{.pp} file extension,}
@item{running it through Pollen.}
]
@margin-note{For more about the Pollen processing modes and how to invoke them, see @secref["file-types"].}
``The preprocessor be used with @bold{any} kind of text-based file?'' Right. ``But how?'' The preprocessor reads the source file, handles any Pollen commands it finds, and lets the rest of the content pass through untouched. To the preprocessor, it's all just text data. It doesn't care whether that text represents HTML, CSS, JavaScript, or even @link["https://en.wikipedia.org/wiki/TI-BASIC"]{TI-BASIC}.
``I can use the preprocessor with @bold{any} kind of text-based file?'' Right. ``But how?'' The preprocessor reads the source file, handles any Pollen commands it finds, and lets the rest of the content pass through untouched. To the preprocessor, it's all just text data. It doesn't care whether that text represents HTML, CSS, JavaScript, or even @link["https://en.wikipedia.org/wiki/TI-BASIC"]{TI-BASIC}.
One caveat: because the preprocessor only deals with text, the Pollen commands you use in the preprocessor also have to produce text. Moreover, Pollen doesn't enforce the syntax rules of the underlying file — that's your responsibility. For instance, Pollen won't stop you from doing nonsensical things like this:
@ -363,7 +365,7 @@ Look out for the grue.
◊(insert-mp3-recording-of-scream)
}]
Pollen will fulfill your request, but the result won't be valid HTML, because you can't simply drop binary data in the middle of an HTML file. To paraphrase Mr. Babbage — garbage in, garbage out.
Pollen will fulfill your request, but the result won't be valid HTML, because you can't simply drop binary data in the middle of an HTML file. As Mr. Babbage warned — garbage in, garbage out.
I've encouraged you to mess with the source file, but let's return it to its original state:
@ -376,7 +378,7 @@ The padding is 15em.
The border is too.
}]
This file has @tt{#lang pollen} as the first line, and @tt{.pp} as the file extension, so it meets the minimum requirements for the preprocessor.
This file has @tt{#lang pollen} as the first line, and @filepath{.pp} as the file extension, so it meets the minimum requirements for the preprocessor.
@subsection{Creating valid HTML output}
@ -402,7 +404,7 @@ Return to the project server and view @link["http://localhost:8080/poem.html" "h
The margin is 42em. The border is red. The padding is 15em. The border is too.}
But now, because of the @tt{<pre>} tag, the poem will appear in a monospaced font, and the line breaks will be preserved:
But now, because of the @code{<pre>} tag, the poem will appear in a monospaced font, and the line breaks will be preserved:
@terminal{
The margin is 42em.
@ -418,7 +420,7 @@ This is now a valid HTML page.
I mentioned that the preprocessor reads the file and handles any Pollen commands it finds. But our source file doesn't have any commands yet. Let's add some.
Pollen commands can be embedded in your source file using one of two modes: @italic{Racket mode} or @italic{text mode}. We'll try text mode in a later tutorial. For now, we'll use Racket mode.
Pollen commands can be embedded in your source file using one of two modes: @defterm{Racket mode} or @defterm{text mode}. We'll try text mode in a later tutorial. For now, we'll use Racket mode.
To make a Racket-mode Pollen command, just take any Racket expression and put the lozenge character @litchar["◊"] in front of it. For instance, these are valid Racket expressions:
@ -438,30 +440,30 @@ And these are the equivalent commands in Pollen:
◊(define color "blue")
}
How to type a lozenge:
@margin-note{How to type a lozenge:
@(linebreak)@bold{Mac}: option + shift + V
@(linebreak)@bold{Windows}: holding down alt, type 9674 on the num pad
@(linebreak)@bold{Ubuntu}: ctrl + shift + U, then 25CA
@(linebreak)@bold{Ubuntu}: ctrl + shift + U, then 25CA}
Couldn't be simpler.
@subsection{Racket basics (if you're not familiar)}
``But I've never used Racket.'' Today, you start. Here are the five basic rules of Racket:
``But I've never used Racket.'' Today, you start. Here are the four basic rules of Racket:
@itemlist[#:style 'ordered
@item{The core building block of Racket is the @italic{expression}. An expression can be a value (like @racket[2] or @racket{blue}), a variable (like @tt{edge}), or a function call (like @racket[(* inner 4)]).}
@item{Every expression is @italic{evaluated} to produce a value.}
@item{A variable evaluates to whatever value it holds (so @tt{inner} would become @racket[2]). A function call evaluates to its return value (so @racket[(+ 1 1)] would become @racket[2]).}
@item{The core building block of Racket is the @italic{expression}. An expression can be a single value (like @racket[2] or @racket{blue}), a variable (like @code{edge}), a list of values (like @racket[(list 2 "blue" edge)]), or a function call.}
@item{Function calls go between parentheses. Unlike most languages, the function name comes @italic{first}, followed by its arguments (so it's @racket[(* inner 4)], not @racket[(inner * 4)]). This is called @italic{prefix notation}.}
@item{Every expression is @italic{evaluated} to produce a value. A variable evaluates to whatever value it holds (so after we say @code{(define inner 2)}, @code{inner} would evaluate to @racket[2]). A function call evaluates to its return value (so @racket[(+ 2 2)] would evaluate to @racket[4]).}
@item{Expressions can contain recursively nested expressions. Thus, @racket[(* inner 4)] could be written @racket[(* inner (+ 2 2))] or @racket[(* inner (+ (+ 1 1) (+ 1 1)))].}
]
@margin-note{Newcomers to Racket often gripe about prefix notation and the parentheses. If you need to get it out of your system, go ahead. Keep in mind, however, that it's not some peculiar affectation, but rather a necessary consequence of rule #1. As you'll come to learn, rule #1 is where the magic happens.}
@margin-note{Newcomers to Racket often gripe about prefix notation and parentheses. If you need to get it out of your system, go ahead. Keep in mind, however, that it's not some peculiar affectation, but rather a necessary consequence of rule #1. As you'll come to learn, rule #1 is where the magic happens.}
That's all you need to figure out what's going on in the Pollen commands below:
@ -480,7 +482,7 @@ To learn more about Racket syntax, consider a detour through the excellent @othe
@subsection{Defining variables with commands}
Let's use commands to define variables that will hold some values for our page. First, add a @tt{<head>} tag to your source file, and three commmands to define three variables:
Let's use commands to define variables that will hold some values for our page. First, add a @code{<head>} tag to your source file, and three commmands to define three variables:
@fileblock["/path/to/tutorial/poem.html.pp" @codeblock{
#lang pollen
@ -522,7 +524,7 @@ The border is too.
</body>
</html>}
What's with the blank lines? Don't panic — our @tt{◊(define ...)} commands define variables, so they don't evaluate to any value. Instead, we get blank lines. So far, so good.
What's with the blank lines? Don't panic — our @tt{◊(define ...)} commands create variables, so they don't evaluate to any value. Instead, we get blank lines. (Don't panic about that either — @racket[define] is a rare exception to the general rule that all expressions evaluate.) So far, so good.
@subsection{Inserting values from variables}
@ -558,13 +560,13 @@ The border is too.}
Hey, look at that — the text of the poem changed. Now it even rhymes.
If you like, in the source file, edit the variable definitions with different values and reload the page in the project server. The page will be rendered afresh with the new values. In particular, if you update @tt{inner}, you'll also see @tt{edge} change, since its value depends on @tt{inner}.
If you like, in the source file, edit the variable definitions with different values and reload the page in the project server. The page will be rendered afresh with the new values. In particular, if you update @code{inner}, you'll also see @code{edge} change, since its value depends on @code{inner}.
@subsection{Inserting variables within CSS}
Our poem makes claims about the @tt{margin}, @tt{border}, and @tt{padding} of the page that aren't yet true. To fix this, we'll rely on the same basic technique of inserting variables into our HTML file. But instead of putting them in the @tt{<body>} of the page, we'll put them in a CSS @tt{<style>} tag.
Our poem makes claims about the @code{margin}, @code{border}, and @code{padding} of the page that aren't yet true. To fix this, we'll rely on the same basic technique of inserting variables into our HTML file. But instead of putting them in the @code{<body>} of the page, we'll put them in a CSS @code{<style>} tag.
Update the @tt{<head>} section of the page with a new @tt{<style>} tag that defines a style for @tt{pre} like so, using our variables for the relevant values:
Update the @code{<head>} section of the page with a new @code{<style>} tag that defines a style for @code{pre} like so, using our variables for the relevant values:
@fileblock["/path/to/tutorial/poem.html.pp"
@ -598,7 +600,7 @@ The border is too.
Notice that we're using the same @litchar{◊|}@italic{variable-name}@litchar{|} pattern as before to insert the variable values.
What do we expect to see? We expect that the @tt{padding} and @tt{border} will be 2em wide, because @tt{inner} is 2. We expect the @tt{margin} to be 8em, because it's equal to @tt{edge}, which is @tt{inner} multiplied by 4. And we expect the color of the border to be @racket["blue"], because that's the value of the variable @tt{color}.
What do we expect to see? We expect that the @code{padding} and @code{border} will be 2em wide, because @code{inner} is 2. We expect the @code{margin} to be 8em, because it's equal to @code{edge}, which is @code{inner} multiplied by 4. And we expect the color of the border to be @racket["blue"], because that's the value of the variable @code{color}.
And indeed, when you @link["http://localhost:8080/poem.html"]{reload the file} in the project server, you'll see exactly that:

@ -1,6 +1,6 @@
#lang scribble/manual
@(require (for-label racket pollen/world pollen/template pollen/pagetree sugar))
@(require (for-label racket/base pollen/world pollen/template pollen/pagetree sugar))
@(require "mb-tools.rkt")
@ -26,11 +26,13 @@ If you want the shortest possible introduction to Pollen, try the @secref["quick
@section[#:tag-prefix "tutorial-2"]{Prerequisites}
I'll assume you've completed the @secref["first-tutorial"] and you understand how to create source files in DrRacket and view them in the project server. I will not be spelling out those tasks as I did before.
I'll assume you've completed the @secref["first-tutorial"] and you understand how to create source files in DrRacket and view them in the project server. I won't be spelling out those tasks as I did before.
@section{Prelude: my principled objection to Markdown}
@section{The case against Markdown}
I recognize that people like Markdown. I want people to like Pollen too, so that's why Markdown support exists in Pollen. But just to be clear about my own views 
I recognize that people like Markdown. I want people to like Pollen too, so that's why Pollen supports Markdown.
But just to be clear about my own views.
I'm mystified by the popularity of Markdown among writers. I can agree that it's a clever and readable way of notating basic HTML. And sure, that makes it great for things like web comments, where speed and simplicity are primary virtues.
@ -38,7 +40,7 @@ In longer-form writing, however, its shortcomings become evident. Like programmi
An animating principle of Pollen, as explained in the @secref["Backstory"], is that after 20 years, we ought to move beyond thinking of HTML as a source format. Since Markdown is just well-disguised HTML, a vote for Markdown is really a vote to continue the status quo (albeit with fewer angle brackets). For me, that's not good enough. I'm ready for the tools to expand to fit my ideas; I don't want to keep cutting down my ideas to fit the tools.
All that said, if you genuinely prefer Markdown, I'm not looking to pry it from your fingers. Pollen has excellent Markdown support (due entirely to Greg Hendershott's excellent @link["https://github.com/greghendershott/markdown/"]{Markdown parser} for Racket). It makes Markdown more useful.
All that said, if you genuinely prefer Markdown, I'm not looking to pry it from your fingers. Pollen has great Markdown support (due entirely to Greg Hendershott's excellent @link["https://github.com/greghendershott/markdown/"]{Markdown parser} for Racket). It makes Markdown more useful.
But let's make a deal, Markdown fans. Having met you more than halfway, will you at least consider that @seclink["Pollen_markup_vs__XML"]{Pollen markup} might be a better option for you than Markdown? Because it can notate anything that's in your brain, not just a subset of HTML? And if @secref["the-book-is-a-program"], the source for that book should look more like your brain, and less like HTML?
@ -49,7 +51,7 @@ That's all I ask.
There are two ways to use Markdown within Pollen: you can either send Markdown files through the preprocessor, or use Markdown authoring mode.
The preprocessor approach is better if you want to end up with a set of Markdown files that can be passed along to a HTML converter (or other Markdown-to-______ converter) elsewhere.
The preprocessor approach is better if you want to end up with a set of Markdown files that can be passed along to a HTML converter (or other Markdown-to-______ converter) downstream.
The authoring-mode approach is better if you want to end up with something other than Markdown, e.g., finished HTML files.
@ -57,7 +59,7 @@ The authoring-mode approach is better if you want to end up with something other
Because Markdown is a text-based format, you can use the Pollen preprocessor to add programmatic features to existing Markdown files. (See @secref["Working_with_the_preprocessor"] in the @secref["first-tutorial"] if you need a refresher.)
Suppose we have a Markdown file called @tt{brennan.md} that we want to use with the preprocessor. Create this file in DrRacket, save it, and start the project server in that directory.
Suppose we have a Markdown file called @filepath{brennan.md} that we want to use with the preprocessor. Create this file in DrRacket, save it, and start the project server in that directory.
@fileblock["brennan.md"
@codeblock[#:keep-lang-line? #f]{
@ -71,7 +73,7 @@ My name is _Brennan_, and I enjoy:
You'll be able to see this file in the project server, but for now, it's just a static file. Pollen isn't doing anything to it.
Let's change that. Consistent with the usual preprocessor practice, we add @tt{#lang pollen} as the first line, and append the @tt{.pp} file extension, so our new preprocessor-ready file looks like this:
Let's change that. Consistent with the usual preprocessor practice, add @tt{#lang pollen} as the first line, and append the @filepath{.pp} file extension, so our new preprocessor-ready file looks like this:
@fileblock["brennan.md.pp"
@codeblock{
@ -84,7 +86,7 @@ My name is _Brennan_, and I enjoy:
+ 24 fish nuggets
}]
Go back to the project server and you'll see the new filename. When you click on it, Pollen will render a new @tt{markdown.md} file, but it will look the same as the one you had before.
Go back to the project server and you'll see the new filename. When you click on it, Pollen will render a new @filepath{brennan.md} file, but it will look the same as the one you had before.
Now we'll change some of the values using Pollen commands:
@ -103,7 +105,7 @@ My name is _Brennan_, and I enjoy:
+ ◊nugget-quantity ◊nugget-type nuggets
}]
When you reload this file in the project server, @tt{brennan.md} will be regenerated, and will now look like this:
When you reload this file in the project server, @filepath{brennan.md} will be regenerated, and will now look like this:
@terminal{
My name is _Brennan_, and I enjoy:
@ -123,21 +125,21 @@ But first, let's pause to clarify the general concept of an authoring mode.
Though the preprocessor is useful, it limits you to inserting chunks of text at various positions into an existing file.
Pollen's @italic{authoring mode}, by contrast, parses the whole source file into a special data structure called an @italic{X-expression}. You can then process the whole X-expression any way you like, and output to any format you like — or multiple formats — using a @italic{template}.
Pollen's @defterm{authoring mode}, by contrast, parses the whole source file into a special data structure called an @defterm{X-expression}. You can then process the whole X-expression any way you like, and output to any format you like — or multiple formats — using a @defterm{template}.
Compared to the preprocessor, authoring mode offers more abstraction and flexibility. Of course, it's also a bit more effort to set up.
Pollen offers two variants of authoring mode: one that uses Markdown syntax (which we'll cover later in this tutorial) and the other that uses a free-form markup syntax (which we'll cover in the next tutorial). In both cases, the basic idea is the same: parse the source into an X-expression, and then output it using a template.
Pollen offers two variants of authoring mode: one that uses Markdown syntax (which we'll cover later in this tutorial) and the other that uses a free-form markup syntax (which we'll cover in the @secref["third-tutorial" #:doc '(lib "pollen/scribblings/pollen.scrbl")]). In both cases, the basic process is the same: 1) compile the source into an X-expression, and then 2) convert that X-expression to the target file format using a template.
@subsection{X-expressions}
@(noskip-note)
I avoid nerdy jargon whenever possible. But in this case, the thing is called an @italic{X-expression} throughout the Racket documentation, for good reasons. So I use the term too. Better to acclimate you now.
I avoid nerdy jargon whenever possible. But in this case, the thing is called an @defterm{X-expression} throughout the Racket documentation, for good reasons. So I use the term too. Better to acclimate you now.
An X-expression is a way of representing markup-based data in code. X-expressions are indigenous to Lisp-based languages like Pollen and Racket. They don't exist in Python or JavaScript or Ruby.
Let's start with the part you're familiar with. By ``markup-based data,'' I mean things like HTML and XML and SVG. The idea is that you have text-based data surrounded by @italic{tags}. Each tag can also have its own @italic{attributes} that are made of keys and values. Tags can contain other tags, thus creating a tree-like structure. Right? You know what I mean:
Let's start with the part you're familiar with. By ``markup-based data,'' I mean things like HTML and XML and SVG. The idea is that you have text-based data surrounded by @defterm{tags}. Each tag can also have its own @defterm{attributes} that are made of keys and values. Tags can contain other tags, thus creating a tree-like structure. Right? You know what I mean:
@terminal{<body><h1>Hello world</h1><p class="first">Nice to <i>see</i> you.</p></body>}
@ -155,17 +157,17 @@ However, this creates ambiguity between the name of the tag and the content. So
@terminal{(body (h1 "Hello world") (p class="first" "Nice to" (i "see") "you."))}
As for the @tt{class} attribute, we need to distinguish it from both the markup tags and the content, so we'll move it between double parentheses:
As for the @code{class} attribute, we need to distinguish it from both the markup tags and the content, so we'll move it between double parentheses:
@terminal{(body (h1 "Hello world") (p ((class "first")) "Nice to" (i "see") "you."))}
Net of a few boring details, that's basically all there is to it.
Skipping past a few boring details, that's basically all there is to it.
So why is it called an X-expression? Lisp languages are built out of units called S-expressions, which look like this:
@terminal{(and (txexpr? x) (member (get-tag x) (project-block-tags)) #t))}
S-expressions use prefix notation, where each pair of parentheses contains a list. The first element in the list names a function, and the other elements are the arguments to that function. (This is a review of @secref["Racket_basics__if_you_re_not_familiar_"].) X-expressions are just a minor adaptation of S-expression notation to represent markup, hence the name (the @italic{X} is short for @italic{XML-like}).
S-expressions use prefix notation, where each pair of parentheses contains a list. The first element in the list names a function, and the other elements are the arguments to that function. (This is a review of @secref["Racket_basics__if_you_re_not_familiar_"].) X-expressions are just a minor adaptation of S-expression notation to represent markup, hence the name (the @defterm{X} is short for @defterm{XML-like}).
For handling markup-based data, X-expressions have some useful advantages compared to other methods:
@ -179,7 +181,7 @@ For handling markup-based data, X-expressions have some useful advantages compar
@item{@bold{An ideal match for an expression-based programming language.} Aside from some notational details, X-expressions are just a subset of S-expressions generally, which are the building block of Racket. Processing X-expressions in Racket maximizes flexibility and minimizes @link["http://programmers.stackexchange.com/questions/34775/correct-definition-of-the-term-yak-shaving"]{yak-shaving}.}
]
@margin-note{Given the close kinship between XML-ish data structures and Lisp-ish programming languages, I have no explanation why, during the Internet era, they have not been paired more often.}
@margin-note{Given the close kinship between XML-ish data structures and Lisp-ish programming languages, I have no explanation why, during the Internet era, they have not been paired more often. They're like peanut butter and jelly.}
In Pollen's authoring modes, your source file is parsed into an X-expression, which can then be processed further before being injected into a template & converted to output. As a first example, we'll look at Markdown authoring mode.
@ -188,7 +190,7 @@ In Pollen's authoring modes, your source file is parsed into an X-expression, wh
Let's start putting together our article. For simplicity, I'm going to use unrealistically short sample texts. But you can use whatever Markdown content you want.
We want to use Markdown authoring mode to make a file that will ultimately be HTML. So consistent with Pollen file-naming conventions (see @secref["Saving___naming_your_source_file"]), we'll start with our desired output filename, @tt{article.html}, and then append the Markdown authoring suffix, @tt{.pmd}. So in DrRacket, start a new file called @tt{article.html.pmd} and put some Markdown in it:
We want to use Markdown authoring mode to make a file that will ultimately be HTML. So consistent with Pollen file-naming conventions (see @secref["Saving___naming_your_source_file"]), we'll start with our desired output filename, @filepath{article.html}, and then append the Markdown authoring suffix, @filepath{.pmd}. So in DrRacket, start a new file called @filepath{article.html.pmd} and put some Markdown in it:
@fileblock["article.html.pmd"
@codeblock{
@ -208,15 +210,15 @@ Before you preview this file in the project server, click the @onscreen{Run} but
You should now be able to recognize this as an X-expression. In authoring mode, Pollen parses your Markdown into the corresponding HTML entities, but then provides the data as an X-expression rather than finished HTML.
@margin-note{The empty parentheses @tt{()} after @tt{p} and @tt{strong} signal that the tag's attributes are empty. When you write an X-expression without attributes, these parentheses are optional — @tt{(tag () "text")} and @tt{(tag "text")} are equivalent — but Pollen will always print X-expressions this way.}
@margin-note{The empty parentheses @code{()} after @code{p} and @code{strong} signal that the tag's attributes are empty. When you write an X-expression without attributes, these parentheses are optional — @code{(tag () "text")} and @code{(tag "text")} are equivalent — but Pollen will always print X-expressions this way.}
From what you learned in the last section, it should be evident that this X-expression corresponds to HTML that looks like this:
@repl-output{<root><h1 id="my-article">Deep Thought</h1><p>I am @(linebreak)<strong>so</strong> happy to be writing this.</p></root>}
``But what's this @tt{root} tag? That's not HTML.'' An X-expression must have a root tag, so in the spirit of obviousness, every X-expression produced by a source file in authoring mode will start with @tt{root}. If you don't need it, you can discard it. But it also creates a useful hook for further processing, as we'll see later.
``But what's this @code{root} tag? That's not HTML.'' An X-expression must have a root tag, so in the spirit of obviousness, every X-expression produced by a source file in authoring mode will start with @code{root}. If you don't need it, you can discard it. But it also creates a useful hook for further processing, as we'll see later.
By the way, as review, let's remind ourselves how this is different from preprocessor mode. Let's take the same Markdown content, but this time put it into a preprocessor source file called @tt{article.md.pp}.
By the way, as review, let's remind ourselves how this is different from preprocessor mode. Let's take the same Markdown content, but this time put it into a preprocessor source file called @filepath{article.md.pp}.
@fileblock["article.md.pp"
@codeblock{
@ -237,21 +239,34 @@ Deep Thought
I am **so** happy to be writing this.
}
Hopefully, this result makes sense to you: when you run Markdown source in preprocessor mode, you get Markdown. When you run Markdown source in authoring mode, you get an X-expression.
This result makes sense, right? To recap: when you use Markdown source in preprocessor mode, Pollen gives you Markdown. When you use Markdown source in authoring mode, Pollen gives you an X-expression.
So how do you convert an X-expression into your target file format? Read on.
@section[#:tag-prefix "tutorial-2"]{Templates}
So how do you convert an X-expression into a finished file? You use a Pollen @italic{template}, which takes data from an X-expression and converts it to the target format.
In Pollen, a @defterm{template} is where you take data from an X-expression and convert it to your target format. If you've used other web-publishing systems, templates are probably a familiar idea. Templates in Pollen are similar to the ones you've seen before in some ways, but different in other ways.
First, the two major similarities:
@itemlist[
@item{At its simplest, a template holds @bold{boilerplate material} that you want to reuse across multiple output files. For instance, in a set of HTML pages, you might have layout and navigation elements that stay the same, while the content changes. In that case, you could put the layout and navigation in the template, and keep the content in your Pollen source files. When you want to add a new page, you can make a new source file and just use it with the existing template. Moreover, if you want to change the layout and navigation globally, you can just change the template, rather than changing the source files.}
If you've used other web-publishing systems, templates are probably a familiar idea. Templates in Pollen are in some ways similar to the ones you've seen before, but in other ways different.
@item{Pollen templates, like others, can also have @bold{conditional elements} — meaning, you can embed simple code in your templates that allows them to change based on the content in the page. For instance, a template could show or hide ``previous page'' and ``next page'' links depending on whether there's actually a previous or next page.}
First, the similarities. At its simplest, a template holds boilerplate material that you want to reuse across multiple pages. For instance, in a set of HTML pages, you might have layout and navigation elements that stay the same, while the content changes. In that case, you could put the layout and navigation in the template, and keep the content in your Pollen source files. When you want to add a new page, you can make a new source file and just use it with the existing template. Moreover, if you want to change the layout and navigation globally, you can just change the template, rather than changing the source files.
]
Pollen templates, like others, can also have conditional features — meaning, you can embed simple code in your templates that allows them to change based on the content in the page. For instance, a template could show or hide ``previous page'' and ``next page'' links depending on whether there's actually a previous or next page.
And two major differences:
The major difference with Pollen templates is that there's no special ``template language'' you need to learn, with magic delimiters and whatnot. Instead, you can use all the same Pollen commands in a template that you can in authoring mode or preprocessor mode.
@itemlist[
To see a template in action, let's return to the source file we started in the last section:
@item{There's @bold{no special template language} you need to learn, with magic syntax and whatnot. Instead, you can use all the same Pollen commands in a template that you can in authoring mode or preprocessor mode.}
@item{Within a template, you have to @bold{explicitly convert} the X-expression to the target format. This is a feature, not a bug. By avoiding assumptions about the target format, Pollen templates can be used to generate any kind of file (even binary formats like PDF). But the cost of this flexibility is that you need to tell Pollen what you want.}
]
To see how this works, let's return to the source file we started in the last section:
@fileblock["article.html.pmd"
@codeblock{
@ -280,13 +295,13 @@ Here, you're seeing the X-expression from your source combined with an HTML temp
</body></html>
}
But wait — where did the template come from? When you view an authoring-mode source file in the project server without specifying a template, Pollen helps you out and uses its @italic{fallback template}. The fallback template is just a minimal template that's used as a last resort. Under ordinary circumstances, seeing the fallback template usually signals a problem (e.g., Pollen couldn't find the template you asked for).
But wait — where did the template come from? When you view an authoring-mode source file in the project server without specifying a template, but you're using an @filepath{html} extension, Pollen helps you out and uses its @defterm{fallback template} for HTML. The fallback template is just a minimal template that's used as a last resort. Under ordinary circumstances, seeing the fallback template usually signals a problem (e.g., Pollen couldn't find the template you asked for).
But we can learn a few things from the fallback template about how to make an HTML template.
@subsection{The @tt{->html} function and the @tt{doc} variable}
@subsection{The @tt{doc} export and the @tt{->html} function}
This is the fallback template that Pollen uses.
To understand the necessary ingredients of a template, let's look at a simple one — the fallback template that Pollen uses for HTML files, called @filepath{fallback.html}.
@fileblock["fallback.html"
@codeblock[#:keep-lang-line? #f]{
@ -303,33 +318,31 @@ First, there's an X-expression that represents a basic HTML page:
(html (head (meta 'charset: "UTF-8")) (body))
}
This is equivalent to the HTML:
That X-expression is equivalent to this HTML string:
@terminal{<html><head><meta charset="UTF-8"></head><body></body></html>}
But within a template, we need to explicitly convert from X-expression to HTML. So we wrap this X-expression with our second key ingredient, the Pollen command @racket[->html]:
But within a template, we need to tell Pollen how we want to convert the X-expression to the target format. explicitly convert from X-expression to HTML. So we wrap this X-expression with our second key ingredient, the Pollen command @racket[->html]:
@codeblock[#:keep-lang-line? #f]{
#lang pollen
◊(->html (html (head (meta 'charset: "UTF-8")) (body)))
}
Third, we need to include the content from our source file. We do this by putting the variable @tt{doc} inside the @tt{body} tag.
Third, we need to include the content from our source file. By convention, every Pollen source file makes its output available through an exported variable named @code{doc}. A source file in preprocessor mode puts its text result in @code{doc}. And a source file in authoring mode puts its X-expression result in @code{doc}. So we put the variable @code{doc} inside the @code{body} tag.
@margin-note{You can change the name to something other than @code{doc} by changing @racket[world:main-pollen-export].}
@codeblock[#:keep-lang-line? #f]{
#lang pollen
◊(->html (html (head (meta 'charset: "UTF-8")) (body doc)))
}
By convention, every Pollen source file makes its output available through the variable @tt{doc}. A source file in preprocessor mode puts its text result in @tt{doc}. And a source file in authoring mode puts its X-expression result in @tt{doc}.
Under the hood, a template is just a partial program that relies on a set of variables defined by another source file. (In Racket, this set of variables is called a @defterm{lexical context}). So if you ran this template on its own, nothing would happen, because @code{doc} isn't defined. But when you run it in the context of another source file, it picks up the @code{doc} that's defined by that file.
@margin-note{You can change the name to something other than @tt{doc} by changing @racket[world:main-pollen-export].}
Caution — despite the name, a Pollen template is not necessarily a file of the type suggested by its extension. For instance, @filepath{fallback.html} is a file that ultimately produces HTML, but as the example above shows, it's not necessarily written in HTML.
Under the hood, a template is just a partial program that relies on a set of variables defined by another source file (fancy name: @italic{lexical context}). So if you ran this template on its own, nothing would happen, because @tt{doc} isn't defined. But when you run it in the context of another source file, it picks up the @tt{doc} that's defined by that file.
Caution — despite the name, a Pollen template is not necessarily a file of the type suggested by its extension. For instance, @tt{fallback.html} is a file that ultimately produces HTML, but it's not actually written in HTML.
It could be, however. Here's an equivalent way of writing @tt{fallback.html} that inserts @tt{doc} into actual HTML, rather than making the whole thing an X-expression.
It could be, however. Here's an equivalent way of writing @filepath{fallback.html} that inserts @code{doc} into actual HTML, rather than making the whole thing an X-expression.
@fileblock["fallback.html" @codeblock[#:keep-lang-line? #f]{
#lang pollen
@ -337,20 +350,22 @@ It could be, however. Here's an equivalent way of writing @tt{fallback.html} tha
<body>◊(->html doc)</body></html>
}]
Notice that we still need to use the @racket[->html] function, but this time, instead of surrounding a larger X-expression, it just goes around @tt{doc}.
Notice that we still need to use the @racket[->html] function, but this time, instead of surrounding a larger X-expression, it just goes around @code{doc}.
Truly, there is no difference between these two methods. In the first method, you're describing the whole template using an X-expression and converting the whole thing with @racket[->html]. In the second method, you're ``hard-coding'' the boilerplate HTML, so the only part that needs to be converted with @racket[->html] is @code{doc}.
Truly, there is no difference between these two methods. Use whichever works best for you. I often prefer the second method because I like to build & test HTML layouts by hand using placeholder content to make sure all the fiddly bits work. Then it's easy to replace the placeholder content with @racket[(->html doc)], and it becomes a template.
Use whichever method works best for you. I often prefer the second method, because I like to build HTML layouts by hand using placeholder content to make sure all the fiddly bits work. Then it's easy to replace the placeholder content with @racket[(->html doc)], and it becomes a template.
@subsection{Making a custom template}
We'll use these three ingredients to make our own template for @tt{article.html.pmd}.
We'll use these three ingredients to make our own template for @filepath{article.html.pmd}.
In general, template files can have any name you want. But by default, Pollen will first look for a file in your project directory called @tt{template.ext}, where @tt{ext} matches the output-file extension of the source file. So if your source file is @tt{database.xml.pmd}, Pollen will look for @tt{template.xml}. And for @tt{article.html.pmd}, Pollen will look for @tt{template.html}.
In general, template files can have any name you want. But by default, Pollen will first look for a file in your project directory called @filepath{template.ext}, where @code{ext} matches the output-file extension of the source file. So if your source file is @filepath{database.xml.pmd}, Pollen will look for @filepath{template.xml}. And for @filepath{article.html.pmd}, Pollen will look for @filepath{template.html}.
Therefore, to set up a custom template, all we need to do is create a file called @tt{template.html} in our project directory, and make sure it has the three key ingredients we saw in the fallback template. Pollen will automatically apply it to @tt{article.html.pmd} when we view it in the project server.
Therefore, to set up a custom template, all we need to do is create a file called @filepath{template.html} in our project directory, and make sure it has the three key ingredients we saw in the fallback template. Pollen will automatically apply it to @filepath{article.html.pmd} when we view it in the project server.
But don't take my word for it. In your project directory, create a new file called @tt{template.html}:
But don't take my word for it. In your project directory, create a new file called @filepath{template.html}:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
@ -362,9 +377,9 @@ But don't take my word for it. In your project directory, create a new file call
</html>
}]
Recall from the last section that this is the same as the fallback template, but written out in HTML, and with a @tt{title} element added. In fact, you can now refresh @tt{article.html} in the project server. Does it look different? No — it won't, because the resulting template is the same. You should notice, however, that the title of the browser window is now ``Custom template,'' because Pollen is relying on your new template file, rather than the fallback template.
Recall from the last section that this is the same as the fallback template, but written out in HTML, and with a @code{title} element added. In fact, you can now refresh @filepath{article.html} in the project server. Does it look different? No — it won't, because the resulting template is the same. You should notice, however, that the title of the browser window is now @onscreen{Custom template}, because Pollen is relying on your new template file, rather than the fallback template.
Let's change our custom template by adding a @tt{style} block:
Let's change our custom template by adding a @code{style} block:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
@ -380,19 +395,19 @@ strong {color: red;}
<body>◊(->html doc)</body>
</html>}]
When you refresh @tt{article.html} in the project server, you'll see that the heading now has a gray background, and one word in the text is red.
When you refresh @filepath{article.html} in the project server, you'll see that the heading now has a gray background, and one word in the text is red.
Feel free to add other settings to @tt{template.html}, or update the text in @tt{article.html}, and see how the page changes. As you'd expect, the project server keeps an eye on both your source files and your template files, and if one changes, it will refresh the output file automatically.
Feel free to add other settings to @filepath{template.html}, or update the text in @filepath{article.html}, and see how the page changes. As you'd expect, the project server keeps an eye on both your source files and your template files, and if one changes, it will refresh the output file automatically.
@subsection{Inserting specific source data into templates}
In the last example, we used @tt{doc} to insert the entire content of the source file — as an X-expression — into the template.
In the last example, we used @code{doc} to insert the entire content of the source file — as an X-expression — into the template.
But what if you want to only insert part of your source file into the template? For instance, you'll look like a dork if the title on each page is ``Custom template.'' So let's fix that.
But what if you want to only insert part of your source file into the template? For instance, you'll look like a dork if the title on each page is @onscreen{Custom template}. So let's fix that.
When you're working in a template, Pollen provides a @racket[select] function that lets you extract the content of a specific tag, like so: @tt{◊(select '@racketvarfont{tag-name} doc)}, which means ``get the content of @racketvarfont{tag-name} out of @tt{doc} and put it here.''
When you're working in a template, Pollen provides a @racket[select] function that lets you extract the content of a specific tag, like so: @code{◊(select tag-name doc)}, which means ``get the content of @racketvarfont{tag-name} out of @code{doc} and put it here.''
Let's suppose that we'd rather use the name of the article — @italic{Deep Thought} — as the page title. We're going to put a @tt{◊(select ...)} command inside the @tt{<title>} tag.
Let's suppose that we'd rather use the name of the article — @italic{Deep Thought} — as the page title. We're going to put a @racket[select] command inside the @code{<title>} tag.
Beyond that, we just need to know the tag name that contains the title. If we have a little Markdown expertise, we might already know that this part of our Markdown source:
@ -403,14 +418,14 @@ Deep Thought
============
}
is going to produce a tag named @tt{h1}.
is going to produce a tag named @code{h1}.
What if we don't have all the Markdown conversions memorized? No problem. We can still figure out the tag name by running the @tt{article.html.pmd} source file in DrRacket and looking at the X-expression that results:
What if we don't have all the Markdown conversions memorized? No problem. We can still figure out the tag name by running the @filepath{article.html.pmd} source file in DrRacket and looking at the X-expression that results:
@repl-output{'(root (h1 ((id "my-article")) "Deep Thought") (p () "I am "
(strong () "so") " happy to be writing this."))}
Either way, now we know that the text @italic{Deep Thought} lives in the @tt{h1} tag. So we update our template accordingly (for brevity, I'm going to omit the @tt{style} tag in these examples, but it's fine to leave it in):
Either way, now we know that the text @italic{Deep Thought} lives in the @code{h1} tag. So we update our template accordingly (for brevity, I'm going to omit the @code{style} tag in these examples, but it's fine to leave it in):
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
@ -422,7 +437,7 @@ Either way, now we know that the text @italic{Deep Thought} lives in the @tt{h1}
</html>
}]
When you refresh the page in the project server, the page title will now appear as ``Deep Thought.'' Of course, you can also combine static and dynamic elements in your template, like so:
When you refresh the page in the project server, the page title will now appear as @onscreen{Deep Thought}. Of course, you can also combine static and dynamic elements in your template, like so:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
@ -434,7 +449,7 @@ When you refresh the page in the project server, the page title will now appear
</html>
}]
The page title will now be ``Deep Thought, by MB''.
The page title will now be @onscreen{Deep Thought, by MB}.
A couple notes on command syntax. We inserted the @racket[select] and @racket[->html] commands using Racket-mode syntax. We could also use text-mode syntax and write the commands this way:
@ -450,7 +465,7 @@ A couple notes on command syntax. We inserted the @racket[select] and @racket[->
This is exactly equivalent to the previous example. Skeptics are welcome to confirm this by checking the result in the project server.
Finally, notice that in the @racket[select] command, the tag name @racket['h1] is written with a quote mark, whereas @tt{doc} is not. This is an easy place to get tripped up, but the rule is simple: you don't use a quote mark when you're referring to the name of an existing function or variable (like @racket[select] or @tt{doc}). But you do need a quote mark when you're using the text as a literal value.
Finally, notice that in the @racket[select] command, the tag name @code{h1} is written with a quote mark (@code{'h1}), whereas @code{doc} is not. This is an easy place to get tripped up, but the rule is simple: you don't use a quote mark when you're referring to the name of an existing function or variable (like @racket[select] or @code{doc}). But you do need a quote mark when you're using the text as a literal value.
@margin-note{Racket (and hence Pollen) makes a distinction between @secref["symbols" #:doc '(lib "scribblings/guide/guide.scrbl")] (e.g. @racket['h1]) and @secref["strings" #:doc '(lib "scribblings/reference/reference.scrbl")] (e.g. @racket["h1"]). Without getting into the weeds, just note for now that the tag of an X-expression is always a symbol, not a string. But if you write @racketfont*{◊(@racket[select] "h1" doc)}, the command will still work, because Pollen will treat it as @racketfont*{◊(@racket[select] 'h1 doc)}, consistent with a general policy of not being persnickety about input types when the intention is clear.}
@ -458,7 +473,7 @@ Finally, notice that in the @racket[select] command, the tag name @racket['h1] i
@subsection{Linking to an external CSS file}
If you're a super web hotshot, you probably don't put your CSS selectors in the @tt{<head>} tag. Instead, you link to an external CSS file. So it will not surprise you that in Pollen, you can do this by adding the usual @tt{<link>} tag to your HTML template, in this case a file called @tt{styles.css}:
If you're a super web hotshot, you probably don't put your CSS selectors in the @code{<head>} tag. Instead, you link to an external CSS file. So it will not surprise you that in Pollen, you can do this by adding the usual @code{<link>} tag to your HTML template, in this case a file called @filepath{styles.css}:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
@ -473,13 +488,13 @@ If you're a super web hotshot, you probably don't put your CSS selectors in the
</html>
}]
Fans of hand-coded CSS, I trust you to take it from here: make your @tt{styles.css} file, and enjoy the results.
Fans of hand-coded CSS, I trust you to take it from here: make your @filepath{styles.css} file, and enjoy the results.
But folks who paid attention during the @secref["first-tutorial"] might be wondering ``Can we link to a dynamically generated @tt{styles.css.pp} file?''
But folks who paid attention during the @secref["first-tutorial"] might be wondering ``Can we link to a dynamically generated @filepath{styles.css.pp} file?''
Yes, of course. Here's the rule of thumb: when you're making links between files — whether CSS, or HTML, or anything else — Pollen doesn't care whether the file is static or dynamic. You just refer to it by its ultimate name, in this case @tt{styles.css}. If a static @tt{styles.css} file exists, Pollen will use that. If it doesn't, Pollen will look for a source file it can use to make @tt{styles.css}, and generate it on the spot. (You can also start with a static file, and change it to be dynamic later, and Pollen will do the right thing.)
Yes, of course. Here's the rule of thumb: when you're making links between files — whether CSS, or HTML, or anything else — Pollen doesn't care whether the file is static or dynamic. You just refer to it by its ultimate name, in this case @filepath{styles.css}. If a static @filepath{styles.css} file exists, Pollen will use that. If it doesn't, Pollen will look for a source file it can use to make @filepath{styles.css}, and generate it on the spot. (You can also start with a static file, and change it to be dynamic later, and Pollen will do the right thing.)
So to use a dynamic CSS file, we don't need to make any changes to @tt{template.html}. We just need to add @tt{styles.css.pp} to the project directory:
So to use a dynamic CSS file, we don't need to make any changes to @filepath{template.html}. We just need to add @filepath{styles.css.pp} to the project directory:
@fileblock["styles.css.pp"
@codeblock{
@ -493,7 +508,7 @@ h1 {background: ◊|h1-color|; color: white;}
strong {color: ◊|strong-color|;}
}]
Now, when you refresh @tt{article.html} in the project server, Pollen will generate the @tt{styles.css} file it needs, and you'll see the new colors in the page. As before, if you update @tt{styles.css.pp}, Pollen will notice and regenerate the CSS file when you refresh the page.
Now, when you refresh @filepath{article.html} in the project server, Pollen will generate the @filepath{styles.css} file it needs, and you'll see the new colors in the page. As before, if you update @filepath{styles.css.pp}, Pollen will notice and regenerate the CSS file when you refresh the page.
Can you add multiple dynamic style sheets? Yes.
@(linebreak)Can you mix dynamic and static style sheets? Yes.
@ -523,7 +538,7 @@ You've actually already been exposed to pagetrees (though I didn't tell you abou
If the multiple pages in your project are already ordered by filename, then you can rely on this automatic pagetree.
From earlier in the tutorial, you have a Markdown source file called @tt{article.html.pmd} that looks like this:
From earlier in the tutorial, you have a Markdown source file called @filepath{article.html.pmd} that looks like this:
@fileblock["article.html.pmd"
@codeblock{
@ -557,30 +572,30 @@ Carticle Title
The terrific third part.
}]
As before, you can fill these source files with any sample Markdown content you like. Moreover, you don't have to use the filenames @tt{barticle.html.pmd} and @tt{carticle.html.pmd} — the point is that the intended sequence needs to match the alphabetic sorting of the filenames.
As before, you can fill these source files with any sample Markdown content you like. Moreover, you don't have to use the filenames @filepath{barticle.html.pmd} and @filepath{carticle.html.pmd} — the point is that the intended sequence needs to match the alphabetic sorting of the filenames.
We'll reuse the @tt{template.html} and @tt{styles.css} files from earlier in the tutorial. Move or delete the other tutorial files so that your dashboard in the project server shows only these five files:
We'll reuse the @filepath{template.html} and @filepath{styles.css} files from earlier in the tutorial. Move or delete the other tutorial files so that your dashboard in the project server shows only these five files:
@itemlist[
@item{@tt{article.html.pmd}}
@item{@tt{barticle.html.pmd}}
@item{@tt{carticle.html.pmd}}
@item{@tt{styles.css} (or @tt{styles.css.pp})}
@item{@tt{template.html}}
@item{@filepath{article.html.pmd}}
@item{@filepath{barticle.html.pmd}}
@item{@filepath{carticle.html.pmd}}
@item{@filepath{styles.css} (or @filepath{styles.css.pp})}
@item{@filepath{template.html}}
]
If you click on any of the three Markdown sources, you will see it converted into HTML using @tt{template.html}, with styles appiled from @tt{styles.css}.
If you click on any of the three Markdown sources, you will see it converted into HTML using @filepath{template.html}, with styles appiled from @filepath{styles.css}.
The automatic pagetree for this project is exactly what you see in the dashboard: a list of the three article files, followed by @tt{styles.css} and @tt{template.html}.
The automatic pagetree for this project is exactly what you see in the dashboard: a list of the three article files, followed by @filepath{styles.css} and @filepath{template.html}.
@subsection{Adding navigation links to the template with @tt{here}}
Recall from earlier in the tutorial that the content of your source file is made available in the template through the special variable @tt{doc}. Likewise, the name of the current source file is made available through the special variable @tt{here}.
Recall from earlier in the tutorial that the content of your source file is made available in the template through the special variable @code{doc}. Likewise, the name of the current source file is made available through the special variable @code{here}.
To make any navigation link — up, down, sideways — the general idea is that we use @tt{here} as input to a pagetree-navigation function, which then looks up the answer in the current pagetree.
To make any navigation link — up, down, sideways — the general idea is that we use @code{here} as input to a pagetree-navigation function, which then looks up the answer in the current pagetree.
First, let's just see @tt{here} on its own. Update your template as follows:
First, let's just see @code{here} on its own. Update your template as follows:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
@ -597,9 +612,9 @@ The current page is called ◊|here|.
</html>
}]
If you refresh @tt{article.html}, you will now see the line ``The current page is called article.html.'' Switch to @tt{barticle.html}, and you'll see ``The current page is called barticle.html.'' Makes sense, right?
If you refresh @filepath{article.html}, you will now see the line ``The current page is called article.html.'' Switch to @filepath{barticle.html}, and you'll see ``The current page is called barticle.html.'' Makes sense, right?
Now let's use pagetree functions to show the names of the previous and next pages. Consistent with the usual policy of obviousness, these functions are called @racket[previous] and @racket[next]:
Now let's use pagetree functions to show the names of the previous and next pages. Consistent with the usual Pollen policy of obviousness, these functions are called @racket[previous] and @racket[next]:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
@ -618,7 +633,7 @@ The next is ◊|(next here)|.
</html>
}]
Refresh @tt{barticle.html}. You'll now see that ``The current page is called barticle.html. The previous is article.html. The next is carticle.html.'' So far, so good: we're correctly deriving the previous and next pages from the automatic pagetree.
Refresh @filepath{barticle.html}. You'll now see that ``The current page is called barticle.html. The previous is article.html. The next is carticle.html.'' So far, so good: we're correctly deriving the previous and next pages from the automatic pagetree.
All that's left is to add hyperlinks, which is easy:
@ -639,19 +654,19 @@ The next is <a href="◊|(next here)|">◊|(next here)|</a>.
</html>
}]
Refresh @tt{barticle.html}, and you'll see that the names of the previous and next pages are now hyperlinks to those pages. Click through and convince yourself that it works.
Refresh @filepath{barticle.html}, and you'll see that the names of the previous and next pages are now hyperlinks to those pages. Click through and convince yourself that it works.
@margin-note{The documentation for pagetree @secref["Navigation"] will tell you about the other functions available for generating navigation links.}
@subsection{Handling navigation boundaries with conditionals}
If you clicked through to @tt{article.html} or @tt{carticle.html}, you might've noticed a couple problems. Because @tt{article.html} is the first page in the automatic pagetree, it doesn't have any previous page it can link to. And the next-page link for @tt{carticle.html} is @tt{styles.css}, which is strictly correct — it is, in fact, the next file in the automatic pagetree — but it's not part of our article, so we'd rather stop the navigation there.
If you clicked through to @filepath{article.html} or @filepath{carticle.html}, you might've noticed a couple problems. Because @filepath{article.html} is the first page in the automatic pagetree, it doesn't have any previous page it can link to. And the next-page link for @filepath{carticle.html} is @filepath{styles.css}, which is strictly correct — it is, in fact, the next file in the automatic pagetree — but it's not part of our article, so we'd rather stop the navigation there.
One way to fix the problem would be to have three separate template files — the standard one with both previous- and next-page links, one with only a next-page link, and one with only a previous-page link.
But since we have a whole programming language available in Pollen, that's a dull-witted way to solve the problem. The better way is to add @italic{conditionals} to the template to selectively change the navigation. That keeps things simple, because we'll still have only one @tt{template.html} to deal with.
But since we have a whole programming language available in Pollen, that's a dull-witted way to solve the problem. The better way is to add @italic{conditionals} to the template to selectively change the navigation. That keeps things simple, because we'll still have only one @filepath{template.html} to deal with.
To handle @tt{article.html}, we want to hide the previous-page navigation link when there's no previous page. As it turns out, if the @racket[previous] function can't find a previous page, it will return false. So we just need to wrap our previous-page navigation in the @racket[when/block] command like so:
To handle @filepath{article.html}, we want to hide the previous-page navigation link when there's no previous page. As it turns out, if the @racket[previous] function can't find a previous page, it will return false. So we just need to wrap our previous-page navigation in the @racket[when/block] command like so:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
@ -671,7 +686,7 @@ The next is <a href="◊|(next here)|">◊|(next here)|</a>.
</html>
}]
The basic structure of @racket[when/block] is @tt{◊when/block[@racketvarfont{condition}]{@racketvarfont{insert-this-text}}.} Note the square braces around the @racketvarfont{condition}, and the curly braces around the @racketvarfont{text}. Using @racket[(previous here)] as the condition is shorthand for ``when @racket{(previous here)} does not return false...''
The basic structure of @racket[when/block] is @tt{◊when/block[@racketvarfont{condition}]{@racketvarfont{insert-this-text}}.} Note the square braces around the @racketvarfont{condition}, and the curly braces around the @racketvarfont{text}. Using @racket[(previous here)] as the condition is shorthand for ``when @racket[(previous here)] does not return false...''
Programmers in the audience might be getting anxious about the repeated use of @racket[(previous here)] — you're welcome to store that value in a variable, and everything will work the same way:
@ -696,7 +711,7 @@ The next is <a href="◊|(next here)|">◊|(next here)|</a>.
We need a different technique for handling the end of the next-page navigation, because we're not reaching the actual end of the pagetree. We're just reaching the end of the pages we care about navigating through.
What condition will help us detect this? Here, we can notice that the names of our article pages all contain the string @tt{article}. While you'd probably want a more robust condition for a real project, in this tutorial, what we'll do is hide the next-page navigation if the name of the next page doesn't contain ``@tt{article}''. As we did before, we wrap our navigation line in the @racket[when/block] function:
What condition will help us detect this? Here, we can notice that the names of our article pages all contain the string @code{article}. While you'd probably want a more robust condition for a real project, in this tutorial, what we'll do is hide the next-page navigation if the name of the next page doesn't contain ``@code{article}''. As we did before, we wrap our navigation line in the @racket[when/block] function:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
@ -720,15 +735,15 @@ The next is <a href="◊|(next here)|">◊|(next here)|</a>.}
This time, the condition is @racket[(regexp-match "article" (->string (next here)))]. How were you supposed to know this? You weren't. That's why this is a tutorial. Without going on a lengthy detour, the @racket[regexp-match] function returns true if the first string (in this case, @racket["article"]) is found inside the second string (in this case, we convert @racket[(next here)] to a string by wrapping it in @racket[->string]).
In any case, even if some of the programmy bits went over your head just now, relax and paste the code into your template. What you'll see when you refresh @tt{carticle.html} is that the next-page link is gone. So now our template lets us navigate among the pages of our article, and the conditionals handle the end pages correctly.
In any case, even if some of the programmy bits went over your head just now, relax and paste the code into your template. What you'll see when you refresh @filepath{carticle.html} is that the next-page link is gone. So now our template lets us navigate among the pages of our article, and the conditionals handle the end pages correctly.
@subsection{Making a pagetree source file}
I didn't want to dwell on programming complications in the last conditional. Why? The extra programming was necessary only because we made life somewhat difficult for ourselves by relying on the automatic pagetree. A better way to solve the problem is to avoid it altogether by making a pagetree file.
Pagetree source files have a different syntax and status than other Pollen source files, so they are parsed using their own Pollen dialect. To invoke this dialect, you just start the file with @tt{#lang pollen} and name the file with the @tt{ptree} extension, for instance @tt{my-project.ptree}. While you can have as many pagetrees in your project as you want, Pollen will accord primary status to the one named @tt{index.ptree}.
Pagetree source files have a different syntax and status than other Pollen source files, so they are parsed using their own Pollen dialect. To invoke this dialect, you just start the file with @tt{#lang pollen} and name the file with the @filepath{ptree} extension, for instance @filepath{my-project.ptree}. While you can have as many pagetrees in your project as you want, Pollen will first look for one named @filepath{index.ptree}.
So let's make an @tt{index.ptree} file. At its simplest, a pagetree file can just be a list of files in the intended order. In DrRacket, create a new file in your project directory as follows:
So let's make an @filepath{index.ptree} file. At its simplest, a pagetree file can just be a list of files in the intended order. In DrRacket, create a new file in your project directory as follows:
@fileblock["index.ptree"
@codeblock{
@ -756,13 +771,13 @@ article.html.pmd
barticle.html.pmd
}]
You also probably noticed that the files are in a different order than they were in the automatic pagetree: @tt{carticle.html} is first, followed by @tt{article.html} and then @tt{barticle.html}. This too is deliberate, so we can see what happens with a differently ordered pagetree.
You also probably noticed that the files are in a different order than they were in the automatic pagetree: @filepath{carticle.html} is first, followed by @filepath{article.html} and then @filepath{barticle.html}. This too is deliberate, so we can see what happens with a differently ordered pagetree.
Pagetrees don't change nearly as often as other source files, so as a performance optimization, the project server does @italic{not} dynamically reflect changes to pagetrees. To see the effect of this new pagetree on our project, you'll need to go to your terminal window and stop the project server with ctrl+C, and then restart it. Which will take all of three seconds.
Pagetrees don't change nearly as often as other source files, so as a performance optimization, the project server does @italic{not} dynamically reflect changes to pagetrees. To see the effect of this new pagetree on our project, you'll need to go to your terminal window and stop the project server with @onscreen{Ctrl+C}, and then restart it. Which will take all of three seconds.
Now refresh @tt{carticle.html}. You'll notice that the navigation links are different. You won't see a previous-page link — because @tt{carticle.html} is now the first page in the pagetree — and the next page will show up as @tt{article.html}. Click through to @tt{article.html}, and you'll see the navigation likewise updated. Click through to @tt{barticle.html}, and you'll see ...
Now refresh @filepath{carticle.html}. You'll notice that the navigation links are different. You won't see a previous-page link — because @filepath{carticle.html} is now the first page in the pagetree — and the next page will show up as @filepath{article.html}. Click through to @filepath{article.html}, and you'll see the navigation likewise updated. Click through to @filepath{barticle.html}, and you'll see ...
BAM! An error page with a yellow box that says @tt{Cant convert #f to string}. What happened? We switched to using our own pagetree file but we didn't update our template conditionals. Once you reach @tt{barticle.html}, the value of @racket[(next here)] is false, which means the @racket[(->string (next here))] command in the template conditional is trying to convert false into a string. Hence the error.
BAM! An error page that says @tt{Cant convert #f to string}. What happened? We switched to using our own pagetree file but we didn't update our template conditionals. Once you reach @filepath{barticle.html}, the value of @racket[(next here)] is false, which means the @racket[(->string (next here))] command in the template conditional is trying to convert false into a string. Hence the error.
So let's go back and fix that. Because we don't have extraneous files in our pagetree anymore, we can change the second conditional in the template to work the same way as the first:
@ -787,13 +802,13 @@ The next is <a href="◊|next-page|">◊|next-page|</a>.}
</html>
}]
Refresh @tt{barticle.html} — because you're updating the template, you don't need to restart the project server — and you'll see the right result. The previous-page link goes to @tt{article.html}, and the next-page link is hidden.
Refresh @filepath{barticle.html} — because you're updating the template, you don't need to restart the project server — and you'll see the right result. The previous-page link goes to @filepath{article.html}, and the next-page link is hidden.
@subsection{@tt{index.ptree} & the project server}
One more thing to show you before we wrap up this tutorial. Remember that the dashboard of the project server is at @tt{http://localhost:8080/index.ptree}? By default, the project server will synthesize a pagetree from an alphbetical directory listing.
But if you put your own @tt{index.ptree} file in the directory, the project server will use that for the dashboard instead. In fact, visit @link-tt{http://localhost:8080/index.ptree} now and you'll see what I mean. Consistent with the @tt{index.ptree} you made, you'll now see @tt{carticle.html}, @tt{article.html}, and @tt{barticle.html}, but not @tt{template.html} nor @tt{styles.css} (even though they're still in the project directory).
But if you put your own @filepath{index.ptree} file in the directory, the project server will use that for the dashboard instead. In fact, visit @link-tt{http://localhost:8080/index.ptree} now and you'll see what I mean. Consistent with the @filepath{index.ptree} you made, you'll now see @filepath{carticle.html}, @filepath{article.html}, and @filepath{barticle.html}, but not @filepath{template.html} nor @filepath{styles.css} (even though they're still in the project directory).
@section{Second tutorial complete}

@ -18,7 +18,7 @@ Now you're getting to the good stuff. In this tutorial, you'll use Pollen to pub
@item{Attaching behavior to tag functions}
@item{the @tt{directory-require.rkt} file}
@item{the @filepath{directory-require.rkt} file}
@item{Using @racket[decode] with Pollen markup}
@ -50,9 +50,9 @@ So why hasn't XML taken over the world? In practice, XML promises more than it d
@itemlist[
@item{@bold{Verbose syntax}. Unfortunately, XML relies on the same angle-bracket notation as HTML. If you think HTML source is hard to read, XML is even worse. Since much of writing involves reading, this feature is also a major bug.}
@item{@bold{Verbose syntax}. Unfortunately, XML relies on the same angle-bracket notation as HTML. If you think HTML source is hard to read, XML is worse. Since much of writing involves reading, this feature is also a major bug.}
@item{@bold{Validation overhead}. Integral to XML is the concept of @italic{validation}, which guarantees that a document meets certain formal criteria, usually asserted in a @italic{schema}. To get the full value from XML, you generally want to use validation. But doing so imposes a lot more work on you as an author, and removes much of the expressive potential of XML.}
@item{@bold{Validation overhead}. Integral to XML is the concept of @defterm{validation}, which guarantees that a document meets certain formal criteria, usually asserted in a @italic{schema}. To get the full value from XML, you generally want to use validation. But doing so imposes a lot more work on you as an author, and removes much of the expressive potential of XML.}
@item{@bold{Masochistic document processing}. I'm referring to XSLT, the preferred method of transforming XML documents. I know a little XSLT, so I'll concede that there's a method to its madness. But it's still madness.}
@ -86,7 +86,7 @@ In this tutorial, I'll be rendering Pollen markup with an HTML template. But you
@section{Writing with Pollen markup}
Pollen markup is a free-form markup system that lets you add arbitrary @italic{tags} and @italic{attributes} to your text. By arbitrary, I mean that they don't need to match up with an existing schema or specification (e.g., the tags permitted by HTML). They can — but that's an option, not a requirement.
Pollen markup is a free-form markup system that lets you add arbitrary @defterm{tags} and @defterm{attributes} to your text. By arbitrary, I mean that they don't need to match up with an existing schema or specification (e.g., the tags permitted by HTML). They can — but that's an option, not a requirement.
I like to think of Pollen markup a way of capturing not just the text, but also my @bold{ideas about the text}. Some of these are low-level ideas (``this text should be italicized''). Some are high-level ideas (``this text is the topic of the page''). Some are just notes to myself. In short, everything I know about the text becomes part of the text.
@ -94,9 +94,9 @@ In so doing, Pollen markup becomes the source code of the book. Let's try it out
@subsection{Creating a Pollen markup file}
We're going to use Pollen markup to make a file that will ultimately be HTML. So consistent with the authoring-mode workflow we learned in the @secref["second-tutorial"], we'll start with our desired output filename, @tt{article.html}, and then append the Pollen markup suffix, @tt{.pm}.
We're going to use Pollen markup to make a file that will ultimately be HTML. So consistent with the authoring-mode workflow we learned in the @secref["second-tutorial"], we'll start with our desired output filename, @filepath{article.html}, and then append the Pollen markup suffix, @filepath{.pm}.
In DrRacket, start a new file called @tt{article.html.pm} like so (BTW you can use any sample text you like):
In DrRacket, start a new file called @filepath{article.html.pm} like so (BTW you can use any sample text you like):
@fileblock["article.html.pm" @codeblock{
#lang pollen
@ -104,11 +104,11 @@ In DrRacket, start a new file called @tt{article.html.pm} like so (BTW you can u
I want to attend RacketCon this year.
}]
Consistent with usual authoring-mode policy, when you run this file, you'll get an X-expression that starts with @racketvalfont{root}:
Consistent with usual authoring-mode policy, when you run this file, you'll get an X-expression that starts with @code{root}:
@repl-output{'(root "I want to attend RacketCon this year.")}
Remember, even though the first line of the file is @racketmodfont{#lang} @racketmodname[pollen] — same as the last tutorial — the new @tt{.pm} suffix signals that Pollen should interpret the source as Pollen markup. Look what happens if you goof up and put Markdown source in a Pollen markup file, like so:
Remember, even though the first line of the file is @racketmodfont{#lang} @racketmodname[pollen] — same as the last tutorial — the new @filepath{.pm} suffix signals that Pollen should interpret the source as Pollen markup. Look what happens if you goof up and put Markdown source in a Pollen markup file, like so:
@codeblock{
#lang pollen
@ -125,9 +125,9 @@ Restore the non-Markdown source, and let's continue.
@subsection{Tags & tag functions}
Pollen markup uses the same Pollen command syntax that we first saw in @secref["Adding_commands"]. Previously, we used this command syntax to invoke functions like @racket[define] and @racket[->html]. Pollen markup is used to invoke a special kind of function called a @italic{tag function}, which is a function that, by default, adds a tag to the text.
Pollen markup uses the same Pollen command syntax that we first saw in @secref["Adding_commands"]. Previously, we used this command syntax to invoke functions like @racket[define] and @racket[->html]. Pollen markup is used to invoke a special kind of function called a @defterm{tag function}, which is a function that, by default, adds a tag to the text.
To see how this works, restore your @tt{article.html.pm} file to its original state:
To see how this works, restore your @filepath{article.html.pm} file to its original state:
@codeblock{
#lang pollen
@ -135,7 +135,7 @@ To see how this works, restore your @tt{article.html.pm} file to its original st
I want to attend RacketCon this year.
}
We can add any tag with Pollen markup, but for now, let's start with an old favorite: @racketvalfont{em}, which is used in HTML to add emphasis to text. We apply a tag by starting with the lozenge character (◊) followed by the tag name @racketvalfont{em}, followed by the text in curly braces, like so:
We can add any tag with Pollen markup, but for now, let's start with an old favorite: @code{em}, which is used in HTML to add emphasis to text. We apply a tag by starting with the lozenge character (◊) followed by the tag name @code{em}, followed by the text in curly braces, like so:
@fileblock["article.html.pm" @codeblock{
#lang pollen
@ -161,11 +161,11 @@ With the expected results:
@subsection{Attributes}
@italic{Attributes} are like tags for tags. Each attribute is a keyvalue pair where the key is any name, and the value is a string. Anyone who's seen HTML is familiar with them:
@defterm{Attributes} are like tags for tags. Each attribute is a keyvalue pair where the key is any name, and the value is a string. Anyone who's seen HTML is familiar with them:
@repl-output{<span class="author">Prof. Leonard</span>}
Here, @racketvalfont{class} is an attribute for @racketvalfont{span} that has value @racketvalfont{"author"}. And this is what it looks like as an X-expression:
Here, @code{class} is an attribute for @code{span} that has value @code{"author"}. And this is what it looks like as an X-expression:
@repl-output{'(span ((class "author")) "Prof. Leonard")}
@ -175,7 +175,7 @@ You can add any number of attributes to a tag (first as an X-expression, then as
@repl-output{<span class="author" id="primary" living="true">Prof. Leonard</span>}
In Pollen markup, attributes have the same logic, but a slightly different syntax. In keeping with the tag notation you just saw, the @racketvalfont{span} tag is added in the usual way:
In Pollen markup, attributes have the same logic, but a slightly different syntax. In keeping with the tag notation you just saw, the @code{span} tag is added in the usual way:
@fileblock["article.html.pm" @codeblock{
#lang pollen
@ -215,7 +215,7 @@ You could write it in Pollen markup like so:
@repl-output{◊div['class:"red" style:"font-size:150%"]{Important ◊em{News}}}
And then just convert it (using the @racket[->html] function) into the HTML above. Thus, the tags you already know and love (?) can be used in Pollen markup, but with fewer keystrokes and cruft.
And then just convert it (using the @racket[->html] function) into the HTML above. Thus, the tags you already know (and love?) can be used in Pollen markup, but with fewer keystrokes and cruft.
Still, if Pollen markup were just an alternative notation system for HTML tags, it would be pretty boring. As I alluded above, that's merely a boring way to use it.
@ -225,25 +225,25 @@ In the XML spirit, Pollen markup lets you use any tags you want. That's consider
XML jocks can skip this section, since you already know. But if you've been mired in Markdown or HTML, read on.
Tags, broadly speaking, are a means of annotating a text with extra information, which I'll call @italic{metadata} (using that term in its generic sense, not in any fiddly computery way). Metadata is the key tool that enables an author to write a book with the benefits of @italic{semantic markup} and @italic{format independence}.
Tags, broadly speaking, are a means of annotating a text with extra information, which I'll call @defterm{metadata} (using that term in its generic sense, not in any fiddly computery way). Metadata is the key tool that enables an author to write a book with the benefits of @defterm{semantic markup} and @defterm{format independence}.
@subsection{Semantic markup}
@italic{Semantic markup} means adding metadata to text according to the meaning of the text, not merely its intended visual appearance. So rather than tagging @racketvalfont{RacketCon} with an @racketvalfont{em} tag, as we did above to indicate how the word should look, maybe we would tag it with an @racketvalfont{event} tag, to indicate what @italic{kind} of thing it is.
@defterm{Semantic markup} means adding metadata to text according to the meaning of the text, not merely its intended visual appearance. So rather than tagging @code{RacketCon} with an @code{em} tag, as we did above to indicate how the word should look, maybe we would tag it with an @code{event} tag, to indicate what @italic{kind} of thing it is.
Semantic markup lets an author specify distinctions that would be ambiguous in pure visual terms, thereby capturing more meaning and intent. For instance, in books, italic styling is commonly applied to a number of unrelated types of information: emphasized words, movie titles, terms being used for the first time, headings, captions and labels, and so on. Under a non-semantic formatting scheme, perhaps one would tag them all @racketvalfont{em}. But in semantic terms, one would tag them @racketvalfont{movie-title}, @racketvalfont{first-use}, @racketvalfont{heading}, as appropriate.
Semantic markup lets an author specify distinctions that would be ambiguous in pure visual terms, thereby capturing more meaning and intent. For instance, in books, italic styling is commonly applied to a number of unrelated types of information: emphasized words, movie titles, terms being used for the first time, headings, captions and labels, and so on. Under a non-semantic formatting scheme, perhaps one would tag them all @code{em}. But in semantic terms, one would tag them @code{movie-title}, @code{first-use}, @code{heading}, as appropriate.
This has two major benefits. First, by separating appearance and meaning, an author can manage the content of the book in useful ways. For instance, if every movie title were tagged as @racketvalfont{movie-title} rather than @racketvalfont{italic}, then it would be simple to generate a list of all movies mentioned in the book (for the author's benefit) or a page index of movie references (for the reader's benefit). But without that semantic tagging, a movie title couldn't be distinguished from any other italicized text.
This has two major benefits. First, by separating appearance and meaning, an author can manage the content of the book in useful ways. For instance, if every movie title were tagged as @code{movie-title} rather than @code{italic}, then it would be simple to generate a list of all movies mentioned in the book (for the author's benefit) or a page index of movie references (for the reader's benefit). But without that semantic tagging, a movie title couldn't be distinguished from any other italicized text.
@subsection{Format independence}
The second benefit of custom tags is @italic{format independence}, or the ability to change the rendering of the text to suit a particular device or context.
The second benefit of custom tags is @defterm{format independence}, or the ability to change the rendering of the text to suit a particular device or context.
When a text is encrusted with format-specific visual tags — for instance, HTML tags — then the document markup is entangled with a single output format. If you only need one output format, fine.
But increasingly, book authors have been called upon to publish their work in multiple formats: paper and PDF, but also web, e-book, or other natively digital formats, that connect to devices with differing display capabilities.
@margin-note{Yes, I know that many of these formats are based on variants of HTML. But the HTML you can use in a desktop web browser is quite different from, say, the HTML you can use in a Kindle .mobi file. The .mobi file has other technical requirements too, like an .ncx and .opf file. So despite some genetic kinship, these HTML-ish formats are best understood as separate targets.}
@margin-note{Yes, I know that many of these formats are based on variants of HTML. But the HTML you can use in a desktop web browser is quite different from, say, the HTML you can use in a Kindle @code{.mobi} file. The @code{.mobi} file has other technical requirements too, like an @code{.ncx} and @code{.opf} file. So despite some genetic kinship, these HTML-ish formats are best understood as separate targets.}
Using a display-driven model to manage this complexity is a terrible idea — as anyone who's tried it can attest. Converting from one display-based file type to another — for instance, word processor to HTML, or HTML to PDF — is an exercise in frustration and drain-circling expectations.
@ -253,9 +253,9 @@ This isn't surprising. For a long time, text processing has been dominated by th
For a document to be format independent, two conditions have to be satisfied.
First, the document has to be readable by other programs, so they can handle the conversion of format-independent markup into a format-specific rendering (e.g., mapping semantic tags like @racketvalfont{movie-title} onto visual tags like @racketvalfont{em}). Most word-processor formats, like Word's .docx, are bad for authoring because these formats are opaque and proprietary. We needn't get into the political objections. As a practical matter, they're inarguably restrictive — if you can't get your data out of your file, you're stuck.
First, the document has to be readable by other programs, so they can handle the conversion of format-independent markup into a format-specific rendering (e.g., mapping semantic tags like @code{movie-title} onto visual tags like @code{em}). Most word-processor formats, like Word's .docx, are bad for authoring because these formats are opaque and proprietary. We needn't get into the political objections. As a practical matter, they're inarguably restrictive — if you can't get your data out of your file, you're stuck.
Second, the document itself has to be represented in a way that's independent of the particularities of any one format. For instance, HTML is a bad authoring format because it encourages authors to litter their text with HTML-isms like @racketvalfont{h1} and @racketvalfont{span}. These have no meaning outside of HTML, and thus will always cause conversion problems. The @seclink["Prelude__my_principled_objection_to_Markdown"]{same goes for Markdown}, which is simply HTML in disguise.
Second, the document itself has to be represented in a way that's independent of the particularities of any one format. For instance, HTML is a bad authoring format because it encourages authors to litter their text with HTML-isms like @code{h1} and @code{span}. These have no meaning outside of HTML, and thus will always cause conversion problems. The @seclink["The_case_against_Markdown"]{same goes for Markdown}, which is simply HTML in disguise.
@ -264,7 +264,7 @@ The solution to the first condition is to use text-based markup rather than prop
@subsection{Using custom tags}
You can insert a custom tag using the same syntax as any other tag. Suppose you want to use an @racketvalfont{event} tag to mark events. You would insert it like so:
You can insert a custom tag using the same syntax as any other tag. Suppose you want to use an @code{event} tag to mark events. You would insert it like so:
@fileblock["article.html.pm" @codeblock{
#lang pollen
@ -288,11 +288,11 @@ Don't take my word for it. See what happens if you write this:
I want to attend ◊verylongandimpracticaltagname{RacketCon} this year.}]
One small but important exception to this rule. If you were wondering why I sometimes call them @italic{tag functions} instead of just @italic{tags}, it's because under the hood, every tag is implemented as a function. The default behavior of this function is just to wrap the text in a tag with the given name.
One small but important exception to this rule. If you were wondering why I sometimes call them @defterm{tag functions} instead of just @defterm{tags}, it's because under the hood, every tag is implemented as a function. The default behavior of this function is just to wrap the text in a tag with the given name.
The benefit of treating tags as functions will become evident later in this tutorial. But the cost of this approach is that tags occupy the same namespace as the other functions available in Pollen (and by extension, Racket). So if you try to use a tag name that's already the name of an existing function, an error will occur.
For instance, let's suppose you try to use a custom tag called @racketvalfont{length}:
For instance, let's suppose you try to use a custom tag called @code{length}:
@fileblock["article.html.pm" @codeblock{
#lang pollen
@ -305,7 +305,7 @@ When you run this file, you get an error:
expected: list?
  given: "77km"}
The problem is that Racket already provides a function called @racket[length]. Consistent with the usual rules of Pollen command notation, your command is interpreted as an attempt to invoke the @racket[length] function, rather than apply a tag named @racketvalfont{length}.
The problem is that Racket already provides a function called @racket[length]. Consistent with the usual rules of Pollen command notation, your command is interpreted as an attempt to invoke the @racket[length] function, rather than apply a tag named @code{length}.
In practice, namespace clashes are rare. But if necessary, they're easy to work around (for the simplest method, see @secref["Invoking_tag_functions"]).
@ -349,7 +349,7 @@ If you've used HTML or XML, tags are just tags: things you type into the documen
That's not so in Pollen. Under the hood, Pollen is just an alternate way of writing code in the Racket programming language. And tags, instead of being inert markers, are actually functions.
I think most of you know what a function is, but just to be safe — in programming, a @italic{function} is a chunk of code that accepts some input, processes it, and then returns a value. Asking a function to process some data is known as @italic{calling} the function.
I think most of you know what a function is, but just to be safe — in programming, a @defterm{function} is a chunk of code that accepts some input, processes it, and then returns a value. Asking a function to process some data is known as @defterm{calling} the function.
Leading us to the Three Golden Rules of Pollen Tags:
@ -374,7 +374,7 @@ You've already seen the simplest kind of function in a Pollen document: the @sec
I want to attend ◊em{RacketCon ◊strong{this} year}.}]
What happens when you run this source? Working from the inside out, Pollen calls the function @racketvalfont{strong} with the input @racketvalfont{"this"}. The result is @racketvalfont{(strong "this")}. Then Pollen calls the function @racketvalfont{em} with the three input values @racketvalfont{"RacketCon " (strong "this") " year"}, which yields @racketvalfont{(em "RacketCon " (strong "this") " year")}. Finally, Pollen calls the @racketvalfont{root} function with everything in the document, resulting in:
What happens when you run this source? Working from the inside out, Pollen calls the function @code{strong} with the input @code{"this"}. The result is @code{(strong "this")}. Then Pollen calls the function @code{em} with the three input values @code{"RacketCon " (strong "this") " year"}, which yields @code{(em "RacketCon " (strong "this") " year")}. Finally, Pollen calls the @code{root} function with everything in the document, resulting in:
@repl-output{'(root "I want to attend " (em "RacketCon " (strong "this") " year") ".")}
@ -407,7 +407,7 @@ Sometimes this default behavior will suffice. But other times, you'll want to ch
How do you change the behavior of a tag? By 1) writing a new function and 2) giving it the name of the tag. Once you do this, this new behavior will automatically be invoked when you use the tag.
For example, let's redefine the @racketvalfont{strong} tag in our example above to simply print @racketvalfont{BOOM}:
For example, let's redefine the @code{strong} tag in our example above to simply print @code{BOOM}:
@fileblock["article.html.pm" @codeblock{
#lang pollen
@ -430,9 +430,9 @@ How does this work? First, although you can define a function in Pollen command
I want to attend ◊em{RacketCon ◊strong{this} year}.}]
Let's look at our new function definition. As usual, we start with the lozenge character (@litchar{◊}) to denote a Pollen command. Then we use @racket[define] to introduce a function definition. The name of the function comes next, which needs to match our tag name, @racketvalfont{strong}. The expression @racket[(strong word)] means ``the name of this function is @racket[strong], and it takes a single word as input, which we'll refer to as @racket[word].'' Finally we have the return value, which is @racket["BOOM"].
Let's look at our new function definition. As usual, we start with the lozenge character (@litchar{◊}) to denote a Pollen command. Then we use @racket[define] to introduce a function definition. The name of the function comes next, which needs to match our tag name, @code{strong}. The expression @racket[(strong word)] means ``the name of this function is @racket[strong], and it takes a single word as input, which we'll refer to as @racket[word].'' Finally we have the return value, which is @racket["BOOM"].
Let's run this file again, but go back to the Golden Rules to understand what happens. Working from the inside out, Pollen calls the function @racketvalfont{strong} with the input @racketvalfont{"this"} — same as before. But this time, the result of the @racket[strong] function is not @racketvalfont{(strong "this")}, but simply @racketvalfont{BOOM}. Then Pollen calls the function @racketvalfont{em} with the three input values @racketvalfont{"RacketCon " "BOOM" " year"}, which yields @racketvalfont{(em "RacketCon " "BOOM" " year")}. Finally, Pollen calls the @racketvalfont{root} function with everything in the document, resulting in:
Let's run this file again, but go back to the Golden Rules to understand what happens. Working from the inside out, Pollen calls the function @code{strong} with the input @code{"this"} — same as before. But this time, the result of the @racket[strong] function is not @code{(strong "this")}, but simply @code{BOOM}. Then Pollen calls the function @code{em} with the three input values @code{"RacketCon " "BOOM" " year"}, which yields @code{(em "RacketCon " "BOOM" " year")}. Finally, Pollen calls the @code{root} function with everything in the document, resulting in:
@repl-output{'(root "I want to attend " (em "RacketCon " "BOOM" " year"))}
@ -442,7 +442,7 @@ This example is contrived, of course. But the basic idea — defining a functio
Having said that, some of you are probably eager to hack around a bit. Let me chip off a few more cubes from the iceberg to help you on your way. (Everyone else, take five.)
@subsubsection{Point of no @code{return}} If you've written functions in other programming languages, you might be accustomed to using a @code{return} statement to send a value back from the function. This doesn't exist in Pollen or Racket — the return value of any function is just the last expression evaluated. In the example below, @racketvalfont{"BAP"} becomes the return value because it's in the last position, and @racketvalfont{"BOOM"} is ignored:
@subsubsection{Point of no @code{return}} If you've written functions in other programming languages, you might be accustomed to using a @code{return} statement to send a value back from the function. This doesn't exist in Pollen or Racket — the return value of any function is just the last expression evaluated. In the example below, @code{"BAP"} becomes the return value because it's in the last position, and @code{"BOOM"} is ignored:
@fileblock["article.html.pm" @codeblock{
#lang pollen
@ -469,7 +469,7 @@ expected: 1
  given: 3
}
The error arises because the @racket[em] function is getting three arguments — @racketvalfont{"RacketCon " "BOOM" " year"} — but has been defined to only accept one argument, @racket[word]. This is the ``arity mismatch.''
The error arises because the @racket[em] function is getting three arguments — @code{"RacketCon " "BOOM" " year"} — but has been defined to only accept one argument, @racket[word]. This is the ``arity mismatch.''
To fix this, it's better to get in the habit of writing tag functions that accept an indefinite number of input values. You do this by defining your function with a @italic{@seclink["contracts-rest-args" #:doc '(lib "scribblings/guide/guide.scrbl")]{rest argument}} (as in, ``give me the rest of the input values.'') To use a rest argument, put it last in your list of input arguments, and add a period @litchar{.} before:
@ -529,7 +529,7 @@ I want to attend ◊em{RacketCon ◊strong{this} year}.}]
The second option for building X-expressions is to use the @other-doc['(lib "txexpr/scribblings/txexpr.scrbl")] library that's included with Pollen (see those docs for more information).
@subsubsection{Interpolating variables into strings} The usual way is to use the @racket[format] function:
@subsubsection{Using variables within strings} The usual way is to use the @racket[format] function:
@racket[(format "String with variable: ~a" variable-name)]
@ -644,21 +644,21 @@ And get this output:
@repl-output{'(root "A list of integers: " "0 1 2 3 4")}
@subsection[#:tag-prefix "tutorial-3"]{Using the @tt{directory-require.rkt} file}
@subsection[#:tag-prefix "tutorial-3"]{Using the @filepath{directory-require.rkt} file}
@(noskip-note)
As you get more comfortable attaching behavior to tags using tag functions, you'll likely want to create some functions that can be shared between multiple source files. The @tt{directory-require.rkt} file is a special file that is automatically imported by Pollen source files in the same directory. So every function and value provided by @tt{directory-require.rkt} can be used in these Pollen files.
As you get more comfortable attaching behavior to tags using tag functions, you'll likely want to create some functions that can be shared between multiple source files. The @filepath{directory-require.rkt} file is a special file that is automatically imported by Pollen source files in the same directory. So every function and value provided by @filepath{directory-require.rkt} can be used in these Pollen files.
First, using this file is not mandatory. You can always import functions and values from another file using @racket[require] (as seen in the previous section). The @tt{directory-require.rkt} is just meant to cure the tedium of importing the same file into every Pollen source file in your project. In a small project, not much tedium; in a large project, more.
First, using this file is not mandatory. You can always import functions and values from another file using @racket[require] (as seen in the previous section). The @filepath{directory-require.rkt} is just meant to cure the tedium of importing the same file into every Pollen source file in your project. In a small project, not much tedium; in a large project, more.
Second, notice from the @tt{.rkt} suffix that @tt{directory-require.rkt} is a source file containing Racket code, not Pollen code. This is the default because while Pollen is better for text-driven source files, Racket is better for code-driven source files. Still, the choice is yours: the name of this file can be changed by resetting the @racket[world:directory-require] value.
Second, notice from the @filepath{.rkt} suffix that @filepath{directory-require.rkt} is a source file containing Racket code, not Pollen code. This is the default because while Pollen is better for text-driven source files, Racket is better for code-driven source files. Still, the choice is yours: the name of this file can be changed by resetting the @racket[world:directory-require] value.
Third, notice from the @tt{directory-} prefix that @tt{directory-require.rkt} is only used by Pollen source files @italic{in the same directory}. So if your project has source files nested inside a subdirectory, you'll need to explicitly create another @tt{directory-require.rkt} there and share the functions & values as needed.
Third, notice from the @filepath{directory-} prefix that @filepath{directory-require.rkt} is only used by Pollen source files @italic{in the same directory}. So if your project has source files nested inside a subdirectory, you'll need to explicitly create another @filepath{directory-require.rkt} there and share the functions & values as needed.
@margin-note{``Why not make this file visible throughout a project, rather than just a directory?'' Good idea, but I couldn't figure out how to do it without creating finicky new dependencies. If you have a better idea, I'm open to it.}
Let's see how this works in practice. In the same directory as @tt{article.html.pm}, create a new @tt{directory-require.rkt} file as follows:
Let's see how this works in practice. In the same directory as @filepath{article.html.pm}, create a new @filepath{directory-require.rkt} file as follows:
@fileblock["directory-require.rkt" @codeblock{
#lang racket
@ -668,7 +668,7 @@ Let's see how this works in practice. In the same directory as @tt{article.html.
Here we use the @racket[define] function (which we've seen before) to set @racket[author] equal to @racket["Trevor Goodchild"]. Note the final step: consistent with standard Racket rules, we have to explicitly @racket[provide] the new value so that other files can see it (unlike Python, things you @racket[define] in Racket are private by default, not public).
Then update good old @tt{article.html.pm}:
Then update good old @filepath{article.html.pm}:
@fileblock["article.html.pm" @codeblock{
#lang pollen
@ -692,7 +692,7 @@ Run this, and you'll get:
@repl-output{'(root "The author is really " "Trevor Goodchild" "?")}
That's all there is to it. Everything provided by @tt{directory-require.rkt} is automatically available within each Pollen source file.
That's all there is to it. Everything provided by @filepath{directory-require.rkt} is automatically available within each Pollen source file.
You can include functions, including tag functions, the same way. For instance, add a function for @racket[em]:
@ -721,23 +721,23 @@ With the expected results:
@section{Decoding markup via the @tt{root} tag}
As you've seen, the X-expression you get when you run a Pollen markup file always starts with a node called @tt{root}. You can attach a tag function to @tt{root} the same way as any other tag. For instance, you could do something simple, like change the name of the output X-expression:
As you've seen, the X-expression you get when you run a Pollen markup file always starts with a node called @code{root}. You can attach a tag function to @code{root} the same way as any other tag. For instance, you could do something simple, like change the name of the output X-expression:
@fileblock["article.html.pm" @codeblock|{
#lang pollen
◊(define (root . elements) `(content ,@elements))
The ◊tt{root} tag is now called ◊tt{content}.
The ◊code{root} tag is now called ◊code{content}.
}|]
Resulting in:
@repl-output{'(content "The " (tt "root") " tag is now called " (tt "content") ".")}
But unlike other tags in your document, @tt{root} contains the entire content of the document. So the function you attach to @tt{root} can operate on everything.
But unlike other tags in your document, @code{root} contains the entire content of the document. So the function you attach to @code{root} can operate on everything.
For that reason, one of the most useful things you can do with a tag function attached to @tt{root} is @italic{decoding} the content of the page. Decoding refers to any post-processing of content that happens after the tags within the page have been evaluated.
For that reason, one of the most useful things you can do with a tag function attached to @code{root} is @defterm{decoding} the content of the page. Decoding refers to any post-processing of content that happens after the tags within the page have been evaluated.
Decoding is a good way to automatically accomplish:
@ -755,7 +755,7 @@ Decoding is a good way to automatically accomplish:
]
As an example, let's take one of my favorites — linebreak and paragraph detection. In XML authoring, you have to insert every @tt{<br />} and @tt{<p>} tag by hand. This is profoundly dull, clutters up the source file, and makes editing a chore.
As an example, let's take one of my favorites — linebreak and paragraph detection. In XML authoring, you have to insert every @code{<br />} and @code{<p>} tag by hand. This is profoundly dull, clutters up the source file, and makes editing a chore.
Instead, let's make a decoder that allows us to denote a linebreak with a single newline in the source, and a paragraph break with a double newline. Here's some sample content with single and double newlines:
@ -768,7 +768,7 @@ And a new line.
The second paragraph --- isn't it great.
}|]
But without a decoder, the newlines just get passed through:
Because we don't yet have a decoder, these newlines just get passed through:
@repl-output{'(root "The first line of the 'first' paragraph." "\n" "And a new line." "\n" "\n" "The second paragraph --- isn't it great.")}
@ -804,9 +804,9 @@ And a new line.
The second paragraph --- isn't it great.
}|]
The @racket[make-txexpr] function is a utility from the @racket[txexpr] package, which is installed with Pollen. It builds a new X-expression from a tag, attribute list, and list of elements. Here, we'll keep the tag name @tt{root}, leave the attributes as @tt{null}, and append our decoded list of elements.
The @racket[make-txexpr] function is a utility from the @racket[txexpr] package, which is installed with Pollen. It builds a new X-expression from a tag, attribute list, and list of elements. Here, we'll keep the tag name @code{root}, leave the attributes as @code{null}, and append our decoded list of elements.
@margin-note{Racket jocks: you could also write this using @racket[quasiquote] and @racket[unquote-splicing] syntax as @code|{`(root ,@(decode-elements elements))}|. The @racket[txexpr] package is just a more explicit way of accomplishing the task.}
@margin-note{Racket jocks: you could also write this using @racket[quasiquote] and @racket[unquote-splicing] syntax as @code|{`(root ,@(decode-elements elements))}|. The @racket[txexpr] package is just an alternate way of accomplishing the task.}
If you run this file, what changes? Right — nothing. That's because by default, both @racket[decode-elements] (and @racket[decode]) will let the content pass through unaltered.
@ -844,7 +844,7 @@ The second paragraph --- isn't it great.
}
Of course, in practice you wouldn't put your decoding function in a single source file. You'd make it available to all your source files by putting it in @tt{directory-require.rkt}. So let's do that now:
Of course, in practice you wouldn't put your decoding function in a single source file. You'd make it available to all your source files by putting it in @filepath{directory-require.rkt}. So let's do that now:
@fileblock["directory-require.rkt" @codeblock{
#lang racket
@ -855,7 +855,7 @@ Of course, in practice you wouldn't put your decoding function in a single sourc
(provide root)
}]
We'll also restore the source of @tt{article.html.pm} to its original, simplified state:
We'll also restore the source of @filepath{article.html.pm} to its original, simplified state:
@fileblock["article.html.pm" @codeblock|{
#lang pollen
@ -891,9 +891,9 @@ This time, however, we're going to attach them to another part of @racket[decode
(provide root)
}]
Because @racket[#:string-proc] only accepts one function (not two), we need to use @racket[compose] to combine @racket[smart-quotes] and @racket[smart-dashes] into one (@racket[compose] will apply the last function, then the previous one, and so on to the left end of the list).
Because @racket[#:string-proc] only accepts one function (not two), we need to use @racket[compose] to combine @racket[smart-quotes] and @racket[smart-dashes] into one (@racket[compose], from the Racket library, will apply the last function, then the previous one, and so on to the left end of the list).
Now, if we run @tt{article.html.pm} in DrRacket, we can see the effects of the new decoder functions. The quotes are curled, and the three hyphens become an em dash:
Now, if we run @filepath{article.html.pm} in DrRacket, we can see the effects of the new decoder functions. The quotes are curled, and the three hyphens become an em dash:
@repl-output{'(root (p "The first line of the first paragraph." (br) "And a new line.") (p "The second paragraph—isnt it great."))}
@ -906,7 +906,7 @@ And a new line.
The second paragraph—isnt it great.
}
By the way, even though decoding via the @tt{root} tag is the most likely usage scenario, you don't have to do it that way. Decoding is just a special kind of tag function. So you can make a decoder that only affects a certain tag within the page. Or you can make multiple decoders for different tags. The advantage of using a decoder with @tt{root} is that it can affect all the content, and since it's attached to the root node, it will always be the last tag function that gets called.
By the way, even though decoding via the @code{root} tag is the most likely use case, you don't have to do it that way. Decoding is just a special kind of tag function. So you can make a decoder that only affects a certain tag within the page. Or you can make multiple decoders for different tags. The advantage of using a decoder with @code{root} is that it can affect all the content, and since it's attached to the root node, it will always be the last tag function that gets called.
@section{Putting it all together}
@ -917,11 +917,11 @@ It also provides a recipe you can adapt for your own projects, whether small or
As we go through the ingredients, I'll review the purpose of each. Save these files into a single project directory with the project server running.
@subsection[#:tag-prefix "tutorial-3"]{The @tt{directory-require.rkt} file}
@subsection[#:tag-prefix "tutorial-3"]{The @filepath{directory-require.rkt} file}
This file provides functions that are available to all Pollen source files in the same directory. It's written in standard Racket. The @tt{directory-require.rkt} file is optional — without it, your tags will just be treated as default tag functions. But you'll probably find it a convenient way to make tag functions available within your project, including a @racket[decode] function attached to @tt{root}.
This file provides functions that are available to all Pollen source files in the same directory. It's written in standard Racket. The @filepath{directory-require.rkt} file is optional — without it, your tags will just be treated as default tag functions. But you'll probably find it a convenient way to make tag functions available within your project, including a @racket[decode] function attached to @code{root}.
Here, we'll use the @tt{directory-require.rkt} we devised in the previous section to set up decoding for our source files:
Here, we'll use the @filepath{directory-require.rkt} we devised in the previous section to set up decoding for our source files:
@fileblock["directory-require.rkt" @codeblock{
#lang racket/base
@ -938,9 +938,9 @@ Here, we'll use the @tt{directory-require.rkt} we devised in the previous sectio
When you're using Pollen authoring mode for your content — using either Markdown syntax, or Pollen markup — your source files will produce an X-expression. To convert this X-expression into a finished file, you need to use a template.
By default, when Pollen finds a source file called @tt{filename.ext.pm} or @tt{filename.ext.pmd}, it will look for a template in your project directory called @tt{template.ext}, where @tt{.ext} is the matching output extension.
By default, when Pollen finds a source file called @filepath{filename.ext.pm} or @filepath{filename.ext.pmd}, it will look for a template in your project directory called @filepath{template.ext}, where @filepath{.ext} is the matching output extension.
In this project, we want to end up with HTML, so our source files will be called @tt{filename.html.pm}, and thus we need to make a @tt{template.html}. Let's use a modified version of the one we made in the second tutorial:
In this project, we want to end up with HTML, so our source files will be called @filepath{filename.html.pm}, and thus we need to make a @filepath{template.html}. Let's use a modified version of the one we made in the second tutorial:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
@ -966,7 +966,7 @@ In this project, we want to end up with HTML, so our source files will be called
A pagetree defines sequential and hierarchical relationships among a set of output files. The pagetree is used by the template to calculate navigational links (e.g., previous, next, up, etc.) A pagetree is optional — if you don't need navigation in your project, you don't need a pagetree.
But in this project, we do want navigation. So we'll add an @tt{index.ptree} file like so:
But in this project, we do want navigation. So we'll add an @filepath{index.ptree} file like so:
@fileblock["index.ptree"
@codeblock{
@ -979,11 +979,11 @@ sermon.html
@subsection{A CSS stylesheet using the preprocessor}
Our template file above refers to a CSS file called @tt{styles.css}. When resolving linked files, the project server makes no distinction between static and dynamic files. If there's a static file called @tt{styles.css}, it will use that.
Our template file above refers to a CSS file called @filepath{styles.css}. When resolving linked files, the project server makes no distinction between static and dynamic files. If there's a static file called @filepath{styles.css}, it will use that.
Or, if you make a preprocessor source file called @tt{styles.css.pp}, it will be dynamically rendered into the requested @tt{styles.css} file. The preprocessor will operate on any file with the @tt{.pp} extension — so a preprocessor source called @tt{filename.ext.pp} will be rendered into @tt{filename.ext}. (The corollary is that preprocessor functionality can be added to @italic{any} kind of text-based file.)
Or, if you make a preprocessor source file called @filepath{styles.css.pp}, it will be dynamically rendered into the requested @filepath{styles.css} file. The preprocessor will operate on any file with the @filepath{.pp} extension — so a preprocessor source called @filepath{filename.ext.pp} will be rendered into @filepath{filename.ext}. (The corollary is that preprocessor functionality can be added to @italic{any} kind of text-based file.)
Preprocessor source files, like authoring source files, get access to everything in @tt{directory-require.rkt}, so you can share common functions and variables.
Preprocessor source files, like authoring source files, get access to everything in @filepath{directory-require.rkt}, so you can share common functions and variables.
Let's use an improved version of the dynamic CSS file we made in the first tutorial.
@ -1024,7 +1024,7 @@ h1 {
@subsection{The content source files using Pollen markup}
With the scaffolding in place, we need the content. Our pagetree contains three output files — @tt{burial.html}, @tt{chess.html}, and @tt{sermon.html}. We're going to make these output files using Pollen markup. So we'll create three source files and name them by adding the @tt{.pm} source extension to each of the output names — thus @tt{burial.html.pm}, @tt{chess.html.pm}, and @tt{sermon.html.pm}, as follows (and with apologies to T. S. Eliot):
With the scaffolding in place, we need the content. Our pagetree contains three output files — @filepath{burial.html}, @filepath{chess.html}, and @filepath{sermon.html}. We're going to make these output files using Pollen markup. So we'll create three source files and name them by adding the @filepath{.pm} source extension to each of the output names — thus @filepath{burial.html.pm}, @filepath{chess.html.pm}, and @filepath{sermon.html.pm}, as follows (and with apologies to T. S. Eliot):
@fileblock["burial.html.pm" @codeblock[#:keep-lang-line? #f]{
@ -1089,21 +1089,21 @@ I made no comment. What should I resent?"
@subsection{The result}
Now visit the project server and view @tt{burial.html}, which should look something like this (the box will expand to fit your browser window):
Now visit the project server and view @filepath{burial.html}, which should look something like this (the box will expand to fit your browser window):
@image/rp["burial.png" #:scale 0.8]
Click the navigational links at the top to move between pages. You're encouraged to change the source files, the style sheet, the template, or @tt{directory-require.rkt}, and see how these changes immediately affect the page rendering in the project server. (You can also change the sequence of the pages in @tt{index.ptree}, but in that case, you'll need to restart the project server to see the change.)
Click the navigational links at the top to move between pages. You're encouraged to change the source files, the style sheet, the template, or @filepath{directory-require.rkt}, and see how these changes immediately affect the page rendering in the project server. (You can also change the sequence of the pages in @filepath{index.ptree}, but in that case, you'll need to restart the project server to see the change.)
This page isn't a miracle of web design, but it shows you in one example:
@itemlist[
@item{Pollen markup being decoded — paragraph breaks, linebreaks, smart quotes, smart dashes — with a @racket[decode] function attached to the @tt{root} node by @tt{directory-require.rkt};}
@item{Pollen markup being decoded — paragraph breaks, linebreaks, smart quotes, smart dashes — with a @racket[decode] function attached to the @code{root} node by @filepath{directory-require.rkt};}
@item{A dynamically-generated CSS file that computes positions for CSS elements using numerical values set up with @racket[define], and mathematical conversions thereof;}
@item{Navigational links that appear and disappear as needed using conditional statements (@racket[when/block]) in @tt{template.html}, with the page sequence defined by @tt{index.ptree} and the names of the links being pulled from the @tt{h1} tag of each source file using @racket[select].}
@item{Navigational links that appear and disappear as needed using conditional statements (@racket[when/block]) in @filepath{template.html}, with the page sequence defined by @filepath{index.ptree} and the names of the links being pulled from the @code{h1} tag of each source file using @racket[select].}
]

@ -26,13 +26,13 @@ A parameter that sets the HTTP port for the project server. Initialized to @rack
The two exports from a compiled Pollen source file. Initialized to @racket['doc] and @racket['metas], respectively.
@(defthing world:directory-require string?)
File implicitly required into every Pollen source file from its directory. Initialized to @racket["directory-require.rkt"].
File implicitly required into every Pollen source file from its directory. Initialized to @filepath{directory-require.rkt}.
@defparam[world:check-directory-requires-in-render? check? boolean?]{
A parameter that determines whether the @racket[world:directory-require] file is checked for changes on every pass through @racket[render]. (Can be faster to turn this off if you don't need it.) Initialized to @racket[#t].}
@defthing[world:server-extras-dir string?]
Name of directory where server support files live. Initialized to @racket["server-extras"].
Name of directory where server support files live. Initialized to @tt{server-extras}.
@defparam[world:current-server-extras-path dir path?]{
A parameter that reports the path to the directory of support files for the project server. Initialized to @racket[#f], but set to a proper value when the server runs.}
@ -49,13 +49,13 @@ A parameter that reports the path to the directory of support files for the proj
)]
File extensions for Pollen source files, initialized to the following values:
@racket[world:preproc-source-ext] = @code[(format "~a" world:preproc-source-ext)]
@(linebreak)@racket[world:markup-source-ext] = @code[(format "~a" world:markup-source-ext)]
@(linebreak)@racket[world:markdown-source-ext] = @code[(format "~a" world:markdown-source-ext)]
@(linebreak)@racket[world:null-source-ext] = @code[(format "~a" world:null-source-ext)]
@(linebreak)@racket[world:pagetree-source-ext] = @code[(format "~a" world:pagetree-source-ext)]
@(linebreak)@racket[world:template-source-ext] = @code[(format "~a" world:template-source-ext)]
@(linebreak)@racket[world:scribble-source-ext] = @code[(format "~a" world:scribble-source-ext)]
@racket[world:preproc-source-ext] = @code[(format "'~a" world:preproc-source-ext)]
@(linebreak)@racket[world:markup-source-ext] = @code[(format "'~a" world:markup-source-ext)]
@(linebreak)@racket[world:markdown-source-ext] = @code[(format "'~a" world:markdown-source-ext)]
@(linebreak)@racket[world:null-source-ext] = @code[(format "'~a" world:null-source-ext)]
@(linebreak)@racket[world:pagetree-source-ext] = @code[(format "'~a" world:pagetree-source-ext)]
@(linebreak)@racket[world:template-source-ext] = @code[(format "'~a" world:template-source-ext)]
@(linebreak)@racket[world:scribble-source-ext] = @code[(format "'~a" world:scribble-source-ext)]
@defthing[world:decodable-extensions (listof symbol?)]
@ -71,27 +71,27 @@ File extensions that are eligible for decoding.
)]
Mode indicators for the Pollen reader and parser. Initialized to the following values:
@racket[world:mode-auto] = @code[(format "~a" world:mode-auto)]
@(linebreak)@racket[world:mode-preproc] = @code[(format "~a" world:mode-preproc)]
@(linebreak)@racket[world:mode-markup] = @code[(format "~a" world:mode-markup)]
@(linebreak)@racket[world:mode-markdown] = @code[(format "~a" world:mode-markdown)]
@(linebreak)@racket[world:mode-pagetree] = @code[(format "~a" world:mode-pagetree)]
@racket[world:mode-auto] = @code[(format "'~a" world:mode-auto)]
@(linebreak)@racket[world:mode-preproc] = @code[(format "'~a" world:mode-preproc)]
@(linebreak)@racket[world:mode-markup] = @code[(format "'~a" world:mode-markup)]
@(linebreak)@racket[world:mode-markdown] = @code[(format "'~a" world:mode-markdown)]
@(linebreak)@racket[world:mode-pagetree] = @code[(format "'~a" world:mode-pagetree)]
@defthing[world:default-pagetree string?]
Pagetree that Pollen dashboard loads by default in each directory. Initialized to @racket["index.ptree"].
Pagetree that Pollen dashboard loads by default in each directory. Initialized to @filepath{index.ptree}.
@defthing[world:pagetree-root-node symbol?]
Name of the root node in a decoded pagetree. It's ignored by the code, so its only role is to clue you in that you're looking at something that came out of the pagetree decoder. Initialized to @racket['pagetree-root].
Name of the root node in a decoded pagetree. It's ignored by the code, so its only role is to clue you in that you're looking at something that came out of the pagetree decoder. Initialized to @code{'pagetree-root}.
@defthing[world:command-marker char?]
The magic character that indicates a Pollen command, function, or variable. Initialized to @racket[#\◊].
@defthing[world:default-template-prefix string?]
Prefix of the default template. Initialized to @racket["template"].
Prefix of the default template. Initialized to @code{"template"}.
@defthing[world:fallback-template-prefix string?]
Used to generate the name of the fallback template (i.e., the template used to render a Pollen markup file when no other template can be found). Prefix is combined with the output suffix of the source file. Initialized to @racket["fallback"].
Used to generate the name of the fallback template (i.e., the template used to render a Pollen markup file when no other template can be found). Prefix is combined with the output suffix of the source file. Initialized to @code{"fallback"}.
@defthing[world:template-meta-key symbol?]
Meta key used to store a template name for that particular source file. Initialized to @racket['template].
@ -104,7 +104,7 @@ Meta key used to store a template name for that particular source file. Initiali
Default separators used in decoding. The first two are initialized to @racket["\n"]; the third to @racket["\n\n"].
@(defthing world:dashboard-css string?)
CSS file used for the dashboard. Initialized to @racket["poldash.css"].
CSS file used for the dashboard. Initialized to @filepath{poldash.css}.
@(defthing world:paths-excluded-from-dashboard (listof path?))
Paths not shown in the Pollen dashboard.

Loading…
Cancel
Save