Index: .fossil-settings/ignore-glob
==================================================================
--- .fossil-settings/ignore-glob
+++ .fossil-settings/ignore-glob
@@ -1,21 +1,20 @@
*compiled/*
*.woff*
x-*/*
*.*~
-web-extra/martin.css
+web/martin.css
scribbled/*
-code-docs/*.css
-code-docs/*.js
+yarn-doc/*.css
+yarn-doc/*.js
*/images/*
*.db
*.sqlite
*.pdf
-*.ltx
*.html
*.out
*.ltx
*.aux
*.log
*.xml
*.toc
*.mark
DELETED cache.rkt
Index: cache.rkt
==================================================================
--- cache.rkt
+++ cache.rkt
@@ -1,209 +0,0 @@
-#lang racket/base
-
-; SPDX-License-Identifier: BlueOak-1.0.0
-; This file is licensed under the Blue Oak Model License 1.0.0.
-
-(require deta
- db/base
- db/sqlite3
- threading
- pollen/setup
- racket/match
- "dust.rkt"
- (except-in pollen/core select))
-
-(provide init-cache-db!
- cache-conn ; The most eligible bachelor in Neo Yokyo
- (schema-out cache:article)
- (schema-out cache:note)
- (schema-out cache:index-entry)
- (schema-out listing)
- delete-article!
- delete-notes!
- delete-index-entries!
- save-cache-things!
- articles
- articles+notes
- listing-htmls
- fenced-listing
- unfence)
-
-;; Cache DB and Schemas
-
-(define DBFILE (build-path (current-project-root) "vitreous.sqlite"))
-(define cache-conn (make-parameter (sqlite3-connect #:database DBFILE #:mode 'create)))
-
-(define-schema cache:article #:table "articles"
- ([id id/f #:primary-key #:auto-increment]
- [page symbol/f]
- [title-plain string/f #:nullable]
- [title-html-flow string/f #:nullable]
- [title-specified? boolean/f #:nullable]
- [published string/f #:nullable]
- [updated string/f #:nullable]
- [author string/f #:nullable]
- [conceal string/f]
- [series-page symbol/f #:nullable]
- [noun-singular string/f #:nullable]
- [note-count integer/f #:nullable]
- [content-html string/f #:nullable]
- [disposition string/f #:nullable]
- [disp-html-anchor string/f #:nullable]
- [listing-full-html string/f #:nullable] ; full content but without notes
- [listing-excerpt-html string/f #:nullable] ; Not used for now
- [listing-short-html string/f #:nullable])) ; Date and title only
-
-(define-schema cache:note #:table "notes"
- ([id id/f #:primary-key #:auto-increment]
- [page symbol/f]
- [html-anchor string/f]
- [title-html-flow string/f] ; No block-level HTML elements
- [title-plain string/f]
- [author string/f]
- [author-url string/f]
- [published string/f]
- [disposition string/f]
- [content-html string/f]
- [series-page symbol/f]
- [conceal string/f]
- [listing-full-html string/f]
- [listing-excerpt-html string/f] ; Not used for now
- [listing-short-html string/f])) ; Date and title only
-
-(define-schema cache:index-entry #:table "index_entries"
- ([id id/f #:primary-key #:auto-increment]
- [entry string/f]
- [subentry string/f]
- [page symbol/f]
- [html-anchor string/f]))
-
-(define-schema listing
- #:virtual
- ([path string/f]
- [title string/f]
- [author string/f]
- [published string/f]
- [updated string/f]
- [html string/f]))
-
-(define (init-cache-db!)
- (create-table! (cache-conn) 'cache:article)
- (create-table! (cache-conn) 'cache:note)
- (create-table! (cache-conn) 'cache:index-entry))
-
-(define (delete-article! page)
- (query-exec (cache-conn)
- (~> (from cache:article #:as a)
- (where (= a.page ,(format "~a" page)))
- delete)))
-
-(define (delete-notes! page)
- (query-exec (cache-conn)
- (~> (from cache:note #:as n)
- (where (= n.page ,(format "~a" page)))
- delete)))
-
-(define (delete-index-entries! page)
- (query-exec (cache-conn)
- (~> (from cache:index-entry #:as e)
- (where (= e.page ,(format "~a" page)))
- delete)))
-
-(define (save-cache-things! es)
- (void (apply insert! (cache-conn) es)))
-
-;;
-;; ~~~ Fetching articles and notes ~~~
-;;
-
-;; (Private use) Conveniece function for the WHERE `series-page` clause
-(define (where-series q s)
- (define (s->p x) (format "~a/~a.html" series-folder x))
- (match s
- [(list series ...)
- (where q (in a.series-page ,(map s->p series)))] ; WHERE series-page IN (item1 ...)
- [(or (? string? series) (? symbol? series))
- (where q (= a.series-page ,(s->p series)))] ; WHERE series-page = "item"
- [#t
- (where q (like a.series-page ,(format "%~a" (here-output-path))))]
- [_ q]))
-
-;; (Private use) Convenience for the WHERE `conceal` NOT LIKE clause
-(define (where-not-concealed q)
- (define base-clause (where q (not (like a.conceal "%all%"))))
- (match (listing-context)
- ["" base-clause]
- [(var context) (where base-clause (not (like a.conceal ,(format "%~a%" context))))]))
-
-;; Needed to "parameterize" column names
-;; see https://github.com/Bogdanp/deta/issues/14#issuecomment-573344928
-(require (prefix-in ast: deta/private/ast))
-
-;; Builds a query to fetch articles
-(define (articles type #:series [s #t] #:limit [lim -1] #:order [ord 'desc])
- (define html-field
- (match type
- ['content "content_html"]
- [_ (format "listing_~a_html" type)]))
- (~> (from cache:article #:as a)
- (select (as a.page path)
- (as a.title-plain title)
- a.author
- a.published
- a.updated
- (fragment (ast:as (ast:qualified "a" html-field) "html")))
- (where-series s)
- (where-not-concealed)
- (limit ,lim)
- (order-by ([a.published ,ord]))
- (project-onto listing-schema)))
-
-;; Builds a query that returns articles and notes intermingled chronologically
-(define (articles+notes type #:series [s #t] #:limit [lim -1] #:order [ord 'desc])
- (define html-field
- (match type
- ['content "content_html"]
- [_ (format "listing_~a_html" type)]))
- (~> (from (subquery
- (~> (from cache:article #:as A)
- (select
- (as A.page path)
- (as A.title-plain title)
- A.author
- A.published
- A.updated
- (fragment (ast:as (ast:qualified "A" html-field) "html"))
- A.series-page
- A.conceal)
- (union
- (~> (from cache:note #:as N)
- (select
- (as (array-concat N.page "#" N.html-anchor) path)
- (as N.title-plain title)
- N.author
- N.published
- (as "" updated)
- (fragment (ast:as (ast:qualified "N" html-field) "html"))
- N.series-page
- N.conceal)))))
- #:as a)
- (where-series s)
- (where-not-concealed)
- (limit ,lim)
- (order-by ([a.published ,ord]))
- (project-onto listing-schema)))
-
-;; Get all the a list of the HTML all the results in a query
-(define (listing-htmls list-query)
- (for/list ([l (in-entities (cache-conn) list-query)])
- (listing-html l)))
-
-;; Return cached HTML of articles and/or notes, fenced within a style txexpr to prevent it being
-;; escaped by ->html. See also: definition of `unfence`
-(define (fenced-listing q)
- `(style ,@(listing-htmls q)))
-
-;; Remove "" introduced by using ->html on docs containing output from
-;; listing functions
-(define (unfence html-str)
- (regexp-replace* #px"<[\\/]{0,1}style>" html-str ""))
DELETED code-docs/cache.scrbl
Index: code-docs/cache.scrbl
==================================================================
--- code-docs/cache.scrbl
+++ code-docs/cache.scrbl
@@ -1,246 +0,0 @@
-#lang scribble/manual
-
-@; SPDX-License-Identifier: BlueOak-1.0.0
-@; This file is licensed under the Blue Oak Model License 1.0.0.
-
-@(require "scribble-helpers.rkt" scribble/example)
-
-@(require (for-label deta
- db
- racket/base
- racket/contract
- sugar/coerce
- pollen/template
- "../dust.rkt"
- "../crystalize.rkt"
- "../cache.rkt"))
-
-@(define example-eval (make-base-eval))
-@(example-eval '(require "cache.rkt" txexpr))
-
-@title[#:tag "cache-rkt"]{Cache}
-
-@defmodule["cache.rkt" #:packages ()]
-
-In this project there are several places – the blog, the footer on each page, the RSS feed, series
-pages — where data from an amorphous group of Pollen documents is needed. This is what the cache is
-for.
-
-This module defines and provides the schema and database connection to the SQLite cache, and some
-functions for retrieving records from the cache. Use these when you need quick access to pre-cooked
-HTML.
-
-@section{Cache database}
-
-@defparam[cache-conn conn connection?]{
-The database connection.
-}
-
-@defproc[(init-cache-db!) void?]{
-
-Creates and initializes the SQLite database cache file (named @filepath{vitreous.sqlite} and located
-in the project root folder) by running queries to create tables in the database if they do not
-exist.
-
-}
-
-@section{Retrieving cached data}
-
-Some of this looks a little wacky, but it’s a case of putting a little extra complextity into the
-back end to make things simple on the front end. These functions are most commonly used inside the
-@emph{body} of a Pollen document (i.e., series pages).
-
-@filebox["series/my-series.poly.pm"
-@codeblock|{
-#lang pollen
-
-◊title{My New Series}
-
-...some other content
-
-◊fenced-listing[(articles+notes 'excerpt #:order 'asc)]
-}|
-]
-
-@defproc[(fenced-listing [query query?]) txexpr?]{
-
-Fetches a the HTML strings from the SQLite cache and returns a @racket['style] tagged X-expression
-with these strings as its elements. The @racket[_query] will usually be the result of a call to
-@racket[articles] or @racket[articles+notes], but can be any custom query that projects onto the
-@racket[listing] schema (see @racket[project-onto]).
-
-The reason for enclosing the results in a @racket['style] txexpr is to prevent the HTML from being
-escaped by @racket[->html] in the template. This tag was picked for the job because there will
-generally never be a need to include any actual CSS information inside a @tt{"] removed.
-The contents of the style tags are left intact.
-
-Use this in templates with strings returned from @racket[->html] when called on docs that use the
-@racket[fenced-listing] tag function.
-
-}
-
-@section{Modifying the cache}
-
-@defproc[(save-cache-things!
- [things (listof (or/c cache:article? cache:note? cache:index-entry?))]) void?]{
-
-Saves all the @racket[_thing]s to the cache database.
-
-}
-
-@deftogether[(@defproc[(delete-article! [page stringish?]) void?]
- @defproc[(delete-notes! [page stringish?]) void?])]{
-
-Delete a particular article, or all notes for a particular article, respectively.
-
-}
-
-@section{Schema}
-
-The cache database has four tables: @tt{articles}, @tt{notes}, @tt{index_entries} and @tt{series}.
-Each of these has a corresponding schema, shown below. In addition, there is a “virtual” schema,
-@tt{listing}, for use with queries which may or may not combine articles and notes intermingled.
-
-The work of picking apart an article’s exported @tt{doc} and @tt{metas} into rows in these tables is
-done by @racket[parse-and-cache-article!].
-
-The below are shown as @code{struct} forms but are actually defined with deta’s
-@racket[define-schema]. Each schema has an associated struct with the same name and a smart
-constructor called @tt{make-@emph{id}}. The struct’s “dumb” constructor is hidden so that invalid
-entities cannot be created. For every defined field there is an associated functional setter and
-updater named @tt{set-@emph{id}-field} and @tt{update-@emph{id}-field}, respectively.
-
-@defstruct*[cache:article ([id id/f]
- [page symbol/f]
- [title-plain string/f]
- [title-html-flow string/f]
- [title-specified boolean/f]
- [published string/f]
- [updated string/f]
- [author string/f]
- [conceal string/f]
- [series-page string/f]
- [noun-singular string/f]
- [note-count integer/f]
- [content-html string/f]
- [disposition string/f]
- [disp-html-anchor string/f]
- [listing-full-html string/f]
- [listing-excerpt-html string/f]
- [listing-short-html string/f])
- #:constructor-name make-cache:article]{
-
-Table holding cached @tech{article} information.
-
-When creating a @racket[cache:article] (should you ever need to do so directly, which is unlikely),
-the only required fields are @racket[_page], @racket[_title], and @racket[_conceal].
-
-}
-
-@defstruct*[cache:note ([id id/f]
- [page symbol/f]
- [html-anchor string/f]
- [title-html-flow string/f]
- [title-plain string/f]
- [author string/f]
- [author-url string/f]
- [published string/f]
- [disposition string/f]
- [content-html string/f]
- [series-page symbol/f]
- [conceal string/f]
- [listing-full-html string/f]
- [listing-excerpt-html string/f]
- [listing-short-html string/f])
- #:constructor-name make-cache:note]{
-
-Table holding cached information on @tech{notes}.
-
-}
-
-@defstruct*[cache:index-entry ([id id/f]
- [entry string/f]
- [subentry string/f]
- [page symbol/f]
- [html-anchor string/f])
- #:constructor-name make-cache:index-entry]{
-
-Table holding cached information about index entries found in @tech{articles}.
-
-}
-
-@defstruct*[listing ([path string/f]
- [title string/f]
- [author string/f]
- [published string/f]
- [updated string/f]
- [html string/f])
- #:constructor-name make-listing]{
-
-This is a “virtual” schema targeted by @racket[articles] and @racket[articles+notes] using deta’s
-@racket[project-onto]. It supplies the minimum set of fields needed to build the RSS feed, and which
-are common to both articles and notes; most times (e.g., on @tech{series} pages) only the @tt{html}
-field is used, via @racket[fenced-listing] or @racket[listing-htmls].
-
-}
DELETED code-docs/crystalize.scrbl
Index: code-docs/crystalize.scrbl
==================================================================
--- code-docs/crystalize.scrbl
+++ code-docs/crystalize.scrbl
@@ -1,61 +0,0 @@
-#lang scribble/manual
-
-@; SPDX-License-Identifier: BlueOak-1.0.0
-@; This file is licensed under the Blue Oak Model License 1.0.0.
-
-@(require "scribble-helpers.rkt")
-
-@(require (for-label "../pollen.rkt"
- "../crystalize.rkt"
- "../cache.rkt"
- racket/base
- racket/contract
- racket/string
- txexpr
- pollen/core
- pollen/pagetree))
-
-@title[#:tag "crystalize-rkt"]{Crystalize}
-
-@defmodule["crystalize.rkt" #:packages ()]
-
-“Crystalizing” is an extra layer in between docs and templates that destructures the @tt{doc} and
-stores it in various pieces in a SQLite cache. Individual articles save chunks of rendered HTML to
-the cache when their individual pages are rendered. When pulling together listings of articles in
-different contexts that need to be filtered and sorted, a SQL query is much faster than trolling
-through the Pollen cache for matching docs and regenerating the HTML.
-
-@margin-note{These functions are designed to be used within templates, so that the rows in the cache
-database for a page are updated right when that web page is rendered.}
-
-@defproc[(parse-and-cache-article! [pagenode pagenode?] [doc txexpr?])
- (values non-empty-string? non-empty-string?)]{
-
-Returns two values: the “plain” title of the article, and a string containing the full HTML of
-@racket[_doc], in that order.
-
-The title is returned separately for use in the HTML @tt{
} tag. If the @racket[_doc] doesn’t
-specify a title, a provisional title is constructed using @racket[default-title].
-
-Privately, it does a lot of other work. The article is analyzed, additional metadata is constructed
-and saved to the SQLite cache and saved using @racket[make-cache:article]. If the article specifies
-a @racket['series] meta, information about that series is fetched and used in the rendering of the
-article. If there are @racket[note]s or @racket[index] tags in the doc, they are parsed and saved
-individually to the SQLite cache (using @racket[make-cache:note] and
-@racket[make-cache:index-entry]). If any of the notes use the @code{#:disposition} attribute,
-information about the disposition is parsed out and used in the rendering of the article.
-
-}
-
-@defproc[(cache-index-entries-only! [title string?] [page pagenode?] [doc txexpr?]) void?]{
-
-Saves only the @racket[index] entres in @racket[_doc] to the cache database, so that they appear in
-the keyword index.
-
-This function allows pages that are not @tech{articles} to have their own keyword index entries, and
-should be used in the templates for such pages.
-
-As a side effect of calling this function, a minimal @racket[cache:article] is created for the page
-with its @racket['conceal] meta set to @racket{all}, to exclude it from any listings.
-
-}
DELETED code-docs/custom.css
Index: code-docs/custom.css
==================================================================
--- code-docs/custom.css
+++ code-docs/custom.css
@@ -1,28 +0,0 @@
-.fileblock .SCodeFlow {
- padding-top: 0.7em;
- margin-top: 0;
-}
-
-.fileblock {
- width: 90%;
-}
-
-.fileblock_filetitle{
- background: #eee;
- text-align:right;
- padding: 0.15em;
- border: 1px dotted black;
- border-bottom: none;
-}
-
-.terminal, .browser {
- margin-bottom: 1em;
- padding: 0.5em;
- width: 88%;
- background: #fcfcfc;
- color: rgb(150, 35, 105);
-}
-
-.terminal .SIntrapara, .browser .SIntrapara, .fileblock .SIntrapara {
- margin: 0 0 0 0;
-}
DELETED code-docs/design.scrbl
Index: code-docs/design.scrbl
==================================================================
--- code-docs/design.scrbl
+++ code-docs/design.scrbl
@@ -1,172 +0,0 @@
-#lang scribble/manual
-
-@; SPDX-License-Identifier: BlueOak-1.0.0
-@; This file is licensed under the Blue Oak Model License 1.0.0.
-
-@(require "scribble-helpers.rkt"
- racket/runtime-path
- (for-label "../pollen.rkt"))
-
-@(require (for-label racket/base))
-
-@title{Basic Notions}
-
-@section[#:tag "design-goals"]{Design Goals}
-
-The design of @italic{The Local Yarn} is guided by requirements that have evolved since I started
-the site in 1999. I enumerate them here because they explain why the code is necessarily more
-complicated than a typical blog:
-
-@itemlist[
- @item{@bold{The writing will publish to two places from the same source: the web server, and the
- bookshelf.} The web server, because it’s a fun, fast way to publish writing and code to the whole
- world (you knew that already); but also on bookshelves, because
- @ext-link["https://thelocalyarn.com/excursus/secretary/posts/web-books.html"]{a web server is like
- a projector}, and I want to be able to turn it off someday and still have something to show for all
- my work. Plus, I just like printed books.}
-
- @item{@bold{Changes are part of the content.} I like to revisit, resurface and amend things I’ve
- written before. Views change, new ideas come along. In a typical blog the focus is always at
- whatever’s happening at the head of the time stream; an addendum to an older post is, for all
- practical purposes, invisible and nearly useless. I want every published edit to an article to be
- findable and linkable. I want addenda to be extremely visible. These addenda should also be able to
- mark major shifts in the author’s own perspective on what they originally wrote.}
-
- @item{@bold{The system will gracefully accomodate experimentation.} I should be able to write
- fiction, poetry, opinion pieces, minor observations or collections, or anything else, and have or
- create a good home for it here.}
-
- @item{@bold{Everything produced here should look good.}}
-
- @item{@bold{Reward exploration without disorienting the reader.} Draw connections between related
- thoughts using typographic conventions and organizational devices that would be familiar to
- a reader of books. Where dissimilar writings appear together, place signals that help the reader
- understand what they are looking at, switch contexts, and find more if they wish.}
-
- @item{@bold{Everything is produced, and reproducible, by an automatable process.} No clicking or
- tapping around in GUI apps to publish web pages and books.}
-
- ]
-
-@section{Names for things and how they fit together}
-
-The Local Yarn is mostly comprised of @tech{articles} (individual writings) which may contain
-@tech{notes} (addenda by the author or others) and may also be grouped into @tech{series}. These are
-similar to a typical blog’s @italic{posts}, @italic{comments} and @italic{categories}, but there are
-important differences.
-
-@subsection{Articles}
-
-The @deftech{article} is the basic unit of content, like a typical blog post. In the web edition,
-each article has its own @tt{.html} file; in print editions, an article may comprise either
-a chapter or a part of a chapter, depending on the content.
-
-An article can start out very small — just a date and a few sentences. @bold{Supplying a title is
-optional.} Later, it may grow in any of several directions: @tech{notes} can be added, or a title, or
-cross-references to later articles; or it may be added to a series. Or it may just remain the way it
-started.
-
-@subsection{Notes}
-
-A @deftech{note} is a comment or addendum to an @tech{article} using the @racket[note] tag. It may
-be written by the same person who wrote the article, or submitted by a reader.
-
-@(define-runtime-path diagram-notes "diagram-notes.png")
-@centered{@responsive-retina-image[diagram-notes]}
-
-As shown above, a note appears at the bottom of the article to which it is attached, but it also
-appears in the blog and in the RSS feed as a separate piece of content, and is given the same visual
-weight as actual articles.
-
-A note may optionally have a @deftech{disposition} which reflects a change in attitude towards its
-parent article. A disposition consists of a @italic{disposition mark} such as an asterisk or dagger,
-and a past-tense verb. For example, an author may revisit an opinion piece written years earlier and
-add a note describing how their opinion has changed; the tag for this note might include
-@racket[#:disposition "* recanted"] as an attribute. This would cause the @tt{*} to be added to the
-article’s title, and the phrase “Now considered recanted” to be added to the margin, with a link to
-the note.
-
-@subsubsection{Notes vs. blog “comments”}
-
-Typical blog comments serve as kind of a temporary discussion spot for a few days or weeks after
-a post is published. Commenting on an old post feels useless because the comment is only visible at
-the bottom of its parent post, and older posts are never “bumped” back into visibility.
-
-By contrast, notes on @italic{The Local Yarn} appear as self-contained writings at the top of the
-blog and RSS feed as soon as they are published. This “resurfaces” the original article
-to which they are attached. This extra visibility also makes them a good tool for the original
-author to fill out or update the article. In effect, with notes, each article potentially becomes
-its own miniature blog.
-
-The flip side of this change is that what used to be the “comment section” is no longer allowed to
-function as a kind of per-article chat.
-
-@tabular[#:sep @hspace[1]
- #:style 'boxed
- #:row-properties '((bottom-border top))
- (list
- (list @bold{Typical Blog Comments} @bold{Local Yarn @emph{Notes}})
- (list "Rarely used after a post has aged"
- "Commonly used on posts many years old")
- (list "Visible only at the bottom of the parent post"
- "Included in the main stream of posts and in the RSS feed alongside actual posts")
- (list "Invites any and all feedback, from small compliments to lengthy rebuttals"
- "Readers invited to treat their responses as submissions to a publication.")
- (list "Usually used by readers"
- "Usually used by the original author")
- (list "Don’t affect the original post"
- "May have properties (e.g. disposition) that change the status and
-presentation of the original post")
- (list "Moderation (if done) is typically binary: approved or not"
- "Moderation may take the form of edits and inline responses."))]
-
-@subsection{Series}
-
-A @deftech{series} is a grouping of @tech{articles} into a particular order under a descriptive
-title. A series may present its own written content alongside the listing of its articles.
-
-The page for a series can choose how to display its articles: chronologically, or in an arbitrary
-order. It can display articles only, or a mixed listing of articles and @tech{notes}, like the blog.
-And it can choose to display articles in list form, or as excerpts, or in their entirety.
-
-A series can specify @italic{nouns} (noun phrases, really) to be applied to its articles. So, for
-example, a series of forceful opinion pieces might designate its articles as @emph{naked
-aspirations}; the phrase “This is a naked aspiration, part of the series @italic{My Uncensored
-Thoughts}” would appear prominently in the margins. Likewise, a time-ordered series of observations
-might call its articles “journal entries”.
-
-It will be easy for any series to become a printed @emph{book}, using the techniques I
-demonstrated in
-@ext-link["https://thelocalyarn.com/excursus/secretary/posts/web-books.html"]{@italic{The Unbearable
-Lightness of Web Pages}}, and in @other-doc['(lib "bookcover/scribblings/bookcover.scrbl")].
-
-@subsubsection{Series vs. blog “categories”}
-
-Typical blogs are not very good at presenting content that may vary a lot in subject, length and
-style. The kind of writing I want to experiment with may change a lot from day to day, season to
-season, decade to decade. I wanted a single system that could organize extremely varied kinds of
-writings and present them in a thoughtful, coherent way, rather than starting a new blog every time
-I wanted to try writing a different kind of thing.
-
-My solution to this was to enrich the idea of “categories”. Rather than being simply labels that you
-slap on blog posts, they would be titled collections with their own unique content and way of
-presenting articles and notes. In addition, they could pass down certain properties to the posts
-they contain, that can be used to give signals to the reader about what they are looking at.
-
-@tabular[#:sep @hspace[1]
- #:style 'boxed
- #:row-properties '((bottom-border top))
- (list
- (list @bold{Typical Blog Categories/Tags} @bold{Local Yarn @emph{Series}})
- (list "Every article needs to have one"
- "Many or most articles won’t have one")
- (list "Named with a single word"
- "Named with a descriptive title")
- (list "Has no content or properties of its own"
- "Has its own written content, and properties such as nouns, ordering, etc.")
- (list "Broad in scope, few in number"
- "Narrow in scope, many in number")
- (list "Selected to be relevant for use across the entire lifetime of the site"
- "Selected without reference to future creative direction; may be closed after only
- a few articles"))]
-
DELETED code-docs/diagram-notes.png
Index: code-docs/diagram-notes.png
==================================================================
--- code-docs/diagram-notes.png
+++ code-docs/diagram-notes.png
cannot compute difference between binary files
DELETED code-docs/dust.scrbl
Index: code-docs/dust.scrbl
==================================================================
--- code-docs/dust.scrbl
+++ code-docs/dust.scrbl
@@ -1,287 +0,0 @@
-#lang scribble/manual
-
-@; SPDX-License-Identifier: BlueOak-1.0.0
-@; This file is licensed under the Blue Oak Model License 1.0.0.
-
-@(require "scribble-helpers.rkt"
- scribble/example)
-
-@(require (for-label "../pollen.rkt"
- "../dust.rkt"
- "../cache.rkt"
- "../series-list.rkt"
- racket/base
- racket/contract
- txexpr
- sugar/coerce
- pollen/tag
- pollen/setup
- pollen/pagetree
- pollen/core))
-
-@(define dust-eval (make-base-eval))
-@(dust-eval '(require "dust.rkt" txexpr))
-
-@title{Dust}
-
-@defmodule["dust.rkt" #:packages ()]
-
-This is where I put constants and helper functions that are needed pretty much everywhere in the
-project. In a simpler project these would go in @seclink["pollen-rkt"]{@filepath{pollen.rkt}} but
-here I have other modules sitting “behind” that one in the @tt{require} chain.
-
-@section{Constants}
-
-@defthing[default-authorname string? #:value "Joel Dueck"]
-
-Used as the default author name for @code{note}s, and (possibly in the future) for articles
-generally.
-
-@defthing[web-root path-string? #:value "/"]
-
-Specifies the path between the domain name and the root folder of the website generated by this
-project.
-
-@deftogether[(@defthing[articles-folder path-string? #:value "articles"]
- @defthing[series-folder path-string? #:value "series"])]
-
-The names of the folders that contain the Pollen source documents for Articles and Series
-respectively, relative to the project’s document root.
-
-@defthing[images-folder path-string? #:value "images"]
-
-The name of the subfolders within @racket[articles-folder] and @racket[series-folder] used for
-holding image files.
-
-@deftogether[(@defproc[(articles-pagetree) pagetree?]
- @defproc[(series-pagetree) pagetree?])]
-
-These are project-wide pagetrees: @racket[articles-pagetree] contains a pagenode for every Pollen
-document contained in @racket[articles-folder], and @racket[series-pagetree] contains a pagenode for
-every Pollen document in @racket[series-folder]. The pagenodes themselves point to the rendered
-@tt{.html} targets of the source documents.
-
-@deftogether[(@defproc[(here-output-path) path?]
- @defproc[(here-source-path) path?])]{
-
-Returns the path to the current output or source file, relative to @racket[current-project-root]. If
-no metas are available, returns @racket[(string->path ".")].
-
-For the output path, this is similar to the @tt{here} variable that Pollen provides, except it is
-available outside templates. As to the source path, Pollen provides it via the @racket['here-path]
-key in the current metas, but it is a full absolute path, rather then relative to
-@racket[current-project-root].
-
-}
-
-@defproc[(checked-in?) boolean?]{
-
-Returns @racket[#t] if the current article is checked into the Fossil repo, @racket[#f] otherwise.
-
-}
-
-@defproc[(here-id [suffix (or/c (listof string?) string? #f) #f]) string?]
-
-Returns the 8-character prefix of the SHA1 hash of the current document’s output path. If no metas
-are available, the hash of @racket[(string->path ".")] is used. If @racket[_suffix] evaluates to
-a string or a list of strings, they are appended verbatim to the end of the hash.
-
-This ID is used when creating URL fragment links within an article, such as for footnotes and index
-entries. As long as the web version of the article is not moved to a new URL, the ID will remain the
-same, which ensures deep links using the ID don’t break. The ID also ensures each article’s internal
-links will be unique, so that links do not collide when multiple articles are being shown on
-a single HTML page.
-
-@section{Metas and @code{txexpr}s}
-
-@defproc[(maybe-attr [key symbol?] [attrs txexpr-attrs?] [missing-expr any/c ""]) any/c]
-
-Find the value of @racket[_key] in the supplied list of attributes, returning the value of
-@racket[_missing-expr] if it’s not there.
-
-I had to write this because @racket[attr-ref] wants a whole tagged X-expression (not just the
-attributes); also, by default it raises an exception when @racket[_key] is missing, rather than
-returning an empty string.
-
-@defproc[(maybe-meta [key symbolish?] [missing-expr any/c ""]) any/c]
-
-Look up a value in @code{(current-metas)} that may or may not be present, returning the value of
-@racket[_missing-expr] if it’s not there.
-
-@defproc[(tx-strs [tx txexpr?]) string?]
-
-Finds all the strings from the @emph{elements} of @racket[_tx] (ignoring attributes) and
-concatenates them together.
-
-@examples[#:eval dust-eval
-(tx-strs '(p [[class "intro"]]
- (em "I’m not opening the safe") ", Wilson remembers thinking."))]
-
-@defproc[(make-tag-predicate [sym symbol?] ...) (-> any/c boolean?)]
-
-Returns a function (or @italic{predicate}) that returns @racket[#t] if its argument is
-a @racket[_txexpr] whose tag matches any @racket[_sym]. This predicate is useful for passing as the
-@racket[_pred] expression in functions @racket[splitf-txexpr] and @racket[findf-txexpr].
-
-@examples[#:eval dust-eval
-(define is-aside? (make-tag-predicate 'aside 'sidebar))
-
-(is-aside? '(q "I am not mad, Sir Topas. I say to you this house is dark."))
-(is-aside? '(aside "How smart a lash that speech doth give my Conscience?"))
-(is-aside? '(sidebar "Many copies that we use today are conflated texts."))]
-
-@defproc[(first-words [txprs (listof txexpr?)] [n exact-nonnegative-integer?]) string?]
-
-Given a list of tagged X-expressions, returns a string containing the first @racket[_n] words found
-in the string elements of @racket[_txprs], or all of the words if there are less than @racket[_n]
-words available. Used by @racket[default-title].
-
-This function aims to be smart about punctuation, and equally fast no matter how large the list of
-elements that you send it.
-
-@examples[#:eval dust-eval
-(define txs-decimals
- '((p "Four score and 7.8 years ago — our fathers etc etc")))
-(define txs-punc-and-split-elems
- '((p "“Stop!” she called.") (p "(She was never one to be silent.)")))
-(define txs-dashes
- '((p [[class "newthought"]] (span [[class "smallcaps"]] "One - and") " only one.")
- (p "That was all she would allow.")))
-(define txs-parens-commas
- '((p "She counted (" (em "one, two") "— silently, eyes unblinking")))
-(define txs-short
- '((span "Not much here!")))
-
-(first-words txs-decimals 5)
-(first-words txs-punc-and-split-elems 5)
-(first-words txs-dashes 5)
-(first-words txs-parens-commas 5)
-(first-words txs-short 5)
-]
-
-@defproc[(normalize [str string?]) string?]{
-
-Removes all non-space/non-alphanumeric characters from @racket[_str], converts it to lowercase, and
-replaces all spaces with hyphens.
-
-@examples[#:eval dust-eval
-(normalize "Why, Hello World!")
-(normalize "My first-ever 99-argument function, haha")
-]
-
-}
-
-@section{Article parsers and helpers}
-
-@defparam[listing-context ctxt (or/c 'blog 'feed 'print "") #:value ""]
-
-A parameter specifying the current context where any listings of articles would appear. Its purpose
-is to allow articles to exclude themselves from certain special collections (e.g., the blog, the RSS
-feed, print editions). Any article whose @code{conceal} meta matches the current context will not be
-included in any listings returned by the listing functions in
-@seclink["cache-rkt"]{@filepath{cache.rkt}}.
-
-@defproc[(default-title [body-txprs (listof txexpr?)]) string?]
-
-Given a list of tagged X-expressions (the elements of an article’s doc, e.g.), returns a string
-containing a suitable title for the document. (Uses @racket[first-words].)
-
-Titles are not required for articles, but there are contexts where you need something that serves as
-a title if one is not present, and that’s what this function supplies.
-
-@examples[#:eval dust-eval
-(define doc
- '(root (p "If I had been astonished at first catching a glimpse of so outlandish an "
- "individual as Queequeg circulating among the polite society of a civilized "
- "town, that astonishment soon departed upon taking my first daylight "
- "stroll through the streets of New Bedford…")))
-(default-title (get-elements doc))]
-
-@defproc[(current-series-pagenode) pagenode?]
-
-If @code{(current-metas)} has the key @racket['series], converts its value to the pagenode pointing to
-that series, otherwise returns @racket['||].
-
-@examples[#:eval dust-eval
-(require pollen/core)
-(parameterize ([current-metas (hash 'series "marquee-fiction")])
- (current-series-pagenode))]
-
-@defproc[(current-series-noun) string?]
-
-If @code{(current-metas)} has the key @racket['series] and if there is a corresponding
-@racket[series] in the @racket[series-list], return its @racket[series-noun-singular] value;
-otherwise return @racket[""].
-
-@defproc[(current-series-title) string?]
-
-If @code{(current-metas)} has the key @racket['series] and if there is a corresponding
-@racket[series] in the @racket[series-list], return its @racket[series-title] value;
-otherwise return @racket[""].
-
-@defproc[(invalidate-series) (or/c void? boolean?)]
-
-If the current article specifies a @racket['series] meta, and if a corresponding @filepath{.poly.pm}
-file exists in @racket[series-folder], attempts to “touch” the last-modified timestamp on that file,
-returning @racket[#t] on success or @racket[#f] on failure. If either precondition is not true,
-returns @|void-const|.
-
-When an article is being rendered, that means the article has changed, and if the article has
-changed, its series page (if any) should be updated as well. Touching the @filepath{.poly.pm} file
-for a series page triggers a re-render of that page when running @tt{make web} to rebuild the web
-content (see @repo-file{makefile}).
-
-Only used in one place, @repo-file{tags-html.rkt}.
-
-@defproc[(disposition-values [str string?]) any]
-
-Given a string @racket[_str], returns two values: the portion of the string coming before the first
-space, and the rest of the string.
-
-@examples[#:eval dust-eval
-(disposition-values "* thoroughly recanted")]
-
-@defproc[(build-note-id [tx txexpr?]) non-empty-string?]
-
-Given a @code{note} tagged X-expression, returns an identifier string to uniquely identify that note
-within an article. This identifier is used as an anchor link in the note’s HTML, and as part of the
-note’s primary key in the SQLite cache database.
-
-@examples[#:eval dust-eval
-(build-note-id '(note [[date "2018-02-19"]] "This is an example note"))
-(build-note-id '(note [[date "2018-03-19"] [author "Dean"]] "Different author!"))
-]
-
-@defproc[(notes->last-disposition-values [txprs (listof txexpr?)]) any]
-
-Given a list of tagged X-expressions (ideally a list of @code{note}s), returns two values: the value
-of the @racket['disposition] attribute for the last note that contains one, and the ID of that note.
-
-@examples[#:eval dust-eval
-(define notelist
- (list
- '(note [[date "2018-02-19"] [disposition "* problematic"]] "First note")
- '(note [[date "2018-03-19"]] "Second note")
- '(note [[date "2018-04-19"] [disposition "† recanted"]] "Third note")))
-
-(notes->last-disposition-values notelist)]
-
-@section{Date formatters}
-
-@defproc[(ymd->english [ymd-string string?]) string?]
-
-Converts a date-string of the form @code{"YYYY-MM-DD"} to a string of the form @code{"Monthname D,
-YYYY"}.
-
-If the day number is missing from @racket[_ymd-string], the first day of the month is assumed. If
-the month number is also missing, January is asssumed. If the string cannot otherwise be parsed as
-a date, an exception is raised.
-
-If any spaces are present in @racket[_ymd-string], everything after the first space is ignored.
-
-@defproc[(ymd->dateformat [ymd_string string?] [dateformat string?]) string?]
-
-Converts a date-string of the form @code{"YYYY-MM-DD"} to another string with the same date
-formatted according to @racket[_dateformat]. The
-@ext-link["http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table"]{pattern syntax
-of the date format} comes from the Unicode CLDR.
DELETED code-docs/main.scrbl
Index: code-docs/main.scrbl
==================================================================
--- code-docs/main.scrbl
+++ code-docs/main.scrbl
@@ -1,58 +0,0 @@
-#lang scribble/manual
-
-@; SPDX-License-Identifier: BlueOak-1.0.0
-@; This file is licensed under the Blue Oak Model License 1.0.0.
-
-@(require "scribble-helpers.rkt"
- racket/runtime-path
- (for-label racket/base
- "../crystalize.rkt"))
-
-@title{Local Yarn: Source Code Notes}
-
-@author{Joel Dueck}
-
-These are my notes about the internals of the Local Yarn source code. In other words, a personal
-reference, rather than a tutorial.
-
-You’ll get the most out of these notes if you have read @other-doc['(lib
-"pollen/scribblings/pollen.scrbl")], and worked through the tutorials there by hand.
-
-@margin-note{Note that these pages are heavily interlinked with the central Racket documentation at
-@tt{docs.racket-lang.org}, which are written and maintained by others.
-
-Some links from those pages will not work unless you @ext-link["#"]{open this page in its own tab}.
-}
-
-Here’s a rough diagram showing how the @tt{.rkt} modules in this project relate to each other, and
-to the Pollen source documents. This is the least complex system I could devise that would @tt{A)}
-implement everything I want in my @secref["design-goals"], @tt{B)} cleanly separate dependencies for
-print and web output, and @tt{C)} organize an ever-growing collection of hundreds of individual
-notes and articles without noticable loss of speed.
-
-@(define-runtime-path source-diagram "source-diagram.png")
-@centered{@responsive-retina-image[source-diagram]}
-
-The modules are arranged vertically: those on the upper rows provide bindings which are used by
-those on the lower rows. The bottom row are the @tt{.poly.pm} files that make up @tech{articles} and
-@tech{series}.
-
-Individual articles, while they are being rendered to HTML pages, save copies of their metadata and
-HTML to the SQLite cache. This is done by calling @racket[parse-and-cache-article!] from within
-their template.
-
-Any pages that gather content from multiple articles, such as Series pages and the RSS feed, pull
-this content directly from the SQLite cache. This is much faster than trawling through Pollen’s
-cached metas of every article looking for matching articles.
-
-@local-table-of-contents[]
-
-@include-section["tour.scrbl"]
-@include-section["design.scrbl"]
-@include-section["pollen.scrbl"] @; pollen.rkt
-@include-section["series.scrbl"]
-@include-section["dust.scrbl"] @; dust.rkt
-@include-section["snippets-html.scrbl"] @; you get the idea
-@include-section["cache.scrbl"]
-@include-section["crystalize.scrbl"]
-@include-section["other-files.scrbl"]
DELETED code-docs/other-files.scrbl
Index: code-docs/other-files.scrbl
==================================================================
--- code-docs/other-files.scrbl
+++ code-docs/other-files.scrbl
@@ -1,42 +0,0 @@
-#lang scribble/manual
-
-@; SPDX-License-Identifier: BlueOak-1.0.0
-@; This file is licensed under the Blue Oak Model License 1.0.0.
-
-@(require "scribble-helpers.rkt")
-
-@(require (for-label racket/base "../cache.rkt"))
-
-@title[#:tag "other-files"]{Other files}
-
-@section{Home page (@filepath{index.html.pp})}
-
-Simple Pollen preprocessor file that generates the home page.
-
-@section{Keyword Index (@filepath{keyword-index.rkt})}
-
-Through its provided @tt{main} function, builds the keyword index page by pulling all the index
-entries directly from the SQLite cache and sorting them by first letter.
-
-@section{Blog (@filepath{blog.rkt})}
-
-Through its provided @tt{main} function, creates a paginated listing of all @tech{articles} and
-@tech{notes}.
-
-@section{RSS Feed (@filepath{rss-feed.rkt})}
-
-Through its provided @tt{main} function, creates the RSS feed in the file @filepath{feed.xml}. Both
-articles and notes are included. Any article or note with either @racket["all"] or @racket["feed"]
-in its @racket['conceal] meta is excluded.
-
-@section{Cache initialization (@filepath{util/init.rkt})}
-
-Creates and initializes the cache database with @racket[init-cache-db!] and
-@racket[preheat-series!].
-
-@section{New article template (@filepath{util/newpost.rkt})}
-
-Prompts for a title, creates an article with a normalized version of the filename and today’s date,
-and opens the article in an editor.
-
-
DELETED code-docs/pollen.scrbl
Index: code-docs/pollen.scrbl
==================================================================
--- code-docs/pollen.scrbl
+++ code-docs/pollen.scrbl
@@ -1,382 +0,0 @@
-#lang scribble/manual
-
-@; SPDX-License-Identifier: BlueOak-1.0.0
-@; This file is licensed under the Blue Oak Model License 1.0.0.
-
-@(require "scribble-helpers.rkt")
-@(require (for-label "../pollen.rkt"
- "../dust.rkt"
- "../cache.rkt"
- "../crystalize.rkt"
- racket/base
- racket/contract
- racket/string
- txexpr
- pollen/tag
- pollen/setup
- pollen/core
- sugar/coerce))
-
-@title[#:tag "pollen-rkt"]{Pollen}
-
-@defmodule["pollen.rkt" #:packages ()]
-
-The file @filepath{pollen.rkt} is implicitly @code{require}d in every template and every @code{#lang
-pollen} file in the project. It defines the markup for all Pollen documents, and also re-provides
-everything provided by @seclink["cache-rkt"]{@filepath{cache.rkt}} and
-@seclink["crystalize-rkt"]{@filepath{crystalize.rkt}}.
-
-The @code{setup} module towards the top of the file is used as described in
-@racketmodname[pollen/setup].
-
-@section{Markup reference}
-
-These are the tags that can be used in any of @italic{The Local Yarn}’s Pollen documents (articles,
-etc).
-
-@defproc[(title [element xexpr?] ...) txexpr?]{
-
-Supplies a title for the document. You can use any otherwise-valid markup within the title tag.
-
-Titles are optional; if you don’t specify a title, the article will appear without one. This is
-a feature!
-}
-
-@deftogether[(@defproc[(excerpt [elements xexpr?] ...) txexpr?]
- @defproc[(excerpt* [elements xexpr?] ...) txexpr?])]{
-
-Specify an excerpt to be used when the article or note included in an excerpt-style listing (such as
-the blog). The contents of @racket[excerpt] will be extracted out of the article and note and only
-appear in listings; if @racket[excerpt*] is used, its contents will be left in place in the
-article/note and @emph{reused} as the excerpt in listings.
-
-}
-
-@defproc[(p [element xexpr?] ...) txexpr?]{
-
-Wrap text in a paragraph. You almost never need to use this tag explicitly;
-just separate paragraphs by an empty line.
-
-Single newlines within a paragraph will be replaced by spaces, allowing you to use
-@ext-link["https://scott.mn/2014/02/21/semantic_linewrapping/"]{semantic line wrapping}.
-}
-
-@defproc[(newthought [element xexpr?] ...) txexpr?]{
-
-An inline style intended for the first few words of the first paragraph in a new section. Applies
-a “small caps” style to the text. Any paragraph containing a @code{newthought} tag is given extra
-vertical leading.
-
-Rule of thumb: within an article, use either @code{section}/@code{subsection} or @code{newthought}
-to separate sections of text, but not both. Even better, keep it consistent across articles within
-a series.
-
-If you just need small caps without affecting the paragraph, use @racket[caps].
-}
-
-@deftogether[(@defproc[(section [element xexpr?] ...) txexpr?]
- @defproc[(subsection [element xexpr?] ...) txexpr?])]{
-
-Create second- and third-level headings, respectively. This is counting the article's title as the
-first-level header (even if the current article has no title).
-
-}
-
-@defproc[(block [element xexpr?] ...) txexpr?]{
-
-A container for content that should appear grouped together on larger displays. Intended for use in
-Series pages, where the template is very minimal to allow for more customization. You would want
-output from @racket[(fenced-listing (articles 'short))] to appear inside a @racket[block], but when
-using @racket['excerpt] or @racket['full] in place of @racket['short] in that code, you would want
-the output to appear outside it (since the “full” and “excerpt” versions of each article effectively
-supply their own blocks). Only relevant to HTML output.
-
-}
-
-@deftogether[(@defproc[(link [link-id stringish?] [link-text xexpr?]) txexpr?]
- @defproc[(url [link-id stringish?] [url string?]) void?])]{
-
-All hyperlinks are specified reference-style. So, to link some text, use the @code{link} tag with
-an identifier, which can be a string, symbol or number. Elsewhere in the text, use @code{url} with
-the same identifier to specify the URL:
-
-@codeblock|{
- #lang pollen
- If you need help, ◊link[1]{Google it}.
-
- ◊url[1]{https://google.com}
-}|
-
-The @code{url} tag for a given identifier may be placed anywhere in the document, even before it is
-referenced. If you create a @code{link} for an identifier that has no corresponding @code{url},
-a @code{"Missing reference: [link-id]"} message will be substituted for the URL. Conversely,
-creating a @code{url} that is never referenced will produce no output and no warnings or errors.
-
-}
-
-@defproc*[([(xref [title string?]) txexpr?]
- [(xref [article-base string?] [element xexpr?] ...) txexpr?])]{
-
-Hyperlink to another article within @italic{The Local Yarn} using an @racket[_article-base], which
-is the base filename only of an @tech{article} within @racket[articles-folder] (without the
-@filepath{.poly.pm} extension).
-
-If a single argument is supplied (@racket[_title]) it is typeset italicized as the link text, and
-its @racket[normalize]d form is used as the article base to generate the link. If more than one
-argument is supplied, the first is used as the article base, and the rest are used as the contents
-of the link.
-
-@codeblock|{
- #lang pollen
-
- A link to ◊xref{My Ultimate Article} will link to “my-ultimate-article.poly.pm”.
- A link using ◊xref["my-ultimate-article"]{this form} goes to the same place.
-}|
-
-}
-
-@deftogether[(@defproc[(figure [image-file string?] [caption xexpr?] ...) txexpr?]
- @defproc[(figure-@2x [image-file string?] [caption xexpr?] ...) txexpr?])]{
-
-Insert a block-level image. The @racket[_image-file] should be supplied as a filename only, with no
-folder names. It is assumed that the image is located inside an @racket[images-folder] within the
-same folder as the source document.
-
-For web output, using @racket[figure-@2x] will produce an image hard-coded to display at half its
-actual size, or the width of the text block, whichever is smaller.
-
-}
-
-@defproc[(image-link [image-file string?] [link-text xexpr?] ...) txexpr?]{
-
-Adds a hyperlink to @racket[_image-file], supplied as a filename only with no folder names. It is
-assumed that the image is located inside an @racket[images-folder] within the same folder as the
-source document.
-
-}
-
-@deftogether[(@defproc[(fn [fn-id stringish?]) txexpr?]
- @defproc[(fndef [fn-id stringish?] [elements xexpr?] ...) txexpr?])]{
-
-As with hyperlinks, footnotes are specified reference-style. In the output, footnotes will be
-numbered according to the order in which their identifiers are referenced in the source document.
-
-Example:
-
-@codeblock|{
- #lang pollen
- Shoeless Joe Jackson was one of the best players of all time◊fn[1].
-
- ◊fndef[1]{But he might have lost the 1919 World Series on purpose.}
-}|
-
-You can refer to a given footnote definition more than once.
-
-The @code{fndef} for a given id may be placed anywhere in the source document, even before it is
-referenced. If you create a @code{fn} reference without a corresponding @code{fndef},
-a @code{"Missing footnote definition!"} message will be substituted for the footnote text.
-Conversely, creating a @code{fndef} that is never referenced will produce no output, warning or
-error.
-
-}
-
-@deftogether[(@defproc[(dialogue [elements xexpr?] ...) txexpr?]
- @defproc[(say [interlocutor string?] [elements xexpr?] ...) txexpr?]
- @defproc[(saylines [interlocutor string?] [elements xexpr?] ...) txexpr?])]{
-
-Use these tags together for transcripts of dialogue, chats, screenplays, interviews and so
-forth. The @racket[saylines] tag is the same as @racket[say] except that within @racket[saylines],
-linebreaks within paragraphs are preserved.
-
-Example usage:
-
-@codeblock|{
- #lang pollen
-
- ◊dialogue{
- ◊say["Tavi"]{You also write fiction, or you used to. Do you still?}
- ◊say["Lorde"]{The thing is, when I write now, it comes out as songs.}
- }
-}|
-
-}
-
-@defproc[(index [#:key key string? ""] [elements xexpr?] ...) txexpr?]{
-
-Creates a bidirectional link between this spot in the document and an entry in the keyword index
-under @racket[_key]. If @racket[_key] is not supplied, the string contents of @racket[_elements] are
-used as the key. Use @tt{!} to split @racket[_key] into a main entry and a subentry.
-
-The example below will create two index entries, one under the heading “compassion” and one under
-the main heading "cats" and a subheading “stray”:
-
-@codeblock|{
- #lang pollen
-
- “I have a theory which I suspect is rather immoral,” Smiley
- went on, more lightly. “Each of us has only a quantum of
- ◊index{compassion}. That if we lavish our concern on every
- stray ◊index[#:key "cats!stray"]{cat} we never get to the
- centre of things. What do you think of it?”
-}|
-
-}
-
-@defproc[(note [#:date date-str non-empty-string?]
- [#:author author string? ""]
- [#:author-url author-url string? ""]
- [#:disposition disp-str string? ""]) txexpr?]{
-
-Add a @tech{note} to the “Further Notes” section of the article.
-
-The @code{#:date} attribute is required and must be of the form @tt{YYYY-MM-DD}.
-
-The @code{#:author} and @code{#:author-url} attributes can be used to credit notes from other
-people. If the @code{#:author} attribute is not supplied then the value of @code{default-authorname}
-is used.
-
-The @code{#:disposition} attribute is used for notes that update or alter the whole disposition of
-the article. It must be a string of the form @racket[_mark _past-tense-verb], where @racket[_mark]
-is a symbol suitable for use as a marker, such as * or †, and @racket[_past-tense-verb] is the word
-you want used to describe the article’s current state. An article stating a metaphysical position
-might later be marked “recanted”; a prophecy or prediction might be marked “fulfilled”.
-
-@codeblock|{
-#lang pollen
-
-◊note[#:date "2019-02-19" #:disposition "✓ verified"]{I wasn’t sure, but now I am.}
-}|
-
-
-If more than one note contains a @code{disposition} attribute, the one from the most recent note is
-the one used.
-
-Some caveats (for now):
-
-@itemlist[
- @item{Avoid defining new footnotes using @code{fndef} inside a @code{note}; these footnotes will
- be placed into the main footnote section of the article, which is probably not what you want.}
-]
-
-}
-
-@defproc[(verse [#:title title string? ""] [#:italic? italic boolean? #f] [element xexpr?] ...)
- txexpr?]{
-
-Typeset contents as poetry, with line breaks preserved and the block centered on the longest line.
-To set the whole block in italic, use @code{#:italic? #t} — otherwise, use @code{i} within the
-block.
-
-If the first element in an article is a @racket[verse] tag with the @racket[#:title] attribute
-specified, that title is used as the article’s title if the normal @racket[title] tag is absent.
-
-To cite a source, use @racket[attrib] immediately afterward.
-
-}
-
-@defproc[(magick [element xexpr?] ...) txexpr?]{
-
-Typeset contents using historical ligatures and the “long s” conventions of 17th-century English
-books.
-
-}
-
-@defproc[(blockquote [element xexpr?] ...) txexpr?]{
-
-Surrounds a block quotation. To cite a source, use @racket[attrib] immediately afterward.
-
-}
-
-@defproc[(attrib [element xexpr?] ...) txexpr?]{
-
-An attribution line, for citing a source for a block quotation, epigraph or poem.
-
-}
-
-@defproc[(blockcode [element xexpr?] ...) txexpr?]{
-
-Typeset contents as a block of code using a monospace font. Line breaks are preserved.
-
-}
-
-@deftogether[(@defproc[(i [element xexpr?] ...) txexpr?]
- @defproc[(em [element xexpr?] ...) txexpr?]
- @defproc[(b [element xexpr?] ...) txexpr?]
- @defproc[(mono [element xexpr?] ...) txexpr?]
- @defproc[(strong [element xexpr?] ...) txexpr?]
- @defproc[(strike [element xexpr?] ...) txexpr?]
- @defproc[(ol [element xexpr?] ...) txexpr?]
- @defproc[(ul [element xexpr?] ...) txexpr?]
- @defproc[(item [element xexpr?] ...) txexpr?]
- @defproc[(sup [element xexpr?] ...) txexpr?]
- @defproc[(caps [element xexpr?] ...) txexpr?]
- @defproc[(code [element xexpr?] ...) txexpr?])]{
-
-Work pretty much how you’d expect.
-
-}
-
-@section{Convenience macros}
-
-@defform[(for/s thing-id listofthings result-exprs ...)
- #:contracts ([listofthings (listof any/c)])]{
-
-A shorthand form for Pollen’s @code{for/splice} that uses far fewer brackets when you’re only
-iterating through a single list.
-
-@codeblock|{
-#lang pollen
-
-◊for/s[x '(7 8 9)]{Now once for number ◊x}
-
-◊;Above line is shorthand for this one:
-◊for/splice[[(x (in-list '(7 8 9)))]]{Now once for number ◊x}
-}|
-
-}
-
-@section{Defining new tags}
-
-I use a couple of macros to define tag functions that automatically branch into other functions
-depending on the current output target format. This allows me to put the format-specific tag
-functions in separate files that have separate places in the dependency chain. So if only the HTML
-tag functions have changed and not those for PDF, the @filepath{makefile} can ensure only the HTML
-files are rebuilt.
-
-@defproc[#:kind "syntax"
- (poly-branch-tag (tag-id symbol?))
- (-> txexpr?)]{
-
-Defines a new function @racket[_tag-id] which will automatically pass all of its arguments to a
-function whose name is the value returned by @racket[current-poly-target], followed by a hyphen,
-followed by @racket[_tag]. So whenever the current output format is @racket['html], the function
-defined by @racket[(poly-branch-tag _p)] will branch to a function named @racket[html-p]; when the
-current format is @racket['pdf], it will branch to @racket[pdf-p], and so forth.
-
-You @emph{must} define these branch functions separately, and you must define one for @emph{every}
-output format included in the definition of @racket[poly-targets] in this file’s @racket[setup]
-submodule. If you do not, you will get “unbound identifier” errors at expansion time.
-
-The convention in this project is to define and provide these branch functions in separate files:
-see, e.g., @filepath{tags-html.rkt}.
-
-Functions defined with this macro @emph{do not} accept keyword arguments. If you need keyword
-arguments, see @racket[poly-branch-kwargs-tag].
-
-@margin-note{The thought behind having two macros so similar is that, by cutting out handling for keyword
-arguments, @racket[poly-branch-tag] could produce simpler and faster code. I have not verified if
-this intuition is meaningful or correct.}
-
-}
-
-@defproc[#:kind "syntax"
- (poly-branch-kwargs-tag (tag-id symbol?))
- (-> txexpr?)]{
-
-Works just like @racket[poly-branch-tag], but uses Pollen’s @racket[define-tag-function] so that
-keyword arguments will automatically be parsed as X-expression attributes.
-
-Additionally, the branch functions called from the new function must accept exactly two arguments:
-a list of attributes and a list of elements.
-
-}
DELETED code-docs/scribble-helpers.rkt
Index: code-docs/scribble-helpers.rkt
==================================================================
--- code-docs/scribble-helpers.rkt
+++ code-docs/scribble-helpers.rkt
@@ -1,79 +0,0 @@
-#lang racket/base
-
-; SPDX-License-Identifier: BlueOak-1.0.0
-; This file is licensed under the Blue Oak Model License 1.0.0.
-
-;; Convenience/helper functions for this project’s Scribble documentation
-
-(require scribble/core
- scribble/manual/lang
- scribble/html-properties
- scribble/private/manual-sprop
- scribble/decode
- racket/runtime-path
- (only-in net/uri-codec uri-encode))
-(provide (all-defined-out))
-
-(define-runtime-path custom-css "custom.css")
-
-(define repo-url/ "https://thelocalyarn.com/code/")
-
-;; Link to a ticket on the Fossil repository by specifying the ticket ID.
-;; The "_parent" target breaks out of the iframe used by the Fossil repo web UI.
-(define (ticket id-str)
- (hyperlink (string-append repo-url/ "tktview?name=" id-str)
- "ticket "
- (tt id-str)
- #:style (style #f (list (attributes '((target . "_parent")))))))
-
-;; Link to a wiki page on the Fossil repository by specifying the title
-(define (wiki title)
- (hyperlink (string-append repo-url/ "wiki?name=" (uri-encode title))
- title
- #:style (style #f (list (attributes '((target . "_parent")))))))
-
-;; Link somewhere outside these docs or Racket docs. The `_blank` target opens in a new tab.
-(define (ext-link url-str . elems)
- (keyword-apply hyperlink '(#:style) (list (style #f (list (attributes '((target . "_blank"))))))
- url-str
- elems))
-
-;; Link to show contents of the latest checked-in version of a file
-;; (or a file listing if a directory was specified)
-(define (repo-file filename)
- (hyperlink (string-append repo-url/ "file/" filename)
- (tt filename)
- #:style (style #f (list (attributes '((target . "_parent")))))))
-
-(define (responsive-retina-image img-path)
- (image img-path
- #:scale 0.5
- #:style (style #f (list (attributes '((style . "max-width:100%;height:auto;")))))))
-
-;;
-;; From https://github.com/mbutterick/pollen/blob/master/pollen/scribblings/mb-tools.rkt
-;;
-
-(define (terminal . args)
- (compound-paragraph (style "terminal" (list (css-style-addition custom-css) (alt-tag "div")))
- (list (apply verbatim args))))
-
-(define (cmd . args)
- (elem #:style (style #f (list (color-property "black"))) (tt args)))
-
-(define (fileblock filename . inside)
- (compound-paragraph
- (style "fileblock" (list* (alt-tag "div") 'multicommand
- (box-mode "RfileboxBoxT" "RfileboxBoxC" "RfileboxBoxB")
- scheme-properties))
- (list
- (paragraph (style "fileblock_filetitle" (list* (alt-tag "div") (box-mode* "RfiletitleBox") scheme-properties))
- (list (make-element
- (style "fileblock_filename" (list (css-style-addition custom-css)))
- (if (string? filename)
- (filepath filename)
- filename))))
- (compound-paragraph
- (style "fileblock_filecontent" (list* (alt-tag "div") (box-mode* "RfilecontentBox") scheme-properties))
- (decode-flow inside)))))
-
DELETED code-docs/scribble-iframe.html
Index: code-docs/scribble-iframe.html
==================================================================
--- code-docs/scribble-iframe.html
+++ code-docs/scribble-iframe.html
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
DELETED code-docs/series.scrbl
Index: code-docs/series.scrbl
==================================================================
--- code-docs/series.scrbl
+++ code-docs/series.scrbl
@@ -1,74 +0,0 @@
-#lang scribble/manual
-
-@; SPDX-License-Identifier: BlueOak-1.0.0
-@; This file is licensed under the Blue Oak Model License 1.0.0.
-
-@(require "scribble-helpers.rkt"
- scribble/example)
-
-@(require (for-label "../pollen.rkt"
- "../series-list.rkt"
- "../dust.rkt"
- "../cache.rkt"
- pollen/core
- racket/base
- racket/contract))
-
-@title{Defining Series}
-
-To create a new series:
-
-@itemlist[#:style 'ordered
-
- @item{Create a file @filepath{my-key.poly.pm} inside @racket[series-folder] and include a call
- to @racket[fenced-listing] to list all the articles and notes that will be included in the series:
- @codeblock|{
-#lang pollen
-
-◊(define-meta title "My New Series")
-
-◊block{Here’s what we call a bunch of similar articles:
-
-◊(fenced-listing (articles 'short))
-
-}
- }|
- }
-
- @item{Add an entry for @racket[_my-key] to @racket[series-list] in @filepath{series-list.rkt}}
-
- @item{Use @racket[(define-meta series "my-key")] in articles to add them to the series.}
-
- @item{If @racket[series-ptree-ordered?] is @racket[#t], create a @seclink["Pagetree" #:doc '(lib
- "pollen/scribblings/pollen.scrbl")]{pagetree} file in @racket[series-folder] named
- @filepath{my-key.ptree}.}
-
- ]
-
-@section{Series list}
-
-@defmodule["series-list.rkt" #:packages ()]
-
-This module contains the most commonly used bits of meta-info about @tech{series}. Storing these
-bits in a hash table of structs makes them faster to retrieve than when they are stored inside the
-metas of the Pollen documents for the series themselves.
-
-@defthing[series-list hash?]{
-
-An immutable hash containing all the title and noun info for each @tech{series}. Each key is
-a string and each value is a @racket[series] struct.
-
-}
-
-@defstruct[series ([key string?]
- [title string?]
- [noun-plural string?]
- [noun-singular string?]
- [ptree-ordered? boolean?])]{
-
-Struct for holding metadata for a @tech{series}. The @racket[_ptree-ordered?] value should be
-@racket[#t] if there is a @filepath{@italic{key}.ptree} file in @racket[series-folder] that provides
-information on how articles in the series are ordered.
-
-}
-
DELETED code-docs/snippets-html.scrbl
Index: code-docs/snippets-html.scrbl
==================================================================
--- code-docs/snippets-html.scrbl
+++ code-docs/snippets-html.scrbl
@@ -1,161 +0,0 @@
-#lang scribble/manual
-
-@; SPDX-License-Identifier: BlueOak-1.0.0
-@; This file is licensed under the Blue Oak Model License 1.0.0.
-
-@(require "scribble-helpers.rkt")
-
-@(require (for-label "../pollen.rkt"
- "../dust.rkt"
- "../snippets-html.rkt"
- racket/base
- racket/contract
- racket/string
- pollen/template
- pollen/pagetree
- txexpr
- sugar/coerce))
-
-@title{HTML snippets}
-
-@defmodule["snippets-html.rkt" #:packages ()]
-
-Each “snippet” module provides all (well @emph{most of}) the document- and article-level blocks of
-structural markup necessary for a particular target output format; this one is for HTML. The idea is
-that any block of markup that might be reused across more than one template should be a function.
-
-The functions in the snippets modules follow two conventions in this project:
-
-@itemlist[
- @item{Functions that return strings of HTML have the prefix @tt{html$-}.}
- @item{Such functions do not do any parsing or destructuring of complex objects; every separate
- piece that will be inserted into the template is passed in as a separate argument. This makes it
- harder to change the scope of what a snippet does, but makes things faster since all the parsing
- can happen in one place, before the snippet functions are called.} ]
-
-@section{Using @tt{pollen/mode}}
-
-It’s worth looking at the source for this file to see how @racketmodname[pollen/mode] can be used to
-make it easy to write “mini-template” functions:
-
-@codeblock{
-#lang pollen/mode racket/base
-
-(define (html$-my-article title body-tx)
- ◊string-append{
-
} section of an HTML document.
-
-If @racket[_title] is a string it will be used inside the @tt{} tag.
-
-If you want to include additional stuff inside the @tt{}, you can set @racket[_close-head?] to
-@racket[#f] to prevent it from including the closing @tt{} tag (you’ll have to add it
-yourself).
-}
-
-@defproc[(html$-page-body-open [body-class string? ""]) non-empty-string?]{
-
-Returns the opening @tt{} and @tt{} tags and elements that immediately follow, such as
-site header, logo and navigation.
-
-If @racket[_body-class] is a non-empty string, its contents will be included in the @tt{class}
-attribute of the @tt{} tag.
-}
-
-@defproc[(html$-series-list) non-empty-string?]{
-
-Returns an HTML @tt{} containing a list of all series, grouped by their “plural nouns”. The
-grouped list will flow into columns on wider displays.
-}
-
-@defproc[(html$-article-open [pagenode pagenode?]
- [title-specified-in-doc? boolean?]
- [title txexpr?]
- [pubdate string?])
- non-empty-string?]{
-
-Returns the opening @tt{} tag and elements that immediately follow: permlink, publish date,
-and opening @tt{} tag.
-
-The @racket[_title-specified-in-doc?] form changes the HTML markup structure used.
-}
-
-@defproc[(html$-article-close [footertext string?]) non-empty-string?]{
-
-Returns a string containing a closing @tt{} tag, a @tt{