guile-rsv

R7RS Scheme library for reading and writing RSV (Rows of String Values) data format. Specified in https://github.com/Stenway/RSV-Specification and demonstrated in https://www.youtube.com/watch?v=tb_70o6ohMA
git clone https://kaka.farm/~git/guile-rsv
Log | Files | Refs | README | LICENSE

commit 5650dbc886f5f42190808b25e2c26b9bed2ddbcc
parent 799d2a6f17601b11382be759a2bbea9daf485a35
Author: Yuval Langer <yuval.langer@gmail.com>
Date:   Mon, 22 Jan 2024 18:08:43 +0200

Write the manual.

Diffstat:
Mdoc/guile-rsv.texi | 1003+++++++++----------------------------------------------------------------------
1 file changed, 112 insertions(+), 891 deletions(-)

diff --git a/doc/guile-rsv.texi b/doc/guile-rsv.texi @@ -6,6 +6,7 @@ @setfilename guile-rsv.info @settitle guile-rsv Reference Manual @set VERSION 1.0.0 +@set UPDATED 2024-01-22 @c %**end of header @c XXX @include version.texi @@ -29,7 +30,7 @@ Documentation License''. @titlepage @title guile-rsv Reference Manual @subtitle Using guile-rsv -@author The Haunt Developers +@author Yuval Langer and Zipheir @page @vskip 0pt plus 1filll @@ -44,17 +45,14 @@ Documentation License''. @node Top @top guile-rsv -This document describes guile-rsv version @value{VERSION}, a Rows of -String Values (RSV) R7RS compliant libraray. -generator. -@c * Installation:: Installing Haunt. +This document describes guile-rsv, a Rows of String Values (RSV) R7RS +compliant libraray (version @value{VERSION}, @value{UPDATED}). @menu -* Introduction:: About guile-rsv -* Installation:: Installing Haunt -* Tutorial:: How to get started quickly. +* Introduction:: About guile-rsv. +* Installation:: Installing guile-rsv. * Command-line Interface:: Using guile-rsv from the command-line. -* Programming Interface:: Using the Haunt API in Scheme. +* Programming Interface:: Reading and writing RSV in Scheme. * Contributing:: How to contribute to guile-rsv. * GNU Free Documentation License:: The license of this manual. * Concept Index:: Concepts. @@ -67,20 +65,28 @@ generator. Rows of String Values is a data format used to represent a list of list of unicode strings (or nulls), as shown in this BNF: -@code +@verbatim RSV := RSV-row* -RSV-row := RSV-string-or-null* Row-Terminator-Byte -RSV-string-or-null := ( String | Null-Value-Byte ) Value-Terminator-Byte +RSV-Row := RSV-String-or-Null* Row-Terminator-Byte +RSV-String-or-Null := ( String | Null-Value-Byte ) Value-Terminator-Byte String := a Unicode string encoded as UTF-8 Row-Terminator-Byte := 0xFD Value-Terminator-Byte := 0xFF Null-Value-Byte := 0xFE -@end code +@end verbatim -Because all three bytes used to represent Row-Terminator-Byte, -Value-Terminator-Byte, and Null-Value-Byte are not used to encode -UTF-8, we can freely use them as punctuation between the strings. -This result with us not having to escape any +Contrary to CSV, TSV, and similar formats, which use commas, tabs, and +newlines, in RSV one can use UTF-8 string without modification thanks +to the fact that the byte values used to separate the fields are never +used by UTF-8. That is to say, we will never see 0xFD, 0xFF, or 0xFE +in a UTF-8 encoded Unicode. + +More information on RSV's design can be found on: + +The original specification repository written by Stefan John +(a.k.a. Stenway) @url{https://github.com/Stenway/RSV-Specification}, +and the video presentation +@url{https://www.youtube.com/watch?v=tb_70o6ohMA}. @node Installation @chapter Installation @@ -89,7 +95,6 @@ This result with us not having to escape any * Downloading:: Downloading the source code. * Guix Installation:: Installing from Guix. * Requirements:: guile-rsv Requirements. -* Building:: Building from source code. @end menu @node Downloading @@ -98,7 +103,8 @@ This result with us not having to escape any Official guile-rsv source code is available from @url{https://codeberg.org/kakafarm/guile-rsv, Codeberg}, @url{https://git.sr.ht/~kakafarm/guile-rsv, Sourcehut}, or -@url{https://kaka.farm/stagit/guile-rsv, Kaka Farm's Stagit}. +@url{https://kaka.farm/~stagit/guile-rsv/log.html, Kaka Farm's +Stagit}. @node Guix Installation @section Guix Installation @@ -106,8 +112,16 @@ Official guile-rsv source code is available from Add the Guix Kaka Farm Channel from @url{https://codeberg.org/kakafarm/guix-kakafarm-channel, codeberg}, @url{https://git.sr.ht/~kakafarm/guix-kakafarm-channel/, Sourcehut}, -or @url{https://kaka.farm/stagit/guile-rsv/log.html, Kaka Farm's -Stagit} to your @code{~/.config/guix/channels.scm}. +or @url{https://kaka.farm/~stagit/guix-kakafarm-channel.git/, Kaka +Farm's Repository} +(@url{https://kaka.farm/~stagit/guix-kakafarm-channel/log.html, Kaka +Farm's Stagit}) to your @code{~/.config/guix/channels.scm}. + +Now: + +@example +guix pull && guix install guile-rsv +@end example @node Requirements @section Requirements @@ -118,9 +132,13 @@ guile-rsv depends on the following packages: @item @url{https://gnu.org/software/guile, GNU Guile} @item -@url{https://gnu.org/software/bash, GNU Bash} +@url{https://gnu.org/software/bash, GNU Bash} for the @command{rsv2scm} (@ref{Invoking rsv2scm}) and +@command{scm2rsv} (@ref{Invoking scm2rsv}) commands. @end itemize +You can probably use other R7RS compatible Scheme implementations to +use the @code{(rsv)} and @code{(rsv rows-streams)} libraries. + @node Command-line Interface @chapter Command-line Interface @@ -129,76 +147,59 @@ guile-rsv depends on the following packages: * Invoking scm2rsv:: Convert Lists of lists of strings into RSV. @end menu -The Haunt command-line interface is composed of many subcommands. The -general syntax for all Haunt commands is: +rsv2scm reads binary RSV data from stdin and writes list of lists of +@var{string}-or-@var{#f} values into stdout. It may also produce a +list of @var{string}-or-@var{#f} values per line, each corresponding +to a row of RSV data. -@example -haunt @var{subcommand} @var{options}@dots{} -@end example +scm2rsv does the opposite - it reads a list of lists of +@var{string}-or-@var{#f} from stdin and writes binary RSV data into +stdout. @node Invoking rsv2scm @section Invoking @command{rsv2scm} -The @command{haunt build} command realizes a Haunt site configuration -file by compiling web pages and copying static assets to the output -directory. For details on how to configure a Haunt site, -@pxref{Sites}. - Example: @example -haunt build --config=haunt.scm +cat data.rsv | rsv2scm [-s/--stream] @end example @table @code -@item --config=@var{configuration-file} -@itemx -c @var{configuration-file} -Load the Haunt site declaration from @var{configuration-file}. +@item --stream +@itemx -s +Print one list of @var{string}-or-@var{#f} values per line. + +@item --version +@itemx -V +Print version information. + +@item --help +@itemx -h +Print an hopefully helpful help message. @end table @node Invoking scm2rsv @section Invoking @command{scm2rsv} -The @command{haunt serve} command allows one to quickly view a local -preview of the generated website before publishing the finished -product to a remote web server. When @command{haunt serve} runs, a -local HTTP server is spawned. Visit the server using a web browser to -inspect the results of the build. By default, the web server listens -on port 8080, so the URL to visit would be -@url{http://localhost:8080}. +Example: -While developing, it is common to rebuild the site frequently to view -the results of incremental changes. Rather than manually running -@command{haunt build} (@ref{Invoking haunt build}) each time changes -are made, the @code{--watch} flag can be used to automatically rebuild -the site when a source file changes on disk. +@example +cat data.rsv | rsv2scm | scm2rsv > data-2.rsv +# Now data.rsv and data-2.rsv hold the same exact data. +@end example @table @code -@item --config=@var{configuration-file} -@itemx -c @var{configuration-file} -Load the Haunt site declaration from @var{configuration-file}. - -@item --port=@var{port} -@itemx -p @var{port} - -Listen for HTTP requests on @var{port}. Defaults to 8080. - -@item --host=@var{host} -@itemx -p @var{host} - -Listen for HTTP requests on @var{host}. Accepts an IP address (IPv4 -or IPv6), @code{localhost} or @code{loopback} to serve on the local -loopback device (the default), or @code{any} to bind on all local -available ports (useful if you want to show off your website to -someone else on your LAN, or something.) +@item --version +@itemx -V +Print version information. -@item --watch -@itemx -w - -Automatically rebuild the site when source files change. +@item --help +@itemx -h +Print an hopefully helpful help message. @end table @@ -206,871 +207,91 @@ Automatically rebuild the site when source files change. @chapter Programming Interface @menu -* Sites:: Description of the site and how to build it. -* Posts:: Articles, prose, blog posts, etc. -* Readers:: Post interpreters. -* Builders:: Web page builders. -* Publishers:: How to publish your site. -* Artifacts:: The build outputs that form a website. -* Assets:: Images, stylesheets, etc. -@end menu - -Haunt is a fully-programmable system composed of several Guile Scheme -modules. This section documents the public API. - -@node Sites -@section Sites - -@example -(use-modules (haunt site)) -@end example - -A site object defines all of the properties for a Haunt website: The -site name, domain name, where blog posts are found, what post formats -are understood, which procedures are used to build the site, where the -output files are written to, etc. - -@deffn {Procedure} site [#:title "This Place is Haunted"] @ - [#:domain "example.com"] [#:posts-directory "posts"] @ - [#:file-filter @code{default-file-filter}] @ - [#:build-directory "site"] [#:default-metadata '()] @ - [#:make-slug @code{post-slug}] [#:readers '()] @ - [#:builders '()] [#:publishers '()] -Create a new site object. All arguments are optional: - -@table @var - -@item title -The name of the site. - -@item posts-directory -The directory where posts are found. - -@item file-filter -A predicate procedure that returns @code{#f} when a post file should -be ignored, and @code{#t} otherwise. Emacs temporary files are -ignored by default. - -@item build-directory -The directory that generated pages are stored in. - -@item default-metadata -An alist of arbitrary default metadata for posts whose keys are -symbols. - -@item make-slug -A procedure generating a file name slug from a post. - -@item readers -A list of reader objects for processing posts. - -@item builders -A list of procedures for building pages from posts. - -@item publishers -A list of publisher objects for upload site contents to a remote location - -@end table - -@end deffn - -@deffn {Procedure} site? @var{obj} -Return @code{#t} if @var{obj} is a site object. -@end deffn - -@deffn {Procedure} site-title @var{site} -Return the title of @var{site}. -@end deffn - -@deffn {Procedure} site-domain @var{site} -Return the domain of @var{site}. -@end deffn - -@deffn {Procedure} site-posts-directory @var{site} -Return the posts directory for @var{site}. -@end deffn - -@deffn {Procedure} site-file-filter @var{site} -Return the file filter procedure for @var{site}. -@end deffn - -@deffn {Procedure} site-build-directory @var{site} -Return the build directory of @var{site}. -@end deffn - -@deffn {Procedure} site-make-slug @var{site} -Return the slug constructor for @var{site}. -@end deffn - -@deffn {Procedure} site-readers @var{site} -Return the list of reader procedures for @var{site}. -@end deffn - -@deffn {Procedure} site-builders @var{site} -Return the list of builder procedures for @var{site}. -@end deffn - -@deffn {Procedure} site-publishers @var{site} -Return the list of publisher objects for upload @var{site} contents to a -remote location. -@end deffn - -@node Posts -@section Posts - -@example -(use-modules (haunt post)) -@end example - -Posts represent the articles that are kept in a site's post directory -and written in a markup format that Haunt can understand. -@xref{Readers} for how files on disk can be transformed into posts. - -@deffn {Procedure} make-post @var{file-name} @var{metadata} @var{sxml} -Create a new post object that represents the contents of the file -@var{file-name}. The body of the post, @var{sxml}, is represented as -an SXML tree (@pxref{SXML, SXML,, guile, GNU Guile Reference Manual}) -and the metadata is an association list (@pxref{Association Lists, -Association Lists,, guile, GNU Guile Reference Manual}) of arbitrary -key/value pairs. -@end deffn - -@deffn {Procedure} post? @var{object} -Return @code{#t} if @var{object} is a post. -@end deffn - -@deffn {Procedure} post-file-name @var{post} -Return the file name for @var{post}. -@end deffn - -@deffn {Procedure} post-metadata @var{post} -Return the metadata association list for @var{post}. -@end deffn - -@deffn {Procedure} post-sxml @var{post} -Return the SXML tree for @var{post}. -@end deffn - -@deffn {Procedure} post-ref @var{post} @var{key} -Return the metadata value corresponding to @var{key} within -@var{post}. -@end deffn - -@deffn {Procedure} post-slug post -Return a URL slug suitable for the file name of @var{post}. If a -custom @code{slug} metadata value exists for @var{post} then that is -returned. Otherwise, a slug is automatically generated from the -@code{title} metadata value. -@end deffn - -The original @code{post-slug} procedure above has some less than ideal -behavior. One issue is that version numbers like ``1.2.3'' get -transformed to ``123'' rather than something more sensible like -``1-2-3''. Unfortunately, changing this behavior would mean breaking -the URLs for existing Haunt sites. Instead, users may opt-in to using -@code{post-slug-v2} by passing it as the @code{#:make-slug} argument -to @code{make-site}. @xref{Sites} for more information. - -@deffn {Procedure} post-slug-v2 post -Transform the title of @var{post} into a URL slug. This second -revision does a better job than the original. Like @code{post-slug}, -if a custom @code{slug} metadata value exists for @var{post} then that -is returned. Otherwise, a slug is automatically generated from the -@code{title} metadata value. -@end deffn - -@defvr {Variable} %default-date -The default date of a post when no other date is specified in the -metadata association list. -@end defvr - -@deffn {Procedure} post-date @var{post} -Return the date for @var{post}, or @code{%default-date} if no date is -specified. -@end deffn - -@deffn {Procedure} posts/reverse-chronological @var{posts} -Sort @var{posts}, a list of posts, in reverse chronological order. -@end deffn - -@deffn {Procedure} post-author @var{post} -Return the author of @var{post}, or @code{#f} if no author is -specified. -@end deffn - -@deffn {Procedure} post-tags @var{post} -Return list of tags for @var{post}, or the empty list if no tags are -specified. -@end deffn - -@deffn {Procedure} post-title @var{post} -Return the title of @var{post}, or @code{#f} if no title is -specified. -@end deffn - -@deffn {Procedure} posts/group-by-tag @var{posts} -Create an association list of tags mapped to the posts in the list -@var{posts} that used them. -@end deffn - -@node Readers -@section Readers - -@menu -* Reader:: Reader interface and basic readers -* Texinfo:: Texinfo reader -* Skribe:: Skribe reader -* CommonMark:: CommonMark reader -@end menu - -@node Reader -@subsection Reader -@example -(use-modules (haunt reader)) -@end example - -The purpose of a reader is to translate the markup within a post file -into an SXML tree representing the HTML structure and associate some -metadata with it. - -@deffn {Procedure} make-reader @var{matcher} @var{proc} -Create a new reader. The reader is to be activated when -@var{matcher}, a procedure that accepts a file name as its only -argument, returns @code{#t}. When a post file matches, the procedure -@var{proc}, which also accepts a file name as its only argument, reads -the contents and returns a post object (@pxref{Posts}). -@end deffn - -@deffn {Procedure} reader? @var{object} -Return @code{#t} if @var{object} is a reader. -@end deffn - -@deffn {Procedure} reader-matcher @var{reader} -Return the match procedure for @var{reader}. -@end deffn - -@deffn {Procedure} reader-proc @var{reader} -Return the read procedure for @var{reader}. -@end deffn - -@deffn {Procedure} reader-match? @var{reader} @var{file-name} -Return @code{#t} if @var{file-name} is a file supported by -@var{reader}. -@end deffn - -@deffn {Procedure} reader-find? readers file-name -Return the first reader in @var{readers} that can parse -@var{file-name}, or @code{#f} if there is no such reader. -@end deffn - -@deffn {Procedure} reader-read reader file-name -Parse @var{file-name} using @var{reader} and return two values: an -alist of metadata and an SXML tree. -@end deffn - -@deffn {Procedure} read-post @var{reader} @var{file-name} [@var{default-metadata}] -Read a post object from @var{file-name} using @var{reader}, merging -its metadata with @var{default-metadata}, or the empty list if not -specified. -@end deffn - -@deffn {Procedure} read-posts @var{directory} @var{keep?} @var{readers} [@var{default-metadata}] -Read all of the files in @var{directory} that match @var{keep?} as -post objects. The @var{readers} list must contain a matching reader -for every post. -@end deffn - -@deffn {Procedure} make-file-extension-matcher @var{ext} -Create a procedure that returns @code{#t} when a file name ends with -``.ext''. -@end deffn - -@defvr {Procedure} sxml-reader -A basic reader for posts written as Scheme code that evaluates to an -an association list. The special key @code{content} contains the post -body as an SXML tree. - -Example: - -@example -(use-modules (haunt utils)) - -`((title . "Hello, world!") - (date . ,(string->date* "2015-04-10 23:00")) - (tags "foo" "bar") - (summary . "Just a test") - (content - ((h2 "Hello!") - (p "This is Haunt. A static site generator for GNU Guile.")))) -@end example - -@end defvr - -@defvr {Procedure} html-reader -A basic reader for posts written in plain ol' HTML. Metadata is -encoded as the @code{key: value} pairs, one per line, at the beginning -of the file. A line with the @code{---} sentinel marks the end of the -metadata section and the rest of the file is encoded as HTML. - -Example: - -@example -title: A Foo Walks Into a Bar -date: 2015-04-11 20:00 -tags: bar ---- -<p> - This is an example using raw HTML, because Guile doesn't have a - Markdown parser. -</p> -@end example - -@end defvr - -@node Texinfo -@subsection Texinfo -@example -(use-modules (haunt reader texinfo)) -@end example - -@defvr {Procedure} texinfo-reader -A reader for posts written in texinfo, the official documentation format -of the GNU project. Metadata is encoded as @code{key: value} pairs, one -per line, at the beginning of the file. A line with the @code{---} -sentinel marks the end of the metadata section and the rest of the file -is encoded as HTML. - -Example: - -@example -title: Hello, Texi! -date: 2016-08-20 12:00 -tags: texinfo, foo ---- - -@@emph@{Texinfo@} is the official documentation format of the -@@url@{http://www.gnu.org/, GNU project@}. It was invented by Richard -Stallman and Bob Chassell many years ago, loosely based on Brian -Reid's Scribe and other formatting languages of the time. It is -used by many non-GNU projects as well. -@end example - -@end defvr - -@node Skribe -@subsection Skribe -@example -(use-modules (haunt reader skribe)) -@end example - -@defvr {Procedure} skribe-reader -A reader for posts written in Skribe, a markup language with the full power -of Scheme. Skribe posts are created with the @code{post} expression with -metadata encoded as @code{:key expression} pairs at the beginning of the -@code{post} expression. After the metadata section, the rest of the @code{post} -expression is encoded as HTML. - -Example: - -@example -(post - :title "Hello, Skribe!" - :date (make-date* 2016 08 20 12 00) - :tags '("skribe" "foo" "baz") - - (h2 [This is a Skribe post]) - - (p [Skribe is a ,(em [really]) cool document authoring format - that provides all the power of Scheme whilst giving the user - a means to write literal text without stuffing it into a - string literal. If this sort of thing suits you, be sure to - check out ,(anchor "Skribilo" - "http://www.nongnu.org/skribilo/"), too.])) -@end example - -@end defvr - -@node CommonMark -@subsection CommonMark -@example -(use-modules (haunt reader commonmark)) -@end example - -@defvr {Procedure} commonmark-reader -A reader for posts written in CommonMark, a fully specified variant of -Markdown. Metadata is encoded as @code{key: value} pairs, one per line, -at the beginning of the file. A line with the @code{---} sentinel marks -the end of the metadata section and the rest of the file is encoded as HTML. - -Example: - -@example -title: Hello, CommonMark! -date: 2016-08-20 12:00 -tags: markdown, commonmark ---- - -## This is a CommonMark post - -CommonMark is a **strongly** defined, *highly* compatible -specification of Markdown, learn more about CommomMark -[here](http://commonmark.org/). -@end example - -@end defvr - -@node Builders -@section Builders - -@menu -* Static Assets:: Images, CSS, JavaScript, etc. -* Flat pages:: Simple static pages. -* Blog:: Dear diary... -* Atom:: Atom feeds. -* RSS:: RSS feeds. -* Redirects:: Client-side redirects. +* Ports:: Read and write ports. +* Bytevectors:: Read and write bytevectors. +* Rows Streams:: Read ports as streams of RSV rows. @end menu -Builders are procedures that return one or more artifacts -(@pxref{Artifacts}) when applied. A builder accepts two arguments: A -site (@pxref{Sites}) and a list of posts (@pxref{Posts}). +You can read and write RSV using ports, bytevectors, or a stream +reading from a port. -Haunt comes with a few convenient builders to help users who want to -create a simple blog with an Atom feed. - -@node Static Assets -@subsection Static Assets +@node Ports +@section Ports @example -(use-modules (haunt builder assets)) +(import (rsv)) @end example -@deffn {Procedure} static-directory @var{directory} [@var{dest}] - -Create a builder procedure that recursively copies all of the files in -@var{directory}, a file name relative to a site's source directory, -and copies them into @var{dest}, a prefix relative to a site's target -output directory. By default, @var{dest} is @var{directory}. -@end deffn - -@node Flat pages -@subsection Flat pages - -@example -(use-modules (haunt builder flat-pages)) -@end example - -Flat pages cover the simple case of converting a tree of files written -in some markup language to full web pages. Flat pages work great for -the more informational parts of a website that don't require any fancy -programming to generate, like an ``About me'' page. - -@deffn {Procedure} flat-pages directory [#:template] [#:prefix] - -Return a procedure that parses the files in @var{directory} and -returns a list of HTML pages, one for each file. The files are parsed -using the readers configured for the current site. - -Each flat page starts with a metadata header. Only a single piece of -metadata is used, though: the title. - -Here's what a flat page written in Markdown might look like: - -@example -title: About me ---- - -# About me - -Hello, I am Alice! I'm a fictitious person made up for the purposes -of demonstrating Haunt's flat page functionality. I live here in this -manual with my two cats: Bob and Carol. -@end example - -The content of each flat page is inserted into a complete HTML -document by the @var{template} procedure. This procedure takes three -arguments: - -@itemize -@item the site object -@item the page title string (from the metadata header) -@item an SXML tree of the page body -@end itemize - -@var{template} should return a single value: a new SXML tree -representing a complete HTML page that presumably wraps the page body. - -Conveniently, the signature of @var{template} matches the blog theme -layout procedure so that it can be reused for flat pages. @xref{Blog} -for more information. - -The structure of @var{directory} is preserved in the resulting pages -and may be optionally nested within the directory @var{prefix}. If no -prefix is specified, the files are placed starting at the root of the -site. - -@end deffn - -@node Blog -@subsection Blog - -@example -(use-modules (haunt builder blog)) -@end example - -@deffn {Procedure} theme [#:name "Untitled"] [#:layout] [#:post-template] @ - [#:collection-template] [#:pagination-template] -Create a new theme named @var{name}. - -The procedure @var{layout} accepts three arguments: a site, a page -title string, and an SXML tree. Its purpose is to wrap the contents -of a post with the theme's header/footer and return the complete SXML -tree for a web page. - -The procedure @var{post-template} accepts a single argument: a post. -Its purpose is to return an SXML tree containing the contents of the -post, applying any desired post-processing operations. - -The procedure @var{collection-template} accepts four arguments: a -site, a title string, a list of posts, and a URL prefix string. Its -purpose is to return an SXML tree containing the body of the -collection page. - -The procedure @var{pagination-template} accepts four arguments: a -site, an SXML tree, the file name of the previous page, and the file -name of the next page. Its purpose is to incorporate the given SXML -tree into a larger document that incorporates previous/next page -links. -@end deffn - -@deffn {Procedure} theme? @var{object} -Return @code{#t} if @var{object} is a theme object. -@end deffn - -@deffn {Procedure} blog [#:theme] [#:prefix] [#:post-prefix] @ - [#:collections `(("Recent Posts" "index.html" ,posts/reverse-chronological))] @ - [#:posts-per-page] - -Create a builder procedure that transforms a list of posts into pages -decorated by @var{theme}, a theme object, whose URLs start with -@var{prefix}. Post pages may be nested deeper in the file hierarchy -than collection pages by specifying the @var{post-prefix} argument. - -Additionally, this builder creates pages that aggregate previews of -many posts corresponding to what is specified in the list -@var{collections}. Each collection is a three element list in the -form @code{(title file-name filter)}. +@deffn {Procedure} read-rsv port +Read an RSV from PORT as a list of lists of string-or-null values. @table @var -@item title -The human readable name of the collection. - -@item file-name -The HTML file that will contain the rendered collection. - -@item filter -A procedure that accepts a list of posts as its only argument and -returns a new list of posts. The filter procedure is used to remove -and/or sort the posts into the desired form for the collection. For -example, a filter could sort posts in reverse chronological order or -select all posts that are written by a particular author. +@item port +An input port from which an RSV is read. @end table -By default, a single collection is created that lists posts in reverse -chronological order and writes to @file{index.html}. - -Also by default, collection pages are not paginated. When there are a -lot of posts in one or more collections, it is best to paginate them. -To do so, pass the @var{posts-per-page} argument. - -The default theme is intended only for testing purposes. - @end deffn -@node Atom -@subsection Atom - -@example -(use-modules (haunt builder atom)) -@end example - -@deffn {Procedure} atom-feed [#:file-name "feed.xml"] [#:subtitle "Recent Posts"] @ - [#:filter posts/reverse-chronological] @ - [#:last-updated (current-date)] @ - [#:max-entries 20] [#:blog-prefix ""] -Return a builder procedure that renders a site's posts as an Atom -feed. All arguments are optional: +@deffn {Procedure} write-rsv @var{scm} @var{port} +Write @var{scm} into an output port @var{port}. @table @var -@item file-name: -The page file name. - -@item subtitle -The feed subtitle. +@item scm +A list of lists of string-or-null values. -@item filter -The procedure called to manipulate the posts list before rendering. - -@item last-updated -The feed last updated date. Defaults to the current date. - -@item max-entries -The maximum number of posts to render in the feed. - -@item blog-prefix -The prefix for all post URLs, which is the combination of the blog's -prefix and post prefix. @xref{Blog} for more information. +@item port +An output port into which an RSV is written. @end table @end deffn -@deffn {Procedure} atom-feeds-by-tag [#:prefix "feeds/tags"] @ - [#:filter posts/reverse-chronological] @ - [#:last-updated (current-date)] @ - [#:max-entries 20] [#:blog-prefix ""] -Return a builder procedure that renders an atom feed for every tag -used in a post. All arguments are optional: - -@table @var - -@item prefix -The directory in which to write the feeds. - -@item filter -The procedure called to manipulate the posts list before rendering. - -@item last-updated -The feed last updated date. Defaults to the current date. - -@item max-entries -The maximum number of posts to render in each feed. - -@item blog-prefix -The prefix for all post URLs, which is the combination of the blog's -prefix and post prefix. @xref{Blog} for more information. - -@end table - -@end deffn - -@node RSS -@subsection RSS - -@example -(use-modules (haunt builder rss)) -@end example - -@deffn {Procedure} rss-feed [#:file-name "rss-feed.xml"] [#:subtitle "Recent Posts"] @ - [#:filter posts/reverse-chronological] @ - [#:publication-date (current-date)] @ - [#:max-entries 20] [#:blog-prefix ""] -Return a builder procedure that renders a list of posts as an RSS -feed. All arguments are optional: - -@table @var - -@item file-name -The page file name. - -@item subtitle -The feed subtitle. - -@item filter -The procedure called to manipulate the posts list before rendering. - -@item publication-date -The feed publication date. Defaults to the current date. - -@item max-entries -The maximum number of posts to render in the feed. - -@item blog-prefix -The prefix for all post URLs, which is the combination of the blog's -prefix and post prefix. @xref{Blog} for more information. - -@end table - -@end deffn - -@node Redirects -@subsection Redirects - -@example -(use-modules (haunt builder redirects)) -@end example - -The redirects builder creates pages that trigger browser redirects to -another URL. This allows for easily specifying redirects as part of a -Haunt site configuration and without the need for modifying the -configuration of the production web server that is hosting the site. - -@deffn {Procedure} redirects specs -Return a procedure that transforms a list of redirect tuples in -@var{specs}, with the form @code{(from to)}, into a list of pages that -trigger a browser-initiated redirect. - -@code{from} values must be local page file names, @emph{not} URLs, but -@var{to} values may be either local page file names or full URLs to -other websites. - -@example -(redirects '(("/about.html" "/about/me.html") ; local - ("/guile.html" "https://gnu.org/software/guile"))) ; remote -@end example - -@end deffn - -@node Publishers -@section Publishers +@node Bytevectors +@section Bytevectors @example -(use-modules (haunt publisher)) +(import (rsv)) @end example -The purpose of a publisher is to deploy a built site. Haunt comes -with some built-in publishers, but custom publishers can be created -with the following interface. - -@deffn {Procedure} make-publisher @var{name} @var{proc} -Create a new publisher. -@end deffn - -@deffn {Procedure} publisher? @var{object} -Return @code{#t} if @var{object} is a publisher. -@end deffn - -@deffn {Procedure} publisher-name @var{publisher} -Return the publisher name. -@end deffn - -@deffn {Procedure} publisher-proc @var{reader} -Return the publisher procedure for @var{publisher}. +@deffn {Procedure} rsv-bytevector->scm @var{bv} +Convert bytevector @var{bv} holding the binary data of an RSV into a list +of lists of string-or-null values. @end deffn -@deffn {Procedure} publish @var{publisher} @var{site} -Publish @var{site} with @var{publisher}. +@deffn {Procedure} scm->rsv->bytevector @var{scm} +Convert @var{scm}, a list of lists of string-or-null values, into RSV +binary data held in a bytevector. @end deffn -@deffn {Procedure} run-command @var{program} @var{args} -Run command @var{program} with @var{args} arguments. -@end deffn - -Haunt comes with the following built-in publishers: - -@node Rsync -@subsection Rsync - -@example -(use-modules (haunt publisher rsync)) -@end example - -@deffn {Procedure} rsync-publisher [#:name 'production] [#:destination] @@ - [#:user] [#:host] [#:name] [#:rsync] @@ - [#:flags '("--compress" "--delete" "--progress" "--recursive" "--verbose")] - -Return a new publisher named @var{name} that publishes a site to -@var{destination}, either locally or to a remote host if @var{host} -and/or @var{user} arguments are specified. Passing @var{rsync} -overrides the @command{rsync} executable used. Passing @var{flags} -overrides the set of command line flags used. -@end deffn +@node Rows Streams +@section Rows Streams -@node Sourcehut -@subsection Sourcehut @example -(use-modules (haunt publisher sourcehut)) +(import (rsv rows-streams)) @end example -@deffn {Procedure} sourcehut-publisher [#:name 'production] [#:hut] [#:tar] -Return a new publisher named @var{name} that publishes a site to -@url{https://srht.site/, sourcehut pages} using the site's configured -domain. Passing @var{hut} and/or @var{tar} overrides the default -@command{hut} and @command{tar} executables used. - -For the publisher to work, the @command{hut} CLI tool that is used -under the hood has to be configured. One can do so by creating -@file{~/.config/hut/config} manually or by running the @command{hut -init} command. In both cases an OAuth access token needs to be -generated via @url{https://meta.sr.ht/oauth2, sourcehut meta}. -@end deffn - -@node Artifacts -@section Artifacts - -@example -(use-modules (haunt artifact)) -@end example - -Artifacts are objects that represent the output of a build. A -collection of artifacts forms a complete website. Artifacts are quite -simple: They contain a file name string that specifies where the -artifact belongs in the build output directory, and a writer procedure -that populates that file with data. - -For example, making an artifact that writes ``Hello, world!'' to -@file{/hello.txt} would look like this: - -@example -(make-artifact "/hello.txt" - (lambda (output) - (call-with-output-file output - (lambda (port) - (display "Hello, world!\n" port))))) -@end example - -Previous versions of Haunt made a distinction between pages, whose -content is defined algorithmically, and assets, whose content is -copied verbatim from an input file such as an image. The artifact -data type is a unifying primitive that replaces both pages and assets. - -Artifacts that require serializing some input, such as SXML, should -use @code{serialize-artifact}. Artifacts that make a verbatim copy of -an input file should use @code{verbatim-artifact}. Unless you are -implementing a custom builder, it's unlikely that these procedures -will be need to used directly. - -@deffn {Procedure} serialized-artifact destination obj serialize -Return a new artifact whose writer serializes @var{obj} using the -procedure @var{serialize} to the @var{destination} in the build output -directory. -@end deffn - -@deffn {Procedure} verbatim-artifact source destination -Return a new artifact that copies the file @var{source} verbatim to -@var{destination} within the build output directory. -@end deffn - -@node Assets -@section Assets - -@example -(use-modules (haunt asset)) -@end example +@deffn {Procedure} port->rsv-row-stream @var{port} +Return a stream of lists of string-or-null values read from +@var{port}. -Assets represent files on disk that should be copied verbatim to a -site's output directory. Common types of assets include CSS, -JavaScript, images, and fonts. It is often the case that there are -entire directories full of static assets to copy over, thus there is a -convenient @code{directory-assets} procedure. However, it's unlikely -that this procedure needs to be used directly. See @pxref{Static -Assets} for a convenient builder. - -@deffn {Procedure} directory-assets @var{directory} @var{keep?} @var{dest} -Create a list of asset objects to be stored within @var{dest} for all -files in @var{directory} that match @var{keep?}, recursively. @end deffn @node Contributing @chapter Contributing -guile-rsv is developed using the Git version control system. The official -repository is hosted at @url{https://git.dthompson.us/haunt.git}. +guile-rsv is developed using the Git version control system. The +official repository is hosted at +@url{https://kaka.farm/~stagit/guile-rsv.git}. -Send patches and bug reports to @email{yuval.langer@gmail.com}. +Tips, bug reports, suggestions, death threats, love letters, and +global (or local) conspiracy theories go to +@email{yuval.langer@@gmail.com}. You can also bug me on +@url{https://libera.chat/} where I go by @code{cow_2001} or on the +@url{https://matrix.org/} federation where I go by +@code{@@falconstinker:matrix.org} @c ********************************************************************* @node GNU Free Documentation License