summaryrefslogtreecommitdiffstats
path: root/site/cleopatra/soupault.org
diff options
context:
space:
mode:
Diffstat (limited to 'site/cleopatra/soupault.org')
-rw-r--r--site/cleopatra/soupault.org811
1 files changed, 381 insertions, 430 deletions
diff --git a/site/cleopatra/soupault.org b/site/cleopatra/soupault.org
index 452f442..92042c2 100644
--- a/site/cleopatra/soupault.org
+++ b/site/cleopatra/soupault.org
@@ -1,209 +1,136 @@
-#+BEGIN_EXPORT html
-<h1><code>soupault</code> Configuration</h1>
-#+END_EXPORT
+#+TITLE: ~soupault~
-#+NAME: build-dir
-#+BEGIN_SRC text :exports none
-build
-#+END_SRC
+#+SERIES: ../cleopatra.html
+#+SERIES_PREV: ./theme.html
+#+SERIES_NEXT: ./commands.html
-#+NAME: prefix
-#+BEGIN_SRC text :exports none
-~lthms
-#+END_SRC
+We use ~soupault~ to build this website[fn::~soupault~ is an awesome
+free software project, with a unique approach to static website
+generation. You should definitely [[https://soupault.app][check out their website]]!].
+
+#+begin_export html
+<nav id="generate-toc"></nav>
+#+end_export
-In a nutshell, the purpose of ~soupault~ is to post-process HTML files
-generated by the generation processes of *~cleopatra~*
+* Installation
-The rest of this document proceeds as follows. We first describe the general
-settings of ~soupault~. Then, we enumerate the widgets enabled for this website.
-Finally, we provide a proper definition for ~soupault~ the *~cleopatra~*
-generation process.
+ We install ~soupault~ in a local switch. We use a witness file
+ ~_opam/.init~ to determine whether or not our switch has always been
+ created during a previous invocation of *~cleopatra~*.
-#+TOC: headlines 2
+ #+begin_src makefile :tangle soupault.mk
+OCAML_VERSION := 4.11.2
+OCAML := ocaml-base-compiler.${OCAML_VERSION}
-* ~soupault~ General Settings
+CONFIGURE += _opam rss.json
+ARTIFACTS += out
-The general ~settings~ section of ~soupault.conf~ is fairly basic, and there is
-little to say that the
-[[https://soupault.neocities.org/reference-manual/#getting-started][“Getting
-Started”]] already discuss in length.
+soupault-prebuild : _opam/init
+ #+end_src
-We emphasize three things:
+ Using ~soupault~ is as simple as calling it, without any particular
+ command-line arguments.
+
+ #+begin_src makefile :tangle soupault.mk
+soupault-build : package-lock.json style.min.css
+ @cleopatra echo "Executing" "soupault"
+ @soupault
+ #+end_src
-- The ~build_dir~ is set to src_text[:exports code :noweb yes]{<<build-dir>>/<<prefix>>}
- in place of simply src_text[:exports code :noweb yes]{<<build-dir>>}.
-- The ~ignore_extensions~ shall be updated to take into account artifacts
- produces by other *~cleopatra~* generation processes.
-- We disable the “clean URLs” feature of ~soupault. This option renames
- a HTML files ~foo/bar.html~ into ~foo/bar/index.html~, which means when served
- by a HTTP server, the ~foo/bar~ URL will work. The issue we have with this
- feature is that the internal links within your websiste needs to take their
- /final/ URL into account, rather than their actual name. If one day ~soupault~
- starts rewriting internal URLs when ~clean_url~ is enabled, we might
- reconsider using it.
+ We now describe our configuration file for ~soupault~.
+
+* Configuration
+
+ #+name: base-dir
+ #+begin_src verbatim :noweb yes :exports none
+~lthms
+ #+end_src
-#+BEGIN_SRC toml :tangle soupault.conf :noweb yes
+** Global Settings
+
+ The options of the ~[settings]~ section of a ~soupault~
+ configuration are often self-explanatory, and we do not spend too
+ much time to detaul them.
+
+ #+begin_src toml :tangle soupault.conf :noweb yes
[settings]
strict = true
-verbose = false
-debug = false
site_dir = "site"
-build_dir = "<<build-dir>>/<<prefix>>"
-
+build_dir = "out/<<base-dir>>"
+doctype = "<!DOCTYPE html>"
+clean_urls = false
+generator_mode = true
+complete_page_selector = "html"
+default_content_selector = "main"
page_file_extensions = ["html"]
ignore_extensions = [
- "draft", "vo", "vok", "vos", "glob",
- "html~", "org", "aux", "sass",
+ "v", "vo", "vok", "vos", "glob",
+ "html~", "org"
]
-
-generator_mode = true
-complete_page_selector = "html"
default_template_file = "templates/main.html"
-default_content_selector = "main"
-doctype = "<!DOCTYPE html>"
-clean_urls = false
-#+END_SRC
-
-#+BEGIN_TODO
-The list of ignored extensions should be programmatically generated with the
-help of *~cleopatra~*.
-#+END_TODO
-
-* Widgets
+pretty_print_html = false
+ #+end_src
** Setting Page Title
-We use the “page title” widget to set the title of the webpage based on the
-first (and hopefully the only) ~<h1>~ tag of the page.
+ We use the “page title” widget to set the title of the webpage
+ based on the first (and hopefully the only) ~<h1>~ tag of the
+ page.
-#+BEGIN_SRC toml :tangle soupault.conf
+ #+begin_src toml :tangle soupault.conf
[widgets.page-title]
widget = "title"
selector = "h1"
default = "~lthms"
prepend = "~lthms: "
-#+END_SRC
+ #+end_src
** Acknowledging ~soupault~
-When creating a new ~soupault~ project (using ~soupault --init~), the default
-configuration file suggests advertising the use of ~soupault~. Rather than
-hard-coding the used version of ~soupault~ (which is error-prone), we rather
-determine the version of ~soupault~ with the following script.
+ When creating a new ~soupault~ project (using ~soupault --init~),
+ the default configuration file suggests advertising the use of
+ ~soupault~. Rather than hard-coding the used version of ~soupault~
+ (which is error-prone), we rather determine the version of
+ ~soupault~ with the following script.
-#+NAME: soupault-version
-#+BEGIN_SRC bash :results verbatim output
+ #+NAME: soupault-version
+ #+begin_src bash :results verbatim output
soupault --version | head -n 1 | tr -d '\n'
-#+END_SRC
+ #+end_src
-The configuration of the widget ---initially provided by ~soupault~--- becomes
-less subject to the obsolescence.
+ The configuration of the widget ---initially provided by
+ ~soupault~--- becomes less subject to the obsolescence[fn::That
+ is, as long as ~soupault~ does not change the output of its
+ ~--version~ option.].
-#+BEGIN_SRC toml :tangle soupault.conf :noweb yes
+ #+begin_src toml :tangle soupault.conf :noweb yes
[widgets.generator-meta]
widget = "insert_html"
html = """<meta name="generator" content="<<soupault-version()>>">"""
selector = "head"
-#+END_SRC
-
-** Generating Table of Contents
-
-The ~toc~ widget allows for generating a table of contents for HTML files which
-contains a node matching a given ~selector~ (in the case of this document,
-~#generate-toc~).
-
-#+BEGIN_SRC toml :tangle soupault.conf
-[widgets.table-of-contents]
-widget = "toc"
-selector = "#generate-toc"
-action = "replace_element"
-valid_html = true
-min_level = 2
-numbered_list = true
-#+END_SRC
-
-#+BEGIN_TODO
-We could propose a patch to ~soupault~'s upstream to add numbering in titles.
-#+END_TODO
-
-** Fixing Org Internal Links
-
-For some reason, Org prefix internal links to other Org documents with
-~file://~. To avoid that, we provide a simple plugin which removes ~file://~
-from the begining of a URL.
-
-#+BEGIN_TODO
-This plugin definition should be part of [[./Contents/Org.org][the ~org~
-generation process]], but that would require to aggregate “subconfig” into a
-larger one.
-#+END_TODO
-
-This plugin key component is the =fix_org_urls= function.
-
-- =fix_org_urls(LIST, ATTR)= ::
- Enumerate the DOM elements of =LIST=, and check their =ATTR= attribute.
-
-#+BEGIN_SRC lua :tangle plugins/fix-org-urls.lua
-function fix_org_urls(list, attr)
- index, link = next(list)
-
- while index do
- href = HTML.get_attribute(link, attr)
-
- if href then
- href = Regex.replace(href, "^file://", "")
- HTML.set_attribute(link, attr, href)
- end
-
- index, link = next(list, index)
- end
-end
-#+END_SRC
-
-We use this function to fix the URLs of tags known to be subject to Org strange
-behavior. For now, only ~<a>~ has been affected.
-
-#+BEGIN_SRC lua :tangle plugins/fix-org-urls.lua
-fix_org_urls(HTML.select(page, "a"), "href")
-fix_org_urls(HTML.select(page, "img"), "src")
-#+END_SRC
-
-The configuration of this plugin, and the associated widget, is straightforward.
-
-#+BEGIN_SRC toml :tangle soupault.conf :noweb tangle
-[widgets.fix-org-urls]
-widget = "fix-org-urls"
-#+END_SRC
+ #+end_src
** Prefixing Internal URLs
-On the one hand, internal links can be absolute, meaning they start with a
-leading ~/~, and therefore are relative to the website root. On the other hand,
-website (especially static website) can be placed in larger context. For
-instance, my personal website lives inside the ~~lthms~ directory of the
-~soap.coffee~ domain.
+ On the one hand, internal links can be absolute, meaning they
+ start with a leading ~/~, and therefore are relative to the
+ website root. On the other hand, website (especially static
+ website) can be placed in larger context. For instance, my
+ personal website lives inside the ~~lthms~ directory of the
+ ~soap.coffee~ domain[fn::To my experience in hosting webapps and
+ websites, this set-up is way harder to get right than I initially
+ expect.].
-The purpose of this plugin is to rewrite internal URLs which are relative to the
-root, in order to properly prefix them.
+ The purpose of this plugin is to rewrite internal URLs which are relative to the
+ root, in order to properly prefix them.
-From a high-level perspective, the plugin structure is the following.
+ From a high-level perspective, the plugin structure is the following.
-#+BEGIN_SRC lua :tangle plugins/urls-rewriting.lua :noweb no-export
-prefix_url = config["prefix_url"]
-<<validate_prefix>>
+ First, we validate the widget configuration.
-<<prefix_func>>
-<<prefix_calls>>
-#+END_SRC
-
-1. We validate the widget configuration.
-2. We propose a generic function to enumerate and rewrite tags which can have
- internal URLs as attribute argument.
-3. We use this generic function for relevant tags.
+ #+BEGIN_SRC lua :tangle plugins/urls-rewriting.lua
+prefix_url = config["prefix_url"]
-#+NAME: validate_prefix
-#+BEGIN_SRC lua
if not prefix_url then
Plugin.fail("Missing mandatory field: `prefix_url'")
end
@@ -215,10 +142,12 @@ end
if not Regex.match(prefix_url, "(.*)/$") then
prefix_url = prefix_url .. "/"
end
-#+END_SRC
+ #+END_SRC
+
+ Then, we propose a generic function to enumerate and rewrite tags
+ which can have.
-#+NAME: prefix_func
-#+BEGIN_SRC lua
+ #+BEGIN_SRC lua :tangle plugins/urls-rewriting.lua
function prefix_urls (links, attr, prefix_url)
index, link = next(links)
@@ -236,33 +165,35 @@ function prefix_urls (links, attr, prefix_url)
index, link = next(links, index)
end
end
-#+END_SRC
+ #+END_SRC
-#+NAME: prefix_calls
-#+BEGIN_SRC lua
+ Finally, we use this generic function for relevant tags.
+
+ #+BEGIN_SRC lua :tangle plugins/urls-rewriting.lua
prefix_urls(HTML.select(page, "a"), "href", prefix_url)
prefix_urls(HTML.select(page, "link"), "href", prefix_url)
prefix_urls(HTML.select(page, "img"), "src", prefix_url)
prefix_urls(HTML.select(page, "script"), "src", prefix_url)
-#+END_SRC
+prefix_urls(HTML.select(page, "use"), "href", prefix_url)
+ #+END_SRC
-Again, configuring soupault to use this plugin is relatively straightforward.
-The only important thing to notice is the use of the ~after~ field, to ensure
-this plugin is run /after/ the plugin responsible for fixing Org documents URLs.
+ Again, configuring soupault to use this plugin is relatively
+ straightforward.
-#+BEGIN_SRC toml :tangle soupault.conf :noweb tangle
+ #+BEGIN_SRC toml :tangle soupault.conf :noweb yes
[widgets.urls-rewriting]
widget = "urls-rewriting"
-prefix_url = "<<prefix>>"
-after = "fix-org-urls"
-#+END_SRC
+prefix_url = "<<base-dir>>"
+after = "mark-external-urls"
+ #+END_SRC
** Marking External Links
-#+BEGIN_SRC lua :tangle plugins/external-urls.lua
+ #+BEGIN_SRC lua :tangle plugins/external-urls.lua
function mark(name)
- return '<i class="url-mark fa fa-' .. name ..
- '" aria-hidden="true"></i>'
+ return '<span class="icon"><svg><use href="/img/icons.svg#'
+ .. name ..
+ '"></use></svg></span>'
end
links = HTML.select(page, "a")
@@ -274,85 +205,101 @@ while index do
if href then
if Regex.match(href, "^https?://github.com") then
- icon = HTML.parse(mark('github'))
+ icon = HTML.parse(mark("github"))
HTML.append_child(link, icon)
elseif Regex.match(href, "^https?://") then
- icon = HTML.parse(mark('external-link'))
+ icon = HTML.parse(mark("external-link"))
HTML.append_child(link, icon)
end
end
index, link = next(links, index)
end
-#+END_SRC
-
-#+BEGIN_SRC sass :tangle site/style/plugins.sass
-.url-mark.fa
- display: inline
- font-size: 90%
- width: 1em
-
-.url-mark.fa-github::before
- content: "\00a0\f09b"
+ #+END_SRC
-.url-mark.fa-external-link::before
- content: "\00a0\f08e"
-#+END_SRC
-
-#+BEGIN_SRC toml :tangle soupault.conf
+ #+BEGIN_SRC toml :tangle soupault.conf
[widgets.mark-external-urls]
after = "generate-history"
widget = "external-urls"
-#+END_SRC
+ #+END_SRC
+
+** Generating a Table of Contents
+
+ The ~toc~ widget allows for generating a table of contents for
+ HTML files which contains a node matching a given ~selector~ (in
+ the case of this document, ~#generate-toc~).
+
+ #+begin_src toml :tangle soupault.conf
+[widgets.table-of-contents]
+widget = "toc"
+selector = "#generate-toc"
+action = "replace_content"
+valid_html = true
+min_level = 2
+max_level = 3
+numbered_list = false
+heading_links = true
+heading_link_text = " §"
+heading_links_append = true
+heading_link_class = "anchor-link"
+
+[widgets.append-toc-title]
+widget = "preprocess_element"
+selector = "#generate-toc"
+command = 'echo "<h2>Table of Contents</h2> $(cat)"'
+after = "table-of-contents"
+ #+end_src
** Generating Per-File Revisions Tables
*** Users Instructions
-This widgets allows to generate a so-called “revisions table” of the filename
-contained in a DOM element of id ~history~, based on its history. Paths should
-be relative to the directory from which you start the build process (typically,
-the root of your repository). The revisions table notably provides hyperlinks to
-a ~git~ webview for each commit.
+ This widgets allows to generate a so-called “revisions table” of
+ the filename contained in a DOM element of id ~history~, based on
+ its history. Paths should be relative to the directory from which
+ you start the build process (typically, the root of your
+ repository). The revisions table notably provides hyperlinks to a
+ ~git~ webview for each commit.
-For instance, considering the following HTML snippet
+ For instance, considering the following HTML snippet
-#+BEGIN_SRC html
+ #+begin_src html
<div id="history">
site/posts/FooBar.org
</div>
-#+END_SRC
+ #+end_src
-This plugin will replace the content of this ~<div>~ with the revisions table of
-~site/posts/FooBar.org~.
+ This plugin will replace the content of this ~<div>~ with the
+ revisions table of ~site/posts/FooBar.org~.
*** Customization
-The base of the URL webview for the document you are currently reading
-—afterwards abstracted with the ~<<repo>>~ noweb reference— is
+ The base of the URL webview for the document you are currently
+ reading is src_verbatim[:noweb yes :exports code]{<<repo>>}.
-#+NAME: repo
-#+BEGIN_SRC text
+ #+name: repo
+ #+begin_src verbatim :exports none
https://code.soap.coffee/writing/lthms.git
-#+END_SRC
+ #+end_src
-#+BEGIN_SRC html :tangle templates/history.html :noweb tangle
-<details class="history">
+ The template used to generate the revision table is the following.
+
+ #+begin_src html :tangle templates/history.html :noweb yes
+<details id="history">
<summary>Revisions</summary>
<p>
This revisions table has been automatically generated
- from <a href="<<repo>>">the <code>git</code> history
- of this website repository</a>, and the change
- descriptions may not always be as useful as they
- should.
+ from <a href="<<repo>>">the
+ <code>git</code> history of this website repository</a>, and the
+ change descriptions may not always be as useful as they should.
</p>
<p>
- You can consult the source of this file in its current
- version <a href="<<repo>>/tree/{{file}}">here</a>.
+ You can consult the source of this file in its current version
+ <a href="<<repo>>/tree/{{file}}">here</a>.
</p>
- <table>
+ <table class="fullwidth">
{{#history}}
<tr>
<td class="date"
@@ -362,66 +309,44 @@ https://code.soap.coffee/writing/lthms.git
{{#modified}}
id="modified-at"
{{/modified}}
- >
- {{date}}
- </td>
+ >{{date}}</td>
<td class="subject">{{subject}}</td>
<td class="commit">
- <a href="<<repo>>/commit/{{filename}}/?id={{hash}}">
- {{abbr_hash}}
- </a>
+ <a href="<<repo>>/commit/{{filename}}/?id={{hash}}">{{abbr_hash}}</a>
</td>
</tr>
{{/history}}
</table>
</details>
-#+END_SRC
-
-#+BEGIN_SRC sass :tangle site/style/plugins.sass
-table
- border-top : 2px solid black
- border-bottom : 2px solid black
- border-collapse : collapse
- width : 35rem
-
-td
- border-bottom : 1px solid black
- padding : .5em
-
-#history .commit
- font-size : smaller
- font-family : 'Fira Code', monospace
- width : 7em
- text-align : center
-#+END_SRC
+ #+end_src
*** Implementation
-We use the built-in [[https://soupault.neocities.org/reference-manual/#widgets-preprocess-element][=preprocess_element=]] to implement, which means we need a
-script which gets its input from the standard input, and echoes its output to
-the standard input.
+ We use the built-in [[https://soupault.neocities.org/reference-manual/#widgets-preprocess-element][=preprocess_element=]] to implement, which
+ means we need a script which gets its input from the standard
+ input, and echoes its output to the standard input.
-#+BEGIN_SRC toml :tangle soupault.conf
+ #+begin_src toml :tangle soupault.conf
[widgets.generate-history]
widget = "preprocess_element"
selector = "#history"
command = 'scripts/history.sh templates/history.html'
-action = "replace_content"
-#+END_SRC
+action = "replace_element"
+ #+end_src
-This plugin proceeds as follows:
+ This plugin proceeds as follows:
-1. Using an ad-hoc script, it generates a JSON containing for each revision
- - The subject, date, hash, and abbreviated hash of the related commit
- - The name of the file at the time of this commit
-2. This JSON is passed to a mustache engine (~haskell-mustache~) with a
- proper template
-3. The content of the selected DOM element is replaced with the output of
- ~haskell-mustache~
+ 1. Using an ad-hoc script, it generates a JSON containing for each revision
+ - The subject, date, hash, and abbreviated hash of the related commit
+ - The name of the file at the time of this commit
+ 2. This JSON is passed to a mustache engine (~haskell-mustache~) with a
+ proper template
+ 3. The content of the selected DOM element is replaced with the output of
+ ~haskell-mustache~
-This translates in Bash like this.
+ This translates in Bash like this.
-#+BEGIN_SRC bash :tangle scripts/history.sh :shebang "#!/usr/bin/bash"
+ #+begin_src bash :tangle scripts/history.sh :shebang "#!/usr/bin/bash"
function main () {
local file="${1}"
local template="${2}"
@@ -431,26 +356,27 @@ function main () {
haskell-mustache ${template} ${tmp_file}
rm ${tmp_file}
}
-#+END_SRC
-
-Generating the expected JSON is therefore as simple as:
-
-- Fetching the logs
-- Reading 8 line from the logs, parse the filename from the 6th
- line
-- Outputing the JSON
-
-We will use ~git~ to get the information we need. By default, ~git~
-subcommands use a pager when its output is likely to be long. This
-typically includes ~git-log~. To disable this behavior, ~git~ exposes
-the ~--no-pager~ command. Besides, we also need ~--follow~ and
-~--stat~ to deal with file renaming. Without this option, ~git-log~
-stops when the file first appears in the repository, even if this
-“creation” is actually a renaming. Therefore, the ~git~ command line
-we use to collect our history is
-
-#+NAME: gitlog
-#+BEGIN_SRC bash :tangle scripts/history.sh :noweb yes
+ #+end_src
+
+ Generating the expected JSON is therefore as simple as:
+
+ - Fetching the logs
+ - Reading 8 line from the logs, parse the filename from the 6th
+ line
+ - Outputing the JSON
+
+ We will use ~git~ to get the information we need. By default,
+ ~git~ subcommands use a pager when its output is likely to be
+ long. This typically includes ~git-log~. To disable this
+ behavior, ~git~ exposes the ~--no-pager~ command. Besides, we
+ also need ~--follow~ and ~--stat~ to deal with file
+ renaming. Without this option, ~git-log~ stops when the file
+ first appears in the repository, even if this “creation” is
+ actually a renaming. Therefore, the ~git~ command line we use to
+ collect our history is
+
+ #+name: gitlog
+ #+begin_src bash :tangle scripts/history.sh :noweb yes
function gitlog () {
local file="${1}"
git --no-pager log \
@@ -459,33 +385,35 @@ function gitlog () {
--pretty=format:'%s%n%h%n%H%n%cs%n' \
"${file}"
}
-#+END_SRC
+ #+end_src
-This function will generate a sequence of 8 lines containing all the
-relevant information we are looking for, for each commit, namely:
+ This function will generate a sequence of 8 lines containing all
+ the relevant information we are looking for, for each commit,
+ namely:
-- Subject
-- Abbreviated hash
-- Full hash
-- Date
-- Empty line
-- Change summary
-- Shortlog
-- Empty line
+ - Subject
+ - Abbreviated hash
+ - Full hash
+ - Date
+ - Empty line
+ - Change summary
+ - Shortlog
+ - Empty line
-For instance, the =gitlog= function will output the following lines
-for the last commit of this very file:
+ For instance, the =gitlog= function will output the following
+ lines for the last commit of this very file:
-#+BEGIN_SRC bash :results verbatim :exports results :noweb yes
+ #+begin_src bash :results verbatim :exports results :noweb yes
<<gitlog>>
gitlog "soupault.org" | head -n8
-#+END_SRC
+ #+end_src
-Among other things, the 6th line contains the filename. We need to
-extract it, and we do that with ~sed~. In case of file renaming, we
-need to parse something of the form ~both/to/{old => new}~.
+ Among other things, the 6th line contains the filename. We need
+ to extract it, and we do that with ~sed~. In case of file
+ renaming, we need to parse something of the form ~both/to/{old =>
+ new}~.
-#+BEGIN_SRC bash :tangle scripts/history.sh :noweb yes
+ #+begin_src bash :tangle scripts/history.sh :noweb yes
function parse_filename () {
local line="${1}"
local shrink='s/ *\(.*\) \+|.*/\1/'
@@ -493,18 +421,18 @@ function parse_filename () {
echo ${line} | sed -e "${shrink}" | sed -e "${unfold}"
}
-#+END_SRC
-
-The next step is to process the logs to generate the expected JSON. We
-have to deal with the fact that JSON does not allow the last item of
-an array to be concluded by ",". Besides, we also want to indicate
-which commit is responsible for the creation of the file. To do that,
-we use two variables: =idx= and =last_entry=. When =idx= is equal to
-0, we know it is the latest commit. When =idx= is equal to
-=last_entry=, we know we are looking at the oldest commit for that
-file.
-
-#+BEGIN_SRC bash :tangle scripts/history.sh :noweb yes
+ #+end_src
+
+ The next step is to process the logs to generate the expected
+ JSON. We have to deal with the fact that JSON does not allow the
+ last item of an array to be concluded by ",". Besides, we also
+ want to indicate which commit is responsible for the creation of
+ the file. To do that, we use two variables: =idx= and
+ =last_entry=. When =idx= is equal to 0, we know it is the latest
+ commit. When =idx= is equal to =last_entry=, we know we are
+ looking at the oldest commit for that file.
+
+ #+begin_src bash :tangle scripts/history.sh :noweb yes
function generate_json () {
local input="${1}"
local logs="$(gitlog ${input})"
@@ -562,11 +490,11 @@ function generate_json () {
echo -n "]}"
}
-#+END_SRC
+ #+end_src
-Generating the JSON object for a given commit is as simple as
+ Generating the JSON object for a given commit is as simple as
-#+BEGIN_SRC bash :tangle scripts/history.sh :noweb yes
+ #+begin_src bash :tangle scripts/history.sh :noweb yes
function output_json_entry () {
local subject="${1}"
local abbr_hash="${2}"
@@ -585,66 +513,31 @@ function output_json_entry () {
echo -n ",\"filename\":\"${file}\""
echo -n "}"
}
-#+END_SRC
+ #+end_src
-And we are done! We can safely call the =main= function to generate
-our revisions table.
+ And we are done! We can safely call the =main= function to generate
+ our revisions table.
-#+BEGIN_SRC bash :tangle scripts/history.sh
+ #+begin_src bash :tangle scripts/history.sh
main "$(cat)" "${1}"
-#+END_SRC
+ #+end_src
** Rendering Equations Offline
*** Users instructions
-Inline equations written in the DOM under the class src_css{.imath} and using
-the \im \LaTeX \mi syntax can be rendered once and
-for all by ~soupault~. User For instance, ~<span class="imath">\LaTeX</span>~ is
-rendered \im \LaTeX \mi as expected.
+ Inline equations written in the DOM under the class
+ src_css{.imath} and using the \im \LaTeX \mi syntax can be
+ rendered once and for all by ~soupault~. User For instance,
+ ~<span class="imath">\LaTeX</span>~ is rendered \im \LaTeX \mi as
+ expected.
-Using this widgets requires being able to inject raw HTML in input files.
+ Using this widgets requires being able to inject raw HTML in
+ input files.
*** Implementation
-We will use [[https://katex.org][\im \KaTeX \mi]] to render equations offline. \im \KaTeX \mi
-availability on most systems is unlikely, but it is part of [[https://www.npmjs.com/package/katex][npm]], so we can
-define a minimal ~package.json~ file to fetch it automatically.
-
-#+BEGIN_SRC json :tangle package.json
-{
- "private": true,
- "devDependencies": {
- "katex": "^0.11.1"
- }
-}
-#+END_SRC
-
-We introduce a Makefile recipe to call ~npm install~. This command produces a
-file called ~package-lock.json~ that we add to ~GENFILES~ to ensure \im \KaTeX
-\mi will be available when ~soupault~ is called.
-
-If ~Soupault.org~ has been modified since the last generation, Babel will
-generate ~package.json~ again. However, if the modifications of ~Soupault.org~
-do not concern ~package.json~, then ~npm install~ will not modify
-~package-lock.json~ and its “last modified” time will not be updated. This means
-that the next time ~make~ will be used, it will replay this recipe again. As a
-consequence, we systematically ~touch~ ~packase-lock.json~ to satisfy ~make~.
-
-#+BEGIN_SRC makefile :tangle katex.mk
-package-lock.json : package.json
- @cleopatra echo "Fetching" "npm packages"
- @npm install &>> build.log
- @touch $@
-
-CONFIGURE += package-lock.json node_modules/
-#+END_SRC
-
-Once installed and available, \im \KaTeX \mi is really simple to use. The
-following script reads (synchronously!) the standard input, renders it using \im
-\KaTeX \mi and outputs the resut to the standard output.
-
-#+BEGIN_SRC js :tangle scripts/katex.js
+ #+begin_src js :tangle scripts/render-equations.js
var katex = require("katex");
var fs = require("fs");
var input = fs.readFileSync(0);
@@ -656,102 +549,160 @@ var html = katex.renderToString(String.raw`${input}`, {
});
console.log(html)
-#+END_SRC
+ #+end_src
-We reuse once again the =preprocess_element= widget. The selector is ~.imath~
-(~i~ stands for inline in this context), and we replace the previous content
-with the result of our script.
+ We reuse once again the =preprocess_element= widget. The selector
+ is ~.imath~ (~i~ stands for inline in this context), and we
+ replace the previous content with the result of our script.
-#+BEGIN_SRC toml :tangle soupault.conf
+ #+begin_src toml :tangle soupault.conf
[widgets.inline-math]
widget = "preprocess_element"
selector = ".imath"
-command = "node scripts/katex.js"
+command = "node scripts/render-equations.js"
action = "replace_content"
[widgets.display-math]
widget = "preprocess_element"
selector = ".dmath"
-command = "DISPLAY=1 node scripts/katex.js"
+command = "DISPLAY=1 node scripts/render-equations.js"
action = "replace_content"
-#+END_SRC
+ #+end_src
+
+** RSS Feed
+
+ #+begin_src toml :tangle soupault.conf
+[index]
+index = true
+dump_json = "rss.json"
+extract_after_widgets = ["urls-rewriting"]
+
+[index.fields]
+title = {
+ selector = ["h1"]
+}
-The \im\KaTeX\mi font is bigger than the serif font used for this
-website, so we reduce it a bit with a dedicated SASS rule.
+modified-at = {
+ selector = ["#modified-at"]
+}
-#+BEGIN_SRC sass :tangle site/style/plugins.sass
-.imath, .dmath
- font-size : smaller
+created-at = {
+ selector = ["#created-at"]
+}
+ #+end_src
-.dmath
- text-align : center
-#+END_SRC
+** Series Navigation
-* *~cleopatra~* Generation Process Definition
+ #+begin_src lua :tangle plugins/series.lua
+function get_title_from_path (path)
+ if Sys.is_file(path) then
+ local content_raw = Sys.read_file(path)
+ local content_dom = HTML.parse(content_raw)
+ local title = HTML.select_one(content_dom, "h1")
-We introduce the ~soupault~ generation process, obviously based on the
-[[https://soupault.neocities.org/][~soupault~ HTML processor]]. The structure of
-a *~cleopatra~* generation process is always the same.
+ if title then
+ return String.trim(HTML.inner_html(title))
+ else
+ Plugin.fail(path .. ' has no <h1> tag')
+ end
+ else
+ Plugin.fail(path .. ' is not a file')
+ end
+end
+ #+end_src
+
+ #+begin_src lua :tangle plugins/series.lua
+function generate_nav_item_from_title (title, url, template)
+ local env = {}
+ env["url"] = url
+ env["title"] = title
+ local new_content = String.render_template(template, env)
+ return HTML.parse(new_content)
+end
+ #+end_src
-#+BEGIN_SRC makefile :tangle soupault.mk :noweb no-export
-<<stages>>
-<<dependencies>>
-<<ad-hoc-cmds>>
-#+END_SRC
+ #+begin_src lua :tangle plugins/series.lua
+function generate_nav_items (cwd, cls, template)
+ local elements = HTML.select(page, cls)
-In the rest of this section, we define these three components.
+ local i = 1
+ while elements[i] do
+ local element = elements[i]
+ local url = HTML.strip_tags(element)
+ local path = Sys.join_path(cwd, url)
+ local title_str = get_title_from_path(path)
-** Build Stages
+ HTML.replace_content(
+ element,
+ generate_nav_item_from_title(title_str, url, template)
+ )
-From the perspective of *~cleopatra~*, it is a rather simple component, since
-the ~build~ stage is simply a call to ~soupault~, whose outputs are located in a
-single (configurable) directory.
+ i = i + 1
+ end
+end
+ #+end_src
-#+NAME: stages
-#+BEGIN_SRC makefile :noweb yes
-soupault-build :
- @cleopatra echo Running soupault
- @soupault
+ #+begin_src lua :tangle plugins/series.lua
+cwd = Sys.dirname(page_file)
-ARTIFACTS += <<build-dir>>/
-#+END_SRC
+home_template = 'This article is part of the series “<a href="{{ url }}">{{ title }}</a>.”'
+nav_template = '<a href="{{ url }}">{{ title }}</a>'
-** Dependencies
+generate_nav_items(cwd, ".series", home_template)
+generate_nav_items(cwd, ".series-prev", nav_template)
+generate_nav_items(cwd, ".series-next", nav_template)
+ #+end_src
-Most of the generation processes (if not all of them) need to declare themselves
-as a prerequisite for ~soupault-build~. If they do not, they will likely be
-executed after ~soupault~ is called.
+#+begin_src toml :tangle soupault.conf
+[widgets.series]
+widget = "series"
+#+end_src
-This file defines an auxiliary SASS sheet that needs to be declared as a
-dependency of the build stage of the [[./Theme.org][~theme~ generation
-process]].
+** Injecting Minified CSS
-Finally, the offline rendering of equations requires \im \KaTeX \mi to be
-available, so we include the ~katex.mk~ file, and make ~package-lock.json~ (the
-proof that ~npm install~ has been executed) a prerequisite of ~soupault-build~.
+ #+begin_src lua :tangle plugins/css.lua
+style = HTML.select_one(page, "style")
-#+NAME: dependencies
-#+BEGIN_SRC makefile
-theme-build : site/style/plugins.sass
-include katex.mk
-soupault-build : package-lock.json
-#+END_SRC
+if style then
+ css = HTML.create_text(Sys.read_file("style.min.css"))
+ HTML.replace_content(style, css)
+end
+ #+end_src
-** Ad-hoc Commands
+ #+begin_src toml :tangle soupault.conf
+[widgets.css]
+widget = "css"
+ #+end_src
-Finally, this generation process introduces a dedicated (~PHONY~) command to
-start a HTTP server in order to navigate the generated website from a browser.
+** Cleaning-up
-#+NAME: ad-hoc-cmds
-#+BEGIN_SRC makefile :noweb yes
-serve :
- @echo " start a python server"
- @cd <<build-dir>>; python -m http.server 2>/dev/null
+ #+begin_src lua :tangle plugins/clean-up.lua
+function remove_if_empty(html)
+ if String.trim(HTML.inner_html(html)) == "" then
+ HTML.delete(html)
+ end
+end
+ #+end_src
+
+ #+begin_src lua :tangle plugins/clean-up.lua
+function remove_all_if_empty(cls)
+ local elements = HTML.select(page, cls)
+
+ local i = 1
+ while elements[i] do
+ local element = elements[i]
+ remove_if_empty(element)
+ i = i + 1
+ end
+end
+ #+end_src
-.PHONY : serve
-#+END_SRC
+ #+begin_src lua :tangle plugins/clean-up.lua
+remove_all_if_empty("p") -- introduced by org-mode
+remove_all_if_empty("div.code") -- introduced by coqdoc
+ #+end_src
-This command does not assume anything about the current state of generation of
-the project. In particular, it does not check whether or not the ~<<build-dir>>~
-directory exists. The responsibility to use ~make serve~ in a good setting lies
-with final users.
+#+begin_src toml :tangle soupault.conf
+[widgets.clean-up]
+widget = "clean-up"
+#+end_src