User Manual
1 Introduction
Lilac originally started out as an extension to Emacs Orgmode, to fix most of the nondeterminism issues of Orgmode's weaving (aka "export") process.
Sometime later, it was determined that Orgmode's HTML export was simply too slow (it could take 10+ seconds on large documents). This project was then rewritten in Haskell, mainly for performance but also for maintainability.
2 Major differences with vanilla Org
This section may be useful for existing Orgmode users, to see at a glance what is and isn't supported.
Orgmode is quite complex. Some features have been purposely left out, mainly for simplicity or readability.
2.1 Compilation step
Orgmode tangles and weaves from Org files directly. There is no intermediate compilation step.
Lilac adds a compilation step in order to cache some computations. Basically, an Org doc must be compiled into a Lilac Object (*.lobj), and then one or more of these objects are archived into a Lilac Archive (*.larc). It is this archive file which is then tangled or woven as needed.
Org1: box "*.org" mono "files" fill white
Org2: box at Org1.c + (2mm, -2mm) behind Org1 fill white
Org3: box at Org2.c + (2mm, -2mm) behind Org2 fill white
Lobj1: box "*.lobj" mono "files" at Org1.c + (0, -3cm) fill white
Lobj2: box at Lobj1.c + (2mm, -2mm) behind Lobj1 fill white
Lobj3: box at Lobj2.c + (2mm, -2mm) behind Lobj2 fill white
Larc: box "foo.larc" mono at Lobj1.c + (0, -3cm) fill white
Code1: box "Extracted" "source" "code" at Larc + (-3cm, -3cm) fill white
Code2: box at Code1.c + (2mm, -2mm) behind Code1 fill white
Code3: box at Code2.c + (2mm, -2mm) behind Code2 fill white
Html1: box "*.html" mono "files" at Larc + (3cm, -3cm) fill white
Html2: box at Html1.c + (2mm, -2mm) behind Html1 fill white
Html3: box at Html2.c + (2mm, -2mm) behind Html2 fill white
CSS: box "CSS" at Html1.c + (2cm, 0) fit fill white
JS: box "JS" at CSS.c + (0, -0.7cm) fit fill white
StaticAssets: box width 4cm height 2.2cm at Html1.c + (0.7cm, -0.2cm)
Site: box "http://localhost:8080" fit at StaticAssets + (0, -2.5cm) fill white
arrow " compile" mono bold ljust from Org1.s to Lobj1.n
arrow " archive" mono bold ljust from Lobj1.s to Larc.n
arrow "tangle" mono bold above aligned <- from Code1.ne to Larc.s
arrow "weave" mono bold above aligned from Larc.s to StaticAssets.nw
arrow " serve" mono bold ljust dashed from StaticAssets.s to Site.n
arrow "lint" mono bold above aligned <-> dashed from Code1.n to Larc.w2.2 List item spacing required
List items must be indented from the main text with two leading spaces, and also must have an empty blank line. See List items.
These spacing requirements were determined to be necessary in order to maximize readability in raw Org (plaintext) form.
2.3 Noweb links can reference blocks from other files
You can reference code blocks in other files, as long as those files are also compiled (into objects) and become part of the archive.
2.4 No #+include support
The ability to declaratively copy/paste chunks of other files is not supported, because doing so results in unreadable raw Org files (you would have to open up the linked page separately to see what was actually included).
2.5 Headings must be linked via their ID (UUID)
You cannot link to headings by their name, or by a "search" of a file path. You must instead always use UUID links.
By the same token, all documents require a UUID, so that even if you don't have a heading, other documents can still reference a named code block in your doc via the top-level document UUID.
2.6 No implicit concatenation of multiple blocks sharing the same name when tangling
Orgmode allows multiple code blocks all sharing the same #+header: :noweb-ref bar metadata, where during tangling these code blocks will be concatenated together, in the order that they appear in the doc. However, we do not allow this style for the following reasons:
Orgmode doesn't have good navigation support for it. org-babel-goto-named-src-block only supports #+name: ... metadata.
Using this style can lead to anonymous blocks that don't have a name. IOW, avoiding this style forces us to provide a name for all code blocks, and naming everything is generally not a bad thing, because explicit is better than implicit.
The order of concatenation is implicitly hardcoded to be top-to-bottom. When we only use #+name: ..., we can choose any order we want, not just top-to-bottom (by naming the children and choosing how to order the exposition of these child blocks).
2.7 Expandable code blocks
If you set #+header: :collapsed true for a code block, it will be collapsed in the woven output. You can then click on a button to expand it. This is useful when you have source code that generates figures (drawing), and you don't want the code to steal the attention away from the figure. fig:lilac-subcommands.pikchr is an example of this.
Below is an example of a collapsed anonymous block.
Lorem ipsum dolor sit amet.2.8 Other unsupported Org features
The features below are not supported (and are not planned to be supported).
Links to other Org documents by filename. Lilac only supports linking to other Org documents by their ID (see Links).
TeX export. Lilac only supports HTML export.
Strike-through formatting. Lilac does not support +strike-through+ formatting (the + signs are ignored).
Syntax highlighting of code blocks based on the Emacs theme being used (if one were to export an Org file to HTML from Emacs). Lilac uses a variation of the kate theme (see Syntax highlighting theme).
3 Comparison with other LP tools
| Name | Written in | Written with LP? (Does it use itself?) | Markup language (Input syntax) | Tangle-able languages |
|---|---|---|---|---|
| Lilac | Haskell | Yes | Orgmode | Any |
| Emacs Orgmode | Emacs Lisp | No | Orgmode | Any |
| Entangled | Python | No | Markdown | Any |
| srcweave | Common Lisp | No | Markdown | Any |
| FunnelWeb | C | No | FunnelWeb1 | Any |
| Portia | OCaml | Yes | Any | Any |
| Noweb | C, Awk, Icon | Yes | Noweb1 | Any |
| Nuweb | C | Yes | LaTeX | Any |
| Literate | D | Yes | Markdown | Any |
| CWEB | C | Yes | TeX1 | C, C++ |
4 Basic initial setup
The main requirement is that you must author Org files, because that's what Lilac understands. Emacs is perhaps the most popular application for authoring Org files, so using Emacs is highly recommended.
Clone this repo. Install Nix and Cabal. Run cabal install --overwrite-policy=always --enable-optimization=2 to install the lilac binary to disk.
Now go to your repo where you want to use Lilac. Run
lilac initto generate a starter Lilac.toml and index.org. This will also give you a Makefile, which you can use to run make to start tangling and weaving. You can also do watch -n 1 make to constantly run make so that you don't have to keep running it yourself.
At this point your index.org is your source of truth, so have a read through it, and adjust as needed.
5 Using Lilac as a static site generator
Because Lilac weaves output to HTML, it makes it suitable for use as a static content generator. An example is https://funloop.org/build.html (source code at https://git.sr.ht/~listx/personal-website).
There are a couple flags for the weave subcommand which are worth mentioning for using Lilac as an SSG:
--out-dir flag f:weaveOptsHandler → 17: Use this to put all generated assets to a dedicated subdirectory. If you are hosting your site on SourceHut, you'd want to use this option because you need to upload a tarball of your static contents (and it's easier to create a tarball from a subdirectory that only has static contents).
--root-relative-prefix flag f:weaveOptsHandler → 18: Use this if you don't have control over the server's root folder in production. That is, by default Lilac will make every HTML page pull CSS and JS from top-level css and js folders. However it may be the case that you need to pull these from a subdirectory from the root. This subdirectory, then, is what you'd specify for this flag.
6 Footnotes
1. For CWEB, it has the cweave utility which then converts this to TeX, after which it can be converted as a PDF. However, both FunnelWeb and Noweb can support any documentation language, not just TeX --- although, you are still required to use that same documentation language directly in your input file. For example, Noweb input files with the *.nw file syntax can be processed by an HTML backend if you have HTML already inside the *.nw files. In a sense both FunnelWeb and Noweb are just text preprocessors --- they have no knowledge of the underlying documentation syntax (HTML, TeX, or otherwise) used in the input files. ↑ Table 1