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 blocks in other files, as long as those files are also compiled (into objects) and become part of the archive. For example, see module:Lilac.Types where many of the Noweb links point to blocks in other files.
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. See ti:0004-properties-drawer-not-empty for an example (or, if you are reading this document from the raw Org file, just grep for :ID:)
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 block in your doc via the top-level document UUID.
You probably don't want to type these ID values by hand. In Emacs, you can use M-x org-store-link to get the heading or document's ID (or create one automatically in the process if one doesn't exist yet).
2.6 No implicit concatenation of multiple blocks sharing the same name when tangling
Orgmode allows multiple blocks all sharing the same #+header: :noweb-ref bar metadata, where during tangling these 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 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 blocks
If you set #+header: :collapsed true for a 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 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.
4.1 Nix setup (declarative installation)
The Lilac build pipeline uses Cachix to cache the builds, so that you don't have to build from scratch (the above will still make you compile Lilac from the sources). After installing Cachix, run
cachix use funloopto get access to the cached builds (all tagged commits are cached).
And then from your project's Nix configuration, you can bring Lilac into your project's scope with:
lilacSrc = builtins.fetchGit {
url = "https://git.sr.ht/~listx/lilac";
ref = "refs/tags/<<lilac-version>>";
name = "lilac";
submodules = true;
};
lilacPkg = import "${lilacSrc}/nix/release.nix" {
lilacGitVersion = "<<lilac-version>>";
};where <<lilac-version>> is the version string vX.X.X.X you want to use. The current version is defined at Lilac version, so you should use that one.
4.1.1 Summary
Pros:
Delegate most housekeeping things to Nix, so that you really only need to bump the version string to get the latest Lilac version.
Cons:
Every time you bump the version, you have to re-download the Lilac sources.
4.2 Manual setup (imperative installation)
The instructions below are useful for developing Lilac, if you want to submit patches.
Clone this repo. There are 2 ways to install Lilac. The first is with Nix and Cachix. You can just download from the funloop Cachix cache, by running
cachix use funloop
make build-release
make install-releaseThe build-release target will end up pulling from the funloop cache (unless CI on main branch is broken).
You can also build with Cabal, by running make install to have Cabal install the lilac binary to disk. For end-users, this is not as desirable because it takes longer.
4.2.1 Summary
Pros:
Only need to download Lilac once.
More precise control of how you're building Lilac.
Cons:
More manual housekeeping. You have to use git pull to get the latest versions, and then remember to run make build-release, etc. This is not declarative at all.
4.3 Using Lilac
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 -cn 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