From 46b2e7a3be44312f93b3d638f9bbd944f5c063a1 Mon Sep 17 00:00:00 2001 From: Thomas Letan Date: Thu, 2 Apr 2020 20:16:53 +0200 Subject: Refactor the build process to use cleopatra the Second --- site/cleopatra/Bootstrap.org | 396 --------------------- site/cleopatra/Contents.org | 3 - site/cleopatra/Contents/Coq.org | 104 ------ site/cleopatra/Contents/Org.org | 180 ---------- site/cleopatra/Soupault.org | 749 --------------------------------------- site/cleopatra/Theme.org | 291 --------------- site/cleopatra/coq.org | 104 ++++++ site/cleopatra/index.org | 47 --- site/cleopatra/org.org | 188 ++++++++++ site/cleopatra/soupault.org | 762 ++++++++++++++++++++++++++++++++++++++++ site/cleopatra/theme.org | 291 +++++++++++++++ 11 files changed, 1345 insertions(+), 1770 deletions(-) delete mode 100644 site/cleopatra/Bootstrap.org delete mode 100644 site/cleopatra/Contents.org delete mode 100644 site/cleopatra/Contents/Coq.org delete mode 100644 site/cleopatra/Contents/Org.org delete mode 100644 site/cleopatra/Soupault.org delete mode 100644 site/cleopatra/Theme.org create mode 100644 site/cleopatra/coq.org delete mode 100644 site/cleopatra/index.org create mode 100644 site/cleopatra/org.org create mode 100644 site/cleopatra/soupault.org create mode 100644 site/cleopatra/theme.org (limited to 'site/cleopatra') diff --git a/site/cleopatra/Bootstrap.org b/site/cleopatra/Bootstrap.org deleted file mode 100644 index 0a2f821..0000000 --- a/site/cleopatra/Bootstrap.org +++ /dev/null @@ -1,396 +0,0 @@ -#+BEGIN_EXPORT html -

Bootstrapping an Extensible Toolchain

-#+END_EXPORT - -A literate program is a particular type of software program where code is not -directly written in source files, but rather in text document as code -snippets. In some sense, literate programming allows for writing in the same -place both the software program and its technical documentation. - -That being said, *~cleopatra~* is a toolchain to build a website before being a -literate program, and one of its objective is to be /part of this very website -it is used to generate/. To acheive this, *~cleopatra~* has been written as a -collection of org files which can be either “tangled” using -[[https://orgmode.org/worg/org-contrib/babel/][Babel]] or “exported” as a HTML -document. Tangling here refers to extracted marked code blocks into files. - -The page you are currently reading is *~cleopatra~* entry point. Its primilarly -purpose is to introduce two Makefiles: ~Makefile~ and ~bootstrap.mk~. - -#+TOC: headlines 2 - -* The Root of Generation - -~Makefile~ serves two purposes: it initiates a few global variables, and it -provides a rule to generate ~bootstrap.mk~. At this point, some readers may -wonder /why/ we need ~Makefile~ in this context, and the motivation behind this -choice is really reminescent of a boot sequence. The rationale is that we need a -“starting point” for *~cleopatra~*. The toolchain cannot live solely inside -org-files, otherwise there would not have any code to execute the first time we -tried to generate the website. We need an initial Makefile, one that has little -chance to change, so that we can almost consider it read-only. Contrary to the -other Makefiles that we will generate, this one will not be deleted by ~make -clean~. - -This is similar to your computer: it requires a firmware to boot, whose purpose -—in a nutshell— is to find and load an operating system. - -Modifying the content of ~Makefile~ in this document /will/ modify -~Makefile~. This means one can easily put *~cleopatra~* into an inconsistent -state, which would prevent further generation. This is why the generated -~Makefile~ should be versioned, so that you can restore it using ~git~ if you -made a mistake when you modified it. - -For readers interested in using *~cleopatra~* for their own websites, this -documents tries to highlight the potential modifications they would have to -make. - -** Global Constants and Variables - -First, ~Makefile~ defines several global “constants” (although as far as I know -~make~ does not support true constant values, it is expected further generation -process will not modify them). - -In a nutshell, - -- ~ROOT~ :: - Tell Emacs where the root of your website sources is, so that tangled output - filenames can be given relative to it rather than the org files. So for - instance, the ~BLOCK_SRC~ tangle parameter for ~Makefile~ looks like ~:tangle - Makefile~, instead of ~:tangle ../../Makefile~. -- ~CLEODIR~ :: - Tell *~cleopatra~* where its sources live. If you place it inside the ~site/~ - directory (as it is intended), and you enable the use of ~org~ files to author - your contents, then *~cleopatra~* documents will be part of your website. If - you don’t want that, just move the directory outside the ~site/~ directory, - and update the ~CLEODIR~ variable accordingly. - -For this website, these constants are defined as follows. - -#+BEGIN_SRC makefile :tangle Makefile :noweb no-export -ROOT := $(shell pwd) -CLEODIR := site/cleopatra -#+END_SRC - -We then introduce two variables to list the output of the generation processes, -with two purposes in mind: keeping the ~.gitignore~ up-to-date automatically, -and providing rules to remove them. - -- ~ARTIFACTS~ :: - Short-term artifacts which can be removed frequently without too much - hassle. They will be removed by ~make clean~. -- ~CONFIGURE~ :: - Long-term artifacts whose generation can be time consuming. They will only be - removed by ~make cleanall~. - -#+BEGIN_SRC makefile :tangle Makefile -ARTIFACTS := build.log -CONFIGURE := -#+END_SRC - -Generation processes shall declare new build outputs using the ~+=~ assignement -operators. Using another operator will likely provent an underisable result. - -** Easy Tangling of Org Documents - -*~cleopatra~* is a literate program implemented with Org mode, an Emacs major -editing mode. We provide the necessary bits to easily tangle Org documents. - -The configuration of Babel is done using an emacs lisp script called -~tangle-org.el~ whose status is similar to ~Makefile~. It is part of the -bootstrap process, and therefore lives “outside” of *~cleopatra~* (it is not -deleted with ~make clean~ for instance). However, it is overwritten. If you try -to modify it and find that *~cleopatra~* does not work properly, you should -restore it using ~git~. - -#+BEGIN_SRC emacs-lisp :tangle scripts/tangle-org.el -(require 'org) -(cd (getenv "ROOT")) -(setq org-confirm-babel-evaluate nil) -(setq org-src-preserve-indentation t) -(add-to-list 'org-babel-default-header-args - '(:mkdirp . "yes")) -(org-babel-do-load-languages - 'org-babel-load-languages - '((shell . t))) -(org-babel-tangle) -#+END_SRC - -We define variables that ensure that the ~ROOT~ environment variable is set and -~tangle-org.el~ is loaded when using Emacs. - -#+BEGIN_SRC makefile :tangle Makefile -EMACSBIN := emacs -EMACS := ROOT="${ROOT}" ${EMACSBIN} -TANGLE := --batch \ - --load="${ROOT}/scripts/tangle-org.el" \ - 2>> build.log -#+END_SRC - -Finally, we introduce a -[[https://www.gnu.org/software/make/manual/html_node/Canned-Recipes.html#Canned-Recipes][canned -recipe]] to seamlessly tangle a given file. - -#+BEGIN_SRC makefile :tangle Makefile -define emacs-tangle = -echo " tangle $<" -${EMACS} $< ${TANGLE} -endef -#+END_SRC - -** Bootstrapping - -The core purpose of ~Makefile~ remains to bootstrap the chain of generation -processes. This chain is divided into three stages: ~prebuild~, ~build~, and -~postbuild~. - -This translates as follows in ~Makefile~. - -#+BEGIN_SRC makefile :tangle Makefile -default : postbuild ignore - -init : - @rm -f build.log - -prebuild : init - -build : prebuild - -postbuild : build - -.PHONY : init prebuild build postbuild ignore -#+END_SRC - -A *generation process* in *~cleopatra~* is a Makefile which provides rules for -these three stages, along with the utilities used by these rules. More -precisely, a generation process ~proc~ is defined in ~proc.mk~. The rules of -~proc.mk~ for each stage are expected to be prefixed by ~proc-~, /e.g./, -~proc-prebuild~ for the ~prebuild~ stage. - -Eventually, the following dependencies are expected between within the chain of -generation processes. - -#+BEGIN_SRC makefile -prebuild : proc-prebuild -build : proc-build -postbuild : proc-postbuild - -proc-build : proc-prebuild -proc-postbuild : proc build -#+END_SRC - -Because *~cleopatra~* is a literate program, generation processes are defined in -Org documents –which may contains additional utilities like scripts or -templates—, and therefore need to be tangled prior to be effectively -useful. *~cleopatra~ relies on a particular behavior of ~make~ regarding the -~include~ directive. If there exists a rule to generate a Makefile used as an -operand of ~include~, ~make~ will use this rule to update (if necessary) said -Makefile before actually including it. - -Therefore, rules of the following form achieve our ambition of extensibility. - -#+BEGIN_SRC makefile :noweb yes -<> -#+END_SRC - -where - -- ~${IN}~ is the Org document which contains the generation process code -- ~${PROC}~ is the name of the generation process -- ~${AUX}~ lists the utilities of the generation process tangled from ~${IN}~ - with ~${PROC}.mk~ - -We use ~&:~ is used in place of ~:~ to separate the target from its dependencies -in the “tangle rule.” This tells ~make~ that the recipe of this rule generates -all these files. - -Writing these rules manually —has yours truly had to do in the early days of his -website— has proven to be error-prone. - -One desirable feature for *~cleopatra~* would be to generate them automatically, -by looking for relevant ~:tangle~ directives inside the input Org document. The -challenge lies in the “relevant” part: the risk exists that we have false -posivite. However and as a first steps towards a fully automated solution, we -can leverage the evaluation features of Babel here. - -Here is a bash script which, given the proper variables, would generate the -expected Makefile rule. - -#+NAME: extends -#+BEGIN_SRC bash :var PROC="" :var AUX="" :var IN="" :results output -cat <> -#+END_SRC - -Beware that, as a consequence, modifying code block of =extends= is as -“dangerous” as modifying ~Makefile~ itself. Keep that in mind if you start -hacking *~cleopatra~*! - -Additional customizations of *~cleopatra~* will be parth ~bootstrap.mk~, rather -than ~Makefile~. - -* Generation Processes - -Using the =extends= noweb reference, *~cleopatra~* is easily extensible. In -this section, we first detail the structure of a typical generation process. -Then, we construct ~bootstrap.mk~ by enumerating the generation processes that -are currently used to generate the website you are reading. - -** Getting Started - -#+BEGIN_TODO -1. Defining ~proc-prebuild~, ~proc-build~, and ~proc-postbuild~ -2. Declaring dependencies between stages of generation processes -3. Declaring build outputs (see ~ARTIFACTS~ and ~CONFIGURE~) -#+END_TODO - -** Active Generation Processes - -*** Theming and Templating - -The [[./Theme.org][~theme~]] generation process controls the general appearance -of the website. More precisely, it introduces the main template used by -~soupault~ (~main/templates.html~), and the main SASS sheet used by this -template. - -If a generation process produces a set of styles within a specific SASS files, -the current approach is - -1. To make this file a dependency of ~theme-build~ -2. To modify ~style/main.sass~ in ~theme~ - to import this file - -#+BEGIN_TODO -Eventually, the second step will be automated, but in the meantime -this customization is mandatory. -#+END_TODO - -#+BEGIN_SRC makefile :tangle bootstrap.mk :noweb yes :exports none -<> -#+END_SRC - -*** Configuring Soupault - -The [[./Soupault.org][~soupault~]] generation configures and run ~soupault~, in -order to generate a static website. - -If a generation process ~proc~ produces files that will eventually be integrated to -your website, its ~proc-build~ recipe needs to be executed /before/ the -~soupault-build~ recipe. This can be enforced by making the dependency explicit -to ~make~, /i.e./, - -#+BEGIN_SRC makefile -soupault-build : proc-build -#+END_SRC - -#+BEGIN_TODO -Eventually, generation processes shall be allowed to produce specific ~soupault~ -widgets to be integrated into ~soupault.conf~. -#+END_TODO - -#+BEGIN_SRC makefile :tangle bootstrap.mk :noweb yes :exports none -<> -#+END_SRC - -*** Authoring Contents - -The fact that *~cleopatra~* is a literate program which gradually generates -itself was not intended: it is a consequence of my desire to be able to easily -use whatever format I so desire for writing my contents, and Org documents in -particular. - -In the present website, contents can be written in the following format: - -- HTML Files :: - This requires no particular set-up, since HTML is the /lingua franca/ of - ~soupault~. -- Regular Coq files :: - Coq is a system which allows to write machine-checked proofs, and it comes - with a source “prettifier” called ~coqdoc~. [[./Contents/Coq.org][Learn more - about the generation process for Coq files​]] -- Org documents :: - Emacs comes with a powerful editing mode called [[https://orgmode.org/][Org - mode]], and Org documents are really pleasant to work with. - [[./Contents/Org.org][Learn more about the generation process for Org - documents]] - -#+BEGIN_SRC makefile :tangle bootstrap.mk :noweb yes :exports none -<> -<> -#+END_SRC - -** Wrapping-up - -#+BEGIN_TODO -~clean~ and ~cleanall~ should probably follow a similar approach than the build -stages. -#+END_TODO - -#+BEGIN_SRC bash :tangle scripts/update-gitignore.sh :shebang "#+/bin/bash" - -BEGIN_MARKER="# begin generated files" -END_MARKER="# begin generated files" - -# remove the previous list of generated files to ignore -sed -i -e "/${BEGIN_MARKER}/,/${END_MARKER}/d" .gitignore -# remove trailing empty lines -sed -i -e :a -e '/^\n*$/{$d;N;};/\n$/ba' .gitignore - -# output the list of files to ignore -echo "" >> .gitignore -echo ${BEGIN_MARKER} >> .gitignore -for f in $@; do - echo "${f}" >> .gitignore -done -echo ${END_MARKER} >> .gitignore -#+END_SRC - -#+BEGIN_SRC makefile :tangle bootstrap.mk -ignore : - @echo " update gitignore" - @scripts/update-gitignore.sh \ - ${ARTIFACTS} \ - ${CONFIGURE} - -clean : - @rm -rf ${ARTIFACTS} - -cleanall : clean - @rm -rf ${CONFIGURE} -#+END_SRC - -# Local Variables: -# org-src-preserve-indentation: t -# End: diff --git a/site/cleopatra/Contents.org b/site/cleopatra/Contents.org deleted file mode 100644 index 0863709..0000000 --- a/site/cleopatra/Contents.org +++ /dev/null @@ -1,3 +0,0 @@ -#+BEGIN_EXPORT html -

Authoring Contents and HTML Generation

-#+END_EXPORT diff --git a/site/cleopatra/Contents/Coq.org b/site/cleopatra/Contents/Coq.org deleted file mode 100644 index 893efab..0000000 --- a/site/cleopatra/Contents/Coq.org +++ /dev/null @@ -1,104 +0,0 @@ -* Author Guidelines - -* Under the Hood - -#+BEGIN_SRC makefile :tangle coq.mk -COQ_POSTS := $(shell find site/ -name "*.v") -COQ_HTML := $(COQ_POSTS:.v=.html) - -coq-build : ${COQ_HTML} - -theme-build : site/style/coq.sass -soupault-build : coq-build - -ARTIFACTS += *.vo *.vok *.vos .*.aux *.glob .lia.cache -ARTIFACTS += ${COQ_HTML} - -COQLIB := "https://coq.inria.fr/distrib/current/stdlib/" -COQCARG := -async-proofs-cache force \ - -w -custom-entry-overriden -COQDOCARG := --no-index --charset utf8 --short \ - --body-only --coqlib "${COQLIB}" - -%.html : %.v coq.mk - @echo " export $*.v" - @coqc ${COQCARG} $< - @coqdoc ${COQDOCARG} -d $(shell dirname $<) $< - @rm -f $(shell dirname $<)/coqdoc.css -#+END_SRC - -#+BEGIN_SRC sass :tangle site/style/coq.sass -@mixin patchy-centered($inc: 0rem) - width : 100vw - position: relative - @media screen and (min-width : $document-width) - padding-left : calc(50vw - #{$document-width} / 2) - right : calc(50vw - #{$document-width} / 2) - @media screen and (max-width : $document-width) - padding-left : 1rem - right : 1rem - -div.code - white-space: nowrap - -.doc - @include padding-centered - margin-top : 1em - margin-bottom : 1em - - pre - @include patchy-centered - padding-top : 1rem - padding-bottom : 1rem - background : $bg-verbatim - overflow-x : auto - -.code - @include padding-centered - @include code-block - -.inlinecode - @include code-font - -h1, h2, h3, h4, h5, h6 - .inlinecode - font-size: 100% - -.code - .id[title="keyword"] - color : #ff6188 - - .id[title="definition"], - .id[title="projection"], - .id[title="theorem"], - .id[title="lemma"] - color : #a9dc76 - - .id[title="inductive"], - .id[title="record"], - .id[title="axiom"], - .id[title="class"] - color : #78dce8 - - .id[title="constructor"] - color : #ab9df2 - - a[href] - color : inherit - text-decoration : none - background : #403e41 - padding : .05rem .15rem .05rem .15rem - border-radius : 15% - - .url-mark - display: none - -.paragraph - margin-top: 1em - margin-bottom: 1em - -#+END_SRC - -# Local Variables: -# org-src-preserve-indentation: t -# End: diff --git a/site/cleopatra/Contents/Org.org b/site/cleopatra/Contents/Org.org deleted file mode 100644 index bd107fc..0000000 --- a/site/cleopatra/Contents/Org.org +++ /dev/null @@ -1,180 +0,0 @@ -* Author Guidelines - -* Under the Hood - -#+BEGIN_SRC emacs-lisp :tangle scripts/packages.el -(require 'package) - -(setq user-emacs-directory (concat (getenv "ROOT") "/emacs.d")) -(setq package-user-dir (concat (getenv "ROOT") "/emacs.d")) -(setq package-archives - '(("gnu" . "https://elpa.gnu.org/packages/") - ("melpa" . "https://melpa.org/packages/"))) - -(package-initialize) - -(or (file-exists-p package-user-dir) - (package-refresh-contents)) - -(defun ensure-package-installed (&rest packages) - "Ensure every PACKAGES is installed." - (mapcar - (lambda (package) - (if (package-installed-p package) - nil - (package-install package)) - package) - packages)) - -(ensure-package-installed 'use-package) -(eval-when-compile (require 'use-package)) - -(use-package org :ensure t) -(use-package htmlize :ensure t) -(use-package lua-mode :ensure t :defer t) -(use-package sass-mode :ensure t :defer t) -(use-package haskell-mode :ensure t :defer t) -(use-package toml-mode :ensure t :defer t) -(use-package json-mode :ensure t :defer t) -(use-package monokai-pro-theme :ensure t :defer t - :init - (load-theme 'monokai-pro t)) - -(provide 'packages) -#+END_SRC - -#+BEGIN_SRC emacs-lisp :tangle scripts/export-org.el -(require 'packages) - -(org-babel-do-load-languages - 'org-babel-load-languages - '((shell . t))) -(setq org-src-preserve-indentation t) -(setq org-src-fontify-natively t) -(setq org-confirm-babel-evaluate nil) -(setq org-export-with-toc nil) - -(add-to-list 'org-entities-user - '("im" "\\(" nil "" "" "" "")) -(add-to-list 'org-entities-user - '("mi" "\\)" nil "" "" "" "")) - -(setq org-babel-exp-code-template - (concat "#+BEGIN_SRC %lang%switches%flags " - ":tangle %tangle :name %name\n" - "%body\n" - "#+END_SRC")) - -(defun cleopatra-html-src-block (oldfun src-block contents info) - (let* - ((old-ret (funcall oldfun src-block contents info)) - (pars (org-babel-parse-header-arguments - (org-element-property :parameters src-block))) - (tangle (cdr (assoc :tangle pars))) - (name (cdr (assoc :name pars)))) - (cond - (name - (concat - "
" - (format "
<<%s>> :=
" name) - old-ret - "
")) - ((not (string= tangle "no")) - (concat - "
" - old-ret - (format "
%s
" tangle) - "
")) - (t old-ret)))) - -(advice-add 'org-html-src-block - :around #'cleopatra-html-src-block) - -(org-html-export-to-html nil nil nil t) -#+END_SRC - -#+BEGIN_SRC makefile :tangle org.mk -ORG_POSTS := $(shell find site/ -name "*.org") -ORG_HTML := $(ORG_POSTS:.org=.html) - -org-prebuild : .emacs -org-build : ${ORG_HTML} - -theme-build : site/style/org.sass -soupault-build : org-build - -ARTIFACTS += ${ORG_HTML} "*.html~" -CONFIGURE += .emacs emacs.d/ - -EXPORT := --directory="${ROOT}/scripts/" --batch \ - --load="${ROOT}/scripts/export-org.el" \ - 2>> build.log -INIT := --batch --load="${ROOT}/scripts/packages.el" \ - 2>> build.log - -.emacs : scripts/packages.el - @echo " init emacs configuration" - @${EMACS} ${INIT} - @touch .emacs - -%.html : %.org scripts/packages.el scripts/export-org.el \ - .emacs org.mk - @echo " export $*.org" - @${EMACS} $< ${EXPORT} -#+END_SRC - -#+BEGIN_SRC sass :tangle site/style/org.sass -.org-src-container - @include code-block - padding-top : .1rem - padding-bottom : .1rem - -.org-src-tangled-to, .org-src-name - @include padding-centered(4rem) - -.example - @include verbatim-block - // this is hacky, but it works: no need for a padding-bottom - padding-top : 1rem - -.footdef - @include padding-centered - -.footpara - display: inline - margin-left: .2em - -.section-number-2:after, -.section-number-3:after - content: ". " - -.section-number-4, -.section-number-5, -.section-number-6 - display: none - -dl - dt - font-weight: bold - dd p - margin-top: 0 - -.footnotes - font-size : 1rem - -.org-literate-programming - padding-top : 1rem - padding-bottom : 1rem - .org-src-name - @include code-font - font-weight: bold - - .org-src-tangled-to:before - content: "\f054" - font : normal normal normal 14px/1 ForkAwesome - - .org-src-tangled-to - @include code-font - font-weight: bold - text-align: right -#+END_SRC diff --git a/site/cleopatra/Soupault.org b/site/cleopatra/Soupault.org deleted file mode 100644 index 5ad51d6..0000000 --- a/site/cleopatra/Soupault.org +++ /dev/null @@ -1,749 +0,0 @@ -#+BEGIN_EXPORT html -

soupault Configuration

-#+END_EXPORT - -In a nutshell, the purpose of ~soupault~ is to post-process HTML files generated -by the generation processes of *~cleopatra~*. It is parameterized by two -settings, the ~<> directory where ~soupault~ generates its output, -and an eventual ~<>~ wherein the website contents lives. The latter -allows to generate only a subpart of a larger website. - -For the present website, these two settings are initialized as follows. - -#+NAME: build-dir -#+BEGIN_SRC text -build -#+END_SRC - -#+NAME: prefix -#+BEGIN_SRC text -~lthms -#+END_SRC - -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. - -#+TOC: headlines 2 - -* ~soupault~ General Settings - -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. - -We emphasize three things: - -- The ~build_dir~ is set to ~<>/<>~ in place of simply - ~<>~. -- 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. - -#+BEGIN_SRC toml :tangle soupault.conf :noweb tangle -[settings] -strict = true -verbose = false -debug = false -site_dir = "site" -build_dir = "<>/<>" - -page_file_extensions = ["html"] -ignore_extensions = [ - "draft", "vo", "vok", "vos", "glob", - "html~", "org", "aux", "sass", -] - -generator_mode = true -complete_page_selector = "html" -default_template = "templates/main.html" -content_selector = "main" -doctype = "" -clean_urls = false -#+END_SRC - -#+BEGIN_TODO -The list of ignored extensions should be programmatically generated with the -help of *~cleopatra~*. -#+END_TODO - -* Widgets - -** Setting Page Title - -We use the “page title” widget to set the title of the webpage based on the -first (and hopefully the only) ~

~ tag of the page. - -#+BEGIN_SRC toml :tangle soupault.conf -[widgets.page-title] -widget = "title" -selector = "h1" -default = "~lthms" -prepend = "~lthms: " -#+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. - -#+NAME: soupault-version -#+BEGIN_SRC bash :results verbatim output :exports both -soupault --version | head -n 1 | tr -d '\n' -#+END_SRC - -The configuration of the widget ---initially provided by ~soupault~--- becomes -less subject to the obsolescence. - -#+BEGIN_SRC toml :tangle soupault.conf :noweb tangle -[widgets.generator-meta] -widget = "insert_html" -html = """ - -""" -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" -min_level = 2 -numbered_list = true -#+END_SRC - -#+BEGIN_TODO -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 file should be part of ~Org.org~, 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 ~~ has been affected. - -#+BEGIN_SRC lua :tangle plugins/fix-org-urls.lua -fix_org_urls(HTML.select(page, "a"), "href") -#+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 - -** 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. - -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. - -#+BEGIN_SRC lua :tangle plugins/urls-rewriting.lua :noweb no-export -prefix_url = config["prefix_url"] -<> - -<> -<> -#+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. - -#+NAME: validate_prefix -#+BEGIN_SRC lua -if not prefix_url then - Plugin.fail("Missing mandatory field: `prefix_url'") -end - -if not Regex.match(prefix_url, "^/(.*)") then - prefix_url = "/" .. prefix_url -end - -if not Regex.match(prefix_url, "(.*)/$") then - prefix_url = prefix_url .. "/" -end -#+END_SRC - -#+NAME: prefix_func -#+BEGIN_SRC lua -function prefix_urls (links, attr, prefix_url) - index, link = next(links) - - while index do - href = HTML.get_attribute(link, attr) - - if href then - if Regex.match(href, "^/") then - href = Regex.replace(href, "^/*", "") - href = prefix_url .. href - end - - HTML.set_attribute(link, attr, href) - end - index, link = next(links, index) - end -end -#+END_SRC - -#+NAME: prefix_calls -#+BEGIN_SRC 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 - -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. - -#+BEGIN_SRC toml :tangle soupault.conf :noweb tangle -[widgets.urls-rewriting] -widget = "urls-rewriting" -prefix_url = "<>" -after = "fix-org-urls" -#+END_SRC - -** Marking External Links - -#+BEGIN_SRC lua :tangle plugins/external-urls.lua -function mark(name) - return '' -end - -links = HTML.select(page, "a") - -index, link = next(links) - -while index do - href = HTML.get_attribute(link, "href") - - if href then - if Regex.match(href, "^https?://github.com") then - icon = HTML.parse(mark('github')) - HTML.append_child(link, icon) - elseif Regex.match(href, "^https?://") then - 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" - -.url-mark.fa-external-link::before - content: "\00a0\f08e" -#+END_SRC - -#+BEGIN_SRC toml :tangle soupault.conf -[widgets.mark-external-urls] -after = "generate-history" -widget = "external-urls" -#+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. - -For instance, considering the following HTML snippet - -#+BEGIN_SRC html -
- site/posts/FooBar.org -
-#+END_SRC - -This plugin will replace the content of this ~
~ 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 ~<>~ noweb reference— is - -#+NAME: repo -#+BEGIN_SRC text -https://code.soap.coffee/writing/lthms.git -#+END_SRC - -#+BEGIN_SRC html :tangle templates/history.html :noweb tangle -
- Revisions -

- This revisions table has been automatically generated - from the git history - of this website repository, and the change - descriptions may not always be as useful as they - should. -

- -

- You can consult the source of this file in its current - version here. -

- - - {{#history}} - - - - - - {{/history}} -
{{date}}{{subject}} - - {{abbr_hash}} - -
-
-#+END_SRC - -#+BEGIN_SRC sass :tangle site/style/plugins.sass -#history - table - @include margin-centered(2rem) - border-top: 2px solid $primary-color - border-bottom: 2px solid $primary-color - border-collapse: collapse; - - td - border-bottom: 1px solid $primary-color - padding: .5em - vertical-align: top - - td.commit - font-size: smaller - - td.commit - font-family: 'Fira Code', monospace - color: $code-fg-color - font-size: 80% - white-space: nowrap; -#+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. - -#+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 - -#+BEGIN_TODO -This plugin should be reimplemented using ~libgit2~ or other ~git~ libraries, in -a language more suitable than bash. -#+END_TODO - -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~ - -This translates in Bash like this. - -#+BEGIN_SRC bash :tangle scripts/history.sh :shebang "#!/usr/bin/bash" -function main () { - local file="${1}" - local template="${2}" - - tmp_file=$(mktemp) - generate_json ${file} > ${tmp_file} - haskell-mustache ${template} ${tmp_file} - rm ${tmp_file} -} -#+END_SRC - -The difficult part of this script is the definition of the =generate_json= -function. From a high-level perspective, this function is divided into three -steps. - -1. We get an initial (but partial) set of data about the ~git~ commit of - ~${file}~, from the most recent to the oldest -2. For each commit, we check whether or not ~${file}~ was renamed or not -3. Finally, we output a result (because we are writing a bash script) - -#+BEGIN_SRC bash :tangle scripts/history.sh :noweb no-export -function generate_json () { - local file="${1}" - local logs=`<>` - - if [ ! $? -eq 0 ]; then - exit 1 - fi - - <> - - <> -} -#+END_SRC - -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. -We introduce =_git=, a wrapper around ~git~ with the proper option. - -#+BEGIN_SRC bash :tangle scripts/history.sh -function _git () { - git --no-pager "$@" -} -#+END_SRC - -Afterwards, we use =_git= in place of ~git~. - -Using the ~git-log~ ~--pretty~ command-line argument, we can generate -one JSON object per commit which contains most of the information we need, using -the following format string. - -#+NAME: pretty-format -#+BEGIN_SRC json -{ "subject" : "%s", "abbr_hash" : "%h", "hash" : "%H", "date" : "%cs" } -#+END_SRC - -Besides, we also need ~--follow~ 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 initial history is - -#+NAME: git-log -#+BEGIN_SRC bash :noweb no-export -_git log --follow --pretty=format:'<>' "${file}" -#+END_SRC - -To manipulate JSON, we rely on three operators (yet to be defined): - -- =jget OBJECT FIELD= :: - In an =OBJECT=, get the value of a given =FIELD= -- =jset OBJECT FIELD VALIE= :: - In an =OBJECT=, set the =VALUE= of a given =FIELD= -- =jappend ARRAY VALUE= :: - Append a =VALUE= at the end of an =ARRAY= - -#+NAME: remane-tracking -#+BEGIN_SRC bash :noweb no-export -local name="${file}" -local revisions='[]' - -while read -r rev; do - rev=$(jset "${rev}" "filename" "\"${name}\"") - revisions=$(jappend "${revisions}" "${rev}") - - local hash=$(jget "${rev}" "hash") - local rename=$(previous_name "${name}" "${hash}") - - if [[ ! -z "${rename}" ]]; then - name=${rename} - fi -done < <(echo "${logs}") -#+END_SRC - -#+BEGIN_SRC bash :tangle scripts/history.sh -function previous_name () { - local name=${1} - local hash=${2} - - local unfold='s/ *\(.*\){\(.*\) => \(.*\)}/\1\2 => \1\3/' - - _git show --stat=10000 ${hash} \ - | sed -e "${unfold}" \ - | grep "=> ${name}" \ - | xargs \ - | cut -d' ' -f1 -} -#+END_SRC - -#+NAME: result-echoing -#+BEGIN_SRC bash :noweb no-export -jset "$(jset "{}" "file" "\"${file}\"")" \ - "history" \ - "${revisions}" -#+END_SRC - -The last missing pieces are the definitions of the three JSON operators. We use -[[https://stedolan.github.io/jq/][~jq~]] to manipulate JSON data. Since ~jq~ -processes JSON from its standard input, we first define a helper (similar to -=_git=) to deal with JSON from variables seamlessly. - -#+BEGIN_SRC bash :tangle scripts/history.sh -function _jq () { - local input="${1}" - local filter="${2}" - - echo "${input}" | jq -jcM "${filter}" -} -#+END_SRC - -- *-j* tells ~jq~ not to print a new line at the end of its outputs -- *-c* tells ~jq~ to print JSON in a compact format (rather than prettified) -- *-M* tells ~jq~ to output monochrome outputs - -Internally, =jget=, =jset=, and =jappend= are implemented with ~jq~ -[[https://stedolan.github.io/jq/manual/#Basicfilters][basic filters]]. - -#+BEGIN_SRC bash :tangle scripts/history.sh -function jget () { - local obj="${1}" - local field="${2}" - - _jq "${obj}" ".${field}" -} - -function jset () { - local obj="${1}" - local field="${2}" - local val="${3}" - - _jq "${obj}" "setpath([\"${field}\"]; ${val})" -} -function jappend () { - local arr="${1}" - local val="${2}" - - _jq "${arr}" ". + [ ${val} ]" -} -#+END_SRC - -Everything is defined. We can call =main= now. - -#+BEGIN_SRC bash :tangle scripts/history.sh -main "$(cat)" "${1}" -#+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, ~\LaTeX~ is -rendered \im \LaTeX \mi as expected. - -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 - @echo " init 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_TODO -This script should be generalized to handle both display and inline -mode. Currently, only inline mode is supported. -#+END_TODO - -#+BEGIN_SRC js :tangle scripts/katex.js -var katex = require("katex"); -var fs = require("fs"); -var input = fs.readFileSync(0); - -var html = katex.renderToString(String.raw`${input}`, { - throwOnError: false -}); - -console.log(html) -#+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. - -#+BEGIN_SRC toml :tangle soupault.conf -[widgets.inline-math] -widget = "preprocess_element" -selector = ".imath" -command = "node scripts/katex.js" -action = "replace_content" -#+END_SRC - -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. - -#+BEGIN_SRC sass :tangle site/style/plugins.sass -.imath - font-size: smaller -#+END_SRC - -* *~cleopatra~* Generation Process Definition - -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. - -#+BEGIN_SRC makefile :tangle soupault.mk :noweb no-export -<> -<> -<> -#+END_SRC - -In the rest of this section, we define these three components. - -** Build Stages - -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. - -#+NAME: stages -#+BEGIN_SRC makefile :noweb no-export -soupault-build : - @echo " run soupault" - @soupault -ARTIFACTS += <>/ -#+END_SRC - -** Dependencies - -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. - -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]]. - -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~. - -#+NAME: dependencies -#+BEGIN_SRC makefile -theme-build : site/style/plugins.sass -include katex.mk -soupault-build : package-lock.json -#+END_SRC - -** Ad-hoc Commands - -Finally, this generation process introduces a dedicated (~PHONY~) command to -start a HTTP server in order to navigate the generated website from a browser. - -#+NAME: ad-hoc-cmds -#+BEGIN_SRC makefile :noweb no-export -serve : - @echo " start a python server" - @cd <>; python -m http.server 2>/dev/null - -.PHONY : serve -#+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 ~<>~ -directory exists. The responsibility to use ~make serve~ in a good setting lies -with final users. diff --git a/site/cleopatra/Theme.org b/site/cleopatra/Theme.org deleted file mode 100644 index 41faa8b..0000000 --- a/site/cleopatra/Theme.org +++ /dev/null @@ -1,291 +0,0 @@ -#+BEGIN_EXPORT html -

Theming and Templating

-#+END_EXPORT - -#+BEGIN_SRC makefile :tangle theme.mk -SASS := site/style/main.sass -CSS := $(SASS:.sass=.css) - -theme-build : ${SASS} - @echo " compile ${CSS}" - @sassc --style=compressed --sass ${SASS} ${CSS} - -soupault-build : theme-build - -ARTIFACTS += ${CSS} ${SASS} -#+END_SRC - -* Main HTML Template - -#+BEGIN_SRC html :tangle templates/main.html :noweb no-export - - <> - <> - -#+END_SRC - -** ~~ - -#+NAME: head -#+BEGIN_SRC html :noweb no-export - - <> - <> - - <> - <> - -#+END_SRC - -*** Encoding - -#+NAME: encoding -#+BEGIN_SRC html - -#+END_SRC - -*** Viewport - -#+NAME: viewport -#+BEGIN_SRC html - -#+END_SRC - -*** Assets Loading - -#+NAME: syncloading_html -#+BEGIN_SRC html - - -#+END_SRC - -#+NAME: asyncloading_js -#+BEGIN_SRC js -let noscript = document.getElementById('asyncloading'); -noscript.insertAdjacentHTML('beforebegin', noscript.innerText); -noscript.parentNode.removeChild(noscript); -#+END_SRC - -#+NAME: asyncloading_html -#+BEGIN_SRC html -