From 5f9fd6bd19446dd4d35e45861caa307f7afae1a9 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Mon, 4 May 2015 22:52:49 -0400 Subject: [PATCH] documentation edits --- scribblings/big-picture.scrbl | 33 ++--- scribblings/command.scrbl | 48 +++---- scribblings/decode.scrbl | 2 +- scribblings/file.scrbl | 2 +- scribblings/formats.scrbl | 28 ++-- scribblings/installation.scrbl | 13 +- scribblings/pagetree.scrbl | 2 +- scribblings/pollen.scrbl | 2 +- scribblings/quick.scrbl | 114 ++++++++-------- scribblings/raco.scrbl | 26 ++-- scribblings/render.scrbl | 11 +- scribblings/story.scrbl | 30 ++--- scribblings/template.scrbl | 4 +- scribblings/tutorial-first.scrbl | 108 +++++++-------- scribblings/tutorial-second.scrbl | 213 ++++++++++++++++-------------- scribblings/tutorial-third.scrbl | 140 ++++++++++---------- scribblings/world.scrbl | 38 +++--- 17 files changed, 420 insertions(+), 394 deletions(-) diff --git a/scribblings/big-picture.scrbl b/scribblings/big-picture.scrbl index 748b632..0b790a1 100644 --- a/scribblings/big-picture.scrbl +++ b/scribblings/big-picture.scrbl @@ -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[ diff --git a/scribblings/command.scrbl b/scribblings/command.scrbl index 08ccf0b..fd2271b 100644 --- a/scribblings/command.scrbl +++ b/scribblings/command.scrbl @@ -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 # 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 key–value 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 key–value 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 symbol–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: @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. \ No newline at end of file +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. \ No newline at end of file diff --git a/scribblings/decode.scrbl b/scribblings/decode.scrbl index 15855f6..5a438ec 100644 --- a/scribblings/decode.scrbl +++ b/scribblings/decode.scrbl @@ -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) diff --git a/scribblings/file.scrbl b/scribblings/file.scrbl index 1869af1..bf39285 100644 --- a/scribblings/file.scrbl +++ b/scribblings/file.scrbl @@ -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[ diff --git a/scribblings/formats.scrbl b/scribblings/formats.scrbl index 78e9178..ae4ca30 100644 --- a/scribblings/formats.scrbl +++ b/scribblings/formats.scrbl @@ -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 key–value 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 key–value 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. diff --git a/scribblings/installation.scrbl b/scribblings/installation.scrbl index 7fad77f..6638fd6 100644 --- a/scribblings/installation.scrbl +++ b/scribblings/installation.scrbl @@ -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} \ No newline at end of file diff --git a/scribblings/pagetree.scrbl b/scribblings/pagetree.scrbl index ce0c7b1..abf4555 100644 --- a/scribblings/pagetree.scrbl +++ b/scribblings/pagetree.scrbl @@ -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? diff --git a/scribblings/pollen.scrbl b/scribblings/pollen.scrbl index 157a8a6..18c6000 100644 --- a/scribblings/pollen.scrbl +++ b/scribblings/pollen.scrbl @@ -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 diff --git a/scribblings/quick.scrbl b/scribblings/quick.scrbl index caa3661..a3e4c15 100644 --- a/scribblings/quick.scrbl +++ b/scribblings/quick.scrbl @@ -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 }] -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 }] -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 }] -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{tags}? 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{tags}? 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 }] -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. \ No newline at end of file +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. \ No newline at end of file diff --git a/scribblings/raco.scrbl b/scribblings/raco.scrbl index af1e642..88f3bf1 100644 --- a/scribblings/raco.scrbl +++ b/scribblings/raco.scrbl @@ -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} diff --git a/scribblings/render.scrbl b/scribblings/render.scrbl index bc468a3..e352b5e 100644 --- a/scribblings/render.scrbl +++ b/scribblings/render.scrbl @@ -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]). \ No newline at end of file diff --git a/scribblings/story.scrbl b/scribblings/story.scrbl index e770fb5..db108a5 100644 --- a/scribblings/story.scrbl +++ b/scribblings/story.scrbl @@ -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{

...

}? 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{

...

}? 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. - - - diff --git a/scribblings/template.scrbl b/scribblings/template.scrbl index 9089f04..9c6c749 100644 --- a/scribblings/template.scrbl +++ b/scribblings/template.scrbl @@ -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 diff --git a/scribblings/tutorial-first.scrbl b/scribblings/tutorial-first.scrbl index d808d6a..ea116c6 100644 --- a/scribblings/tutorial-first.scrbl +++ b/scribblings/tutorial-first.scrbl @@ -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 doesn’t 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{
} tag, the poem will appear in a monospaced font, and the line breaks will be preserved:
+But now, because of the @code{
} 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{} 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{} 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.
 
 }
 
-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{} of the page, we'll put them in a CSS @tt{