SLWEB(1) General Commands Manual SLWEB(1)
NAME
slweb - Simple static website generator
SYNOPSIS
slweb [-h | --help]
slweb [-v | --version]
slweb [-b | --body-only] [-d | --basedir directory] [-p | --global-
link-prefix URL] [filename]
COPYRIGHT
slweb Copyright © 2020, 2021, 2022, 2023 Strahinya Radich.
This program is licensed under GNU GPL v3 or later. See the file LI-
CENSE in the slweb repository for details.
DESCRIPTION
slweb is a static website generator which aims at being simplistic. It
transforms custom Markdown-like syntax into HTML.
OPTIONS
-b
--body-only
Only add the contents of the <body> tag, skipping <html> and
<head>.
-d directory
--basedir directory
Set the base directory for includes ({include} and {incdir}) and
favicons. Defaults to the current directory (".").
-h
--help
Print this usage information screen.
-p URL
--global-link-prefix URL
Set URL as a global prefix for relative links.
-v
--version
Print program version and exit.
REFERENCE
Files processed by slweb are using a minimal subset of Markdown with
added directives.
Supported Markdown features
• Backticks. Text inside `backticks` will be put inside
<code></code>. Text surrounded by triple backticks (```) on the
lines by themselves will be put inside <pre></pre>. Any "less-than"
characters inside backticks will be converted to < and "amper-
sand" characters to &. Any text following the first triple
backticks until the end of the line will be ignored. This is to ac-
count for language highlighting specification, which isn't yet sup-
ported.
• Blockquotes. Starting the line with > will surround it with a
<blockquote> tag. Multiple lines are supported.
• Bold/italic. Text inside *asterisks* or _underlines_ will be put
inside <em></em>. Text inside **double asterisks** or __double un-
derlines__ will be put inside <strong></strong>. ***More than
two*** of the ___same symbol___ should be avoided.
• Break marks. To address combinations of lists and "raw" tags,
which are problematic to mix together, slweb supports explicitly
marking a raw tag with a "break mark". This currently means that
when such a tag is introduced, any running list item and list will
be closed prior to outputting the custom tag. Tags with break
marks are introduced by prepending the exclamation mark to the tag
name. For example, without a break mark, the input:
- Some list
{break-here}
produces the following output:
<ul><li><p>Some list
<break-here></p></li></ul>
When changed to:
- Some list
{!break-here}
slweb will output:
<ul><li><p>Some list
</p></li></ul>
<break-here>
Same for end tags:
{dl}{dt}{p}Introduction{/dt}
{dd}
- One
- Two
{/dd}{/dl}
produces:
<dl><dt><p>Introduction</dt>
<dd>
<ul><li><p>One
</p></li>
<li><p>Two
</dd></dl></p></li></ul>
while
{dl}{dt}{p}Introduction{/dt}
{dd}
- One
- Two
{/!dd}{/dl}
produces:
<dl><dt><p>Introduction</dt>
<dd>
<ul><li><p>One
</p></li>
<li><p>Two
</p></li></ul>
</dd></dl>
• Footnotes (regular and inline). Two-part regular footnotes can be
added in a manner similar to links (see Links). Inline footnotes
are also supported.
- Regular footnotes have two mandatory parts: first, the footnote
mark is represented by [^footnoteid], where footnoteid is the
footnote identifier. Second, the text of the footnote is repre-
sented by [^footnoteid]: sometext, with sometext being the text
of the footnote. Footnote text construct needs to begin at the
start of a line, and it is the most practical to have it placed
near the bottom of the file, similar to normal links.
Combined, the input:
This is a text[^first].
[^first]: With a footnote!
gives (some lines are wrapped for this manual):
<p>This is a text<a href="#footnote-1" id="footnote-text-1">
<sup>1</sup></a>.</p>
<hr>
<p id="footnote-1"><a href="#footnote-text-1">1.</a>
With a footnote!</p>
- Inline footnotes can be added by using the construct ^[foot-
notetext]. For example, input
Inline footnote^[Footnote text] in a paragraph.
will produce
Inline footnote<a href="#inline-footnote-1"
id="inline-footnote-text-1"><sup>1</sup></a> in a
paragraph.
<hr>
<p id="inline-footnote-1"><a href="#inline-footnote-text-1">
1.</a> Footnote text</p>
The horizontal rule and the list of footnotes is output only once,
before the end of HTML document body. Rule and the list of foot-
notes can be surrounded by a div with the "footnotes" id by setting
the YAML variable add-footnote-div to "1" (see add-footnote-div).
Inline and regular footnotes can be used at the same time, but they
don't share the numbering. This doesn't affect functionality, but
it does affect presentation, as some footnote numbers will overlap.
As a result, whenever slweb encounters both footnote types in the
same document, a warning will be issued to stderr.
• Headings. A line starting with # followed by space will be put in-
side <h?></h?>, where ? stands for 1-4, depending on the number of
hash signs. Tags will have id attributes set to heading-?, with ?
set to the number representing its position within the list of all
headings.
• Horizontal rules. Three dashes at the start of the line will pro-
duce a <hr> in the output. As this Markdown feature clashes with
YAML block boundaries, it will work only if YAML block is present
in the input and before the three dashes for the horizontal rule.
Any text following the three dashes on the same line will be ig-
nored.
Alternatively, three asterisks (***) can be used instead of dashes,
avoiding the necessity for a YAML block preceding the asterisks.
• Images. Similar to links (see Links), images can be added by us-
ing:

Which will produce:
<figure>
<a href="/path/to/image.png" title="Some title" class="image"
target="_blank"><img src="/path/to/image.png" alt="Some title"
width="100" height="50" ></a><figcaption>Some title</figcaption>
</figure>
The attributes width and height will be determined automatically
using the command identify(1) (if present), provided the src attri-
bute contains a valid file path. (Also see image-file-prefix).
As with links, a form similar to the "regular form" of links can
also be used, using the image id instead of the direct URL.
If the additional link or <figure>/<figcaption> tags are not desir-
able, they can be turned off by setting add-image-links and add-
figcaption to "0".
• Keyboard tags. Text inside ||double bars|| will be put inside
<kbd></kbd> tags. As with backticks, any "less-than" character will
be converted to <.
• Line breaks. Two spaces followed by a newline will become <br>.
• Links.
- Inline links. The construct [A link](https://example.com) will
be converted into <a href="https://example.com">A link</a>.
Special case is the form [=somemacro Link title](https://any-
thing) which prepends the body of a macro somemacro into the
<a></a> tag (here broken into multiple lines for clarity):
<a href="https://anything">
<!-- contents of somemacro -->
Link title</a>
This can, for example, be used to add SVG icons to links. See
Macros.
Also, the form [(Link title)](http://asite.com) will surround
the link title (text between <a></a> tags) with <span></span>,
like so:
<a href="http://asite.com"><span>Link title</span></a>
This allows for separate styling of link text. It can be com-
bined with the macro-form:
[=somemacro (Link title)](http://asite.com)
It will prepend the body of a macro somemacro outside of the
<span></span>:
<a href="http://asite.com">
<!-- contents of somemacro -->
<span>Link title</span></a>
Exception is the form [Some text (parenthe-
sized)](https://somelink), which won't output <span> tags, and
will simply include the parentheses in the output instead. This
form doesn't apply to macro-form [=macro Some
(text)](http://link), which will always output <span> tags.
- Regular links. Everything said about inline links applies to
regular links, with the exception that instead of the parenthe-
sized URL, link text inside brackets should be followed by link
id (different than the "id" attribute!) inside brackets, and a
separate definition of that link id is needed, usually near the
end of input.
For example:
Here's a link to [my website][mw].
[mw]: https://mysite.com
will produce:
<p>Here's a link to <a href="https://mysite.com">my
website</a>.</p>
This can help reduce the amount of code in the text of the
page.
• Lists. Lines starting with a dash (-), an asterisk (*) or lower-
case "o", followed by a space, will start an unordered list (if
used for the first time) and start a list item. Input:
Colors are:
- Red
- Green
- Blue
and so on.
will produce:
<p>Colors are:</p>
<ul>
<li><p>Red
</p></li>
<li><p>Green
</p></li>
<li><p>Blue</p>
</li></ul>
<p>And so on.</p>
Indenting a line after a blank line with two spaces will create a
paragraph within the list item, otherwise it will end the list:
- This is a text inside a list item.
Remarkably, this paragraph is as well.
- This is already a second item.
This is after the list.
will produce:
<ul>
<li><p>This is a text inside a list item.</p>
<p>Remarkably, this paragraph is as well.
</p></li>
<li><p>This is already a second item.</p></li></ul>
<p>This is after the list.</p>
Lists can't be nested, and the characters inside an existing list
which would otherwise start a list shall just be inserted as-is in
the output.
• Non-breaking hyphen. Tilde followed by a hyphen (~-) will insert
‑ in the output.
• Non-breaking space. Two consecutive tildes (~~) will produce
in the output.
• Paragraphs. Text surrounded by newlines will be put inside <p></p>
tags. See KNOWN LIMITATIONS.
• Strikethrough. Text surrounded by tildes (~) will be put inside
<s></s>.
• Tables. Lines starting with vertical bars (|) will be transformed
into HTML tables. The first such line is treated as a header row,
second as the alignment specifier (currently ignored), and the rest
regular rows. Table cells and header cells are specified by addi-
tional bar characters. For example, input:
| Month | Jan | Feb | Mar | Apr |
|-------|-----|-----|-----|-----|
| Qty | 2.35| 1.2 | 8 | 15 |
will be transformed into:
<table>
<thead>
<tr><th> Month </th><th> Jan </th><th> Feb </th><th> Mar </th>
<th> Apr </th></tr>
</thead>
<tbody>
<tr><td> Qty </td><td> 2.35</td><td> 1.2 </td><td> 8 </td>
<td> 15 </td></tr>
</tbody>
</table>
Partial tables are a modification of Markdown tables, allowing them
to be combined with the TSV or CSV directive. In order for tables
to work with templating, they need two additional lines at the top
and the bottom, to mark the start and the end of the table. All the
lines in partial tables need to start with "|@", with only the
character following at-mark being different:
|@\------|-----|-----|-----|-----|
{tsv "../tsv/sales" 1}
|@# $#1 | $#2 | $#3 | $#4 | $#5 |
{/tsv}
|@-------|-----|-----|-----|-----|
{tsv "../tsv/sales"}
|@ $1 | $2 | $3 | $4 | $5 |
{/tsv}
|@/------|-----|-----|-----|-----|
The rest of the line following the third character in top, bottom
and lines separating header from body is ignored by the parser and
is included in this example only for aesthetic purposes. See
TSV/CSV templating.
Math mode
Math mode is supported through KaTeX. With katex installed, anything
between dollar signs ($) will be transformed into MathML and HTML
markup. To generate display math, use double dollar signs ($$). The
text between the dollar signs in both cases should be LaTeX source
code, and is passed to katex. The KaTeX stylesheet is not included,
and needs to be included separately through the stylesheet or inline-
stylesheet YAML variables (see stylesheet, inline-stylesheet).
Directives
• Brand "watermark". Directive {made-by} results in a div to be out-
put at the end of the document, with the id made-by containing the
"watermark" text and a link to the slweb home page.
• General tags. Directive {sometag}{/sometag} will be transformed
into <sometag></sometag>.
- Class attributes. Directive {tag.myclass mysecondclass}{/tag}
will be transformed into <tag class="myclass mysecond-
class"></tag>. Only one class attribute is permitted per tag
directive (subsequent dots will be inserted as part of the
class attribute), but you can include multiple classes by sepa-
rating them with a space, just like in HTML, and you can have
both a class attribute and an id attribute per tag.
A variation of this is to use a special form {.myclass}{/.my-
class}, which will be transformed into <div class="my-
class"></div>.
- Id attributes. Directive {tag#myid}{/tag} will be transformed
into <tag id="myid"></tag>. Only one id attribute is permitted
per tag directive (subsequent hash signs will be included as
part of the id attribute), and you can have both an id attri-
bute and a class attribute per tag.
A variation of this is to use a special form {#myid}{/#myid},
which will be transformed into <div id="myid"></div>.
• Includes. Directive {include "somefile"} will fork, parse some-
file.slw (related to basedir) and output the resulting HTML as if
the option --body-only was specified. All YAML variables will be
preserved.
• Macros. Macros can be declared using the directive {=!macron-
ame}{/=!macroname}, where macroname is the name of the macro. Any-
thing between those two tags will then become the body of a macro.
Whenever {=macroname} is subsequently encountered in the file, it
will be replaced by the macro body. Macro definitions can't be
nested nor can they contain macro calls, and doing so will produce
an error. Tags won't be processed within the body of a macro.
• Previous Git commit information. Directive {git-log} is converted
into a div with the id git-log containing the information about the
previous commit (as having information about the current commit
would be impossible).
• Subdirectory inclusion (blogging directive). The directive {incdir
"dirname" num =macroname listonly} (num, macroname and the literal
"listonly" are optional) will be expanded as follows:
1. A <ul class="incdir"> tag will be inserted into the document
instead of the directive.
2. For every subdirectory of dirname, relative to current direc-
tory and up to num (if present) or 5 (if omitted) total subdi-
rectories, a <li> tag will be inserted into the ul tag.
If the parameter listonly was specified, a <li> tag will in-
stead be inserted for every .slw file within each of the subdi-
rectories, sorted in reverse lexicographical order. In this
case, each <li> will contain a permalink with a title preceded
by a timestamp formatted according to list_timestamp_format.
Title and date are read from each .slw file, as YAML variables
title and date. For this case, processing of the incdir direc-
tive stops here.
3. A <details> tag will be inserted into each <li> tag.
4. Inside of the <details> tag, a <summary> tag will be inserted
with the name of the subdirectory. If macroname is present, the
name of the subdirectory will be prepended with the body of a
macro macroname (for example, this can be used to include cus-
tom SVG markup as arrows).
5. After <summary> tag, a <div> tag will be inserted into <de-
tails>, containing the concatenated output from processing each
of the .slw files inside that subdirectory in reverse lexico-
graphical order, in a manner similar to the include directive.
(See Includes and date, ext-in-permalink, permalink-url,
samedir-permalink variables.) The output of each file will be
surrounded by an <article> tag.
If the included file has the variable incdir-only-summary set to
"1", only the text within the summary marks (/- and -/) will be
output, and if the variable incdir-footer-permalink-text is also
set, <footer> element with a permalink to the article will be added
after it. Example: (posts/blog-post.slw)
---
incdir-only-summary: 1
---
/-This article is great!-/ The quick brown fox jumps over the lazy sleeping dog.
The quick brown fox jumps over the lazy sleeping dog. The quick brown fox jumps
over the lazy sleeping dog. The quick brown fox jumps over the lazy sleeping
dog. The quick brown fox jumps over the lazy sleeping dog. The quick brown fox
jumps over the lazy sleeping dog.
(blog-index.slw)
---
incdir-footer-permalink-text: Click here!
---
{incdir "."}
will produce
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="slweb">
</head>
<body>
<ul class="incdir">
<li>
<details open>
<summary>posts</summary>
<div>
<article>
This article is great!<footer>
<a href="././posts/blog-post">Click here!</a>
</footer>
</article>
</div>
</details>
</li>
</ul>
</body>
</html>
for blog-index.slw, and
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="slweb">
</head>
<body>
<p>This article is great! The quick brown fox jumps over the lazy sleeping dog.
The quick brown fox jumps over the lazy sleeping dog. The quick brown fox jumps
over the lazy sleeping dog. The quick brown fox jumps over the lazy sleeping
dog. The quick brown fox jumps over the lazy sleeping dog. The quick brown fox
jumps over the lazy sleeping dog.</p>
</body>
</html>
for posts/blog-post.slw.
• TSV/CSV templating. Directive {tsv "tsvfile" iter}{/tsv} marks a
template. Whatever is between {tsv} and {/tsv} will be processed
by slweb and collected as a template. Afterwards, file tsvfile.tsv
will be read and for each of its lines (up to iter, if present) the
collected template will be output, substituting each occurrence of
a register mark $n (where n is between 1 and 9, inclusive) with the
corresponding TSV field of the read line. All of this applies to
the similar {csv} directive for CSV files. In the case of CSV
files, they need to use semicolons (;) or commas (,) as delimiters
(or set csv-delimiter as a YAML variable in the calling .slw file)
and double quotation marks (") as field boundaries. First line in
the TSV file is parsed as a header and associated with register
marks $#1 to $#9. The symbol $ is represented as $$. Consequently,
math modes (both inline and display) cannot be used within tem-
plates.
Parts of the template can be conditionally rendered by using
the construct:
$?n
<!-- code to include if $n nonempty -->
$?!
<!-- code to include if $n empty -->
$?/
where n is between 1 and 9, inclusive. For example, having a file
sales.tsv:
Item Q1 2020 Q2 2020 Q3 2020 Q4 2020
Toothpick 15.2 12 10
Teapot 1.2 5 3.5
We can write
{tsv "sales"}
{.sales-segment}
$#1 {q}$1{/q} sales by quarter for the last year in
thousands of units sold (for $$) were as follows:
$?2{.q1}$2{/.q1}$?!{.q1 na}N/A{/.q1}$?/
$?3{.q2}$3{/.q2}$?!{.q2 na}N/A{/.q2}$?/
$?4{.q3}$4{/.q3}$?!{.q3 na}N/A{/.q3}$?/
$?5{.q4}$5{/.q4}$?!{.q4 na}N/A{/.q4}$?/
{/.sales-segment}
{/tsv}
to get:
<div class="sales-segment">
Item <q>Toothpick</q> sales by quarter for the last year in
thousands of units sold (for $) were as follows:
<div class="q1">15.2</div>
<div class="q2">12</div>
<div class="q3 na">N/A</div>
<div class="q4">10</div>
</div>
<div class="sales-segment">
Item <q>Teapot</q> sales by quarter for the last year in
thousands of units sold (for $) were as follows:
<div class="q1">1.2</div>
<div class="q2 na">N/A</div>
<div class="q3">5</div>
<div class="q4">3.5</div>
</div>
TSV directives can't be nested and doing so will produce an error.
Special YAML variables
• add-article-header. If set to "1", title, date and header text at
the beginning of the output body will be enclosed in a <header>
tag.
• add-figcaption. If set to "0", <figure> and <figcaption> tags
around images will not be added (otherwise they will by default,
see Images).
• add-footnote-div. If set to "1", list of footnotes preceded by a
horizontal rule will be surrounded with a div having the id "foot-
notes" (see Footnotes).
• add-image-links. If set to "0", links around images will not be
added (otherwise they will by default, see Images).
• author. If set, the contents of this variable will be added to the
start of the output body (inside a <header> tag if it is set), sur-
rounded by <address></address>.
• canonical. Contents of this variable will be added as a value of a
rel attribute for the <link rel="canonical"> tag.
• csv-delimiter. Changes the delimiter used for .csv file parsing.
By default, this will be a semicolon (;). See CSV templating.
• date. If present, this variable, assumed to be in ISO 8601 UTC
datetime format, will be parsed to determine the timestamp in
permalinks generated by the incdir directive. The actual values
used depend on the source-level constants article_timestamp_format
(for incdir without the argument "listonly") and list_time-
stamp_format (for incdir with the argument "listonly").
• ext-in-permalink. If set to "0", permalinks generated by the in-
cdir directive will not have the extension included in the href at-
tribute. For example, instead of blog/2020/august.html, the result-
ing permalink will have blog/2020/august.
• favicon-url. If present, this URL will be used as a favicon URL
instead of the default, /favicon.ico.
• feed, feed-type, feed-desc. If all are present, contents of those
variables will be added as href, type and title attributes (respec-
tively) to the <link rel="alternate"> tag in the page's <head>.
• header-text. The contents of this variable will be added to the
start of the output body (inside a <header> tag if it is set), sur-
rounded by <p></p>.
• image-file-prefix. If present, the value of src attribute will be
appended to the contents of this variable, with path separator
added as necessary, when determining the actual file path to pass
to the identify(1) command. Otherwise, src is appended to ".".
• incdir-footer-permalink-text. If set, and the variable incdir-
only-summary is set to "1", when the file where this variable is
set is included by the {incdir} directive, <footer> tag containing
the permalink to the calling file will be appended to the text be-
tween the summary marks /- and -/.
• incdir-only-summary. If set to "1", when the file where this vari-
able is set is included by the {incdir} directive, only the text
within the summary marks /- and -/ will be output.
• inline-stylesheet. The contents of this variable will be treated
as a CSS file name to be included inline in the header using the
<style> tag. You can add more than one inline-stylesheet declara-
tion per .slw file.
• lang. Contents of this variable will be used for the lang attri-
bute of the <html> tag.
• link-prefix. This variable specifies the prefix which will be
prepended to relative URLs in links. Final slash needs to be in-
cluded if link-prefix is a complete path.
• meta. Contents of this variable is treated as a filename specify-
ing the TSV file containing a list of values to be inserted into
meta tags. The first row of this TSV file is treated as the header
row and ignored. First column in this TSV file contains the meta
variable names, and the second column contains meta variable val-
ues. For each row, a <meta name="firstcol" content="secondcol"> is
inserted, where firstcol is the first column, and secondcol is the
second column. If the values in the second column are surrounded
with percent signs (%), the value between them is treated as the
name of the YAML variable to insert. For example, having the file
m.tsv:
Name Content
og:url %canonical%
and
---
canonical: https://example.com/
meta: m.tsv
---
in the .slw file, a
<meta name="og:url" content="https://example.com/">
line will be added to the output.
• permalink-url. If present, this URL will completely replace the
link used in the href attribute of permalinks generated by the in-
cdir directive. This variable is more useful in individual .slw
files inside the subdirectories of the dirname provided to the in-
cdir directive.
• site-desc. The contents of this variable will be inserted as the
value of the content attribute of the <meta name="description">
tag.
• site-name. The contents of this variable will be inserted inside
the <title></title> tags.
• stylesheet. The contents of this variable will be treated as a CSS
file name to be included using the <link rel="stylesheet"> tag. You
can add more than one stylesheet declaration per .slw file.
• title. If present, contents of this variable will be prepended to
the body (inside a <header> tag if it is set) as a heading with the
level determined by the title-heading-level variable, defaulting to
2. (title: Some title becomes <h2>Some title</h2>).
• title-heading-level. See title.
Special macros
• permalink. If present, the body of this macro will be inserted
into permalinks generated by the incdir directive, similar to the
macro-form of links.
SEE ALSO
sed(1)
EXAMPLES
Given the file index.slw in the current directory:
---
site-name: Test website
site-desc: My first website in slweb
---
{main}
# Hello world
This is an _example_ of a statically generated HTML.
{/main}
after using the command:
$ slweb index.slw > index.html
file index.html contains:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test website</title>
<meta charset="utf-8">
<meta name="description" content="My first website in slweb">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="slweb">
</head>
<body>
<main>
<h1>Hello world</h1>
<p>This is an <em>example</em> of a statically generated HTML.</p>
</main>
</body>
</html>
KNOWN LIMITATIONS
• Currently there is no way to determine where the paragraph inside a
tag should begin and end without adding blank lines or using the
{p}{/p} notation. For example, the code
{tag}
First paragraph
Second paragraph
{/tag}
will produce
<tag>
First paragraph
<p>Second paragraph
</tag></p>
You can suppress the paragraph starting/ending tags by prepending
blank lines with a backslash, like this:
{tag}
First paragraph
\
Second paragraph
{/tag}
which will produce
<tag>
First paragraph
Second paragraph
</tag>
Adding blank lines helps, if paragraphs are desired:
{tag}
First paragraph
Second paragraph
{/tag}
will produce
<tag>
<p>First paragraph</p>
<p>Second paragraph</p>
</tag>
Also see Break marks above.
AUTHOR
Strahinya Radich, <https://strahinja.org>
BUGS
Bugs can be reported using the ticket tracker at: <https://todo.sr.ht/
~strahinja/slweb>
slweb 0.9.0-3-g1701d56 October 06, 2023 SLWEB(1)