General-Purpose Templating Utility
λtext turns text files into higher-order functions, featuring a Hindley-Milner / prenex polymorphic type system. See the github.io page.
Each release has
ready-made builds. Every asset name includes the version, shown as VERSION
below.
| Platform | Download |
|---|---|
| Debian, Ubuntu | ltext_VERSION-1_amd64.deb / _arm64.deb: sudo apt install ./ltext_*.deb |
| Fedora, RHEL, openSUSE | ltext-VERSION-1.x86_64.rpm / .aarch64.rpm: sudo dnf install ./ltext-*.rpm |
| Any Linux (static binary) | ltext-VERSION-x86_64-unknown-linux-musl.tar.gz / aarch64-… |
| macOS (Apple silicon, Intel) | ltext-VERSION-aarch64-apple-darwin.tar.gz / x86_64-… |
| Windows (x64, ARM64) | ltext-VERSION-x86_64-pc-windows-msvc.exe or .zip / aarch64-… |
Unpack an archive and put ltext somewhere on your PATH. SHA256SUMS
lists the checksum of every asset. macOS may quarantine a downloaded binary;
xattr -d com.apple.quarantine ltext clears that.
With Homebrew (macOS, Linux): brew install ltext/tap/ltext.
With Cargo: cargo install ltext builds it from crates.io;
cargo binstall ltext fetches the prebuilt binary instead.
As a container (~1 MB, amd64 and arm64): docker run --rm -v "$PWD:/work" ghcr.io/ltext/ltext 'greet name',
or copy it into your own image with COPY --from=ghcr.io/ltext/ltext /usr/local/bin/ltext /usr/local/bin/.
With Nix: nix run github:ltext/ltext -- --help, or nix profile add github:ltext/ltext.
On Arch Linux, from the AUR: ltext (builds from source) or
ltext-bin (prebuilt), e.g. yay -S ltext-bin.
ltext --version prints the release version, e.g. ltext 0.2.0. A build of
an untagged commit prints the git describe form instead, e.g.
ltext 0.2.0-3-g1a2b3c4: 3 commits after 0.2.0, at commit 1a2b3c4.
λtext is written in Rust (1.85 or newer).
$> git clone https://github.com/ltext/ltext
$> cd ltext
$> cargo install --path .With flakes enabled:
$> nix build # binary at ./result/bin/ltext
$> nix run . -- --help
$> nix develop # shell with cargo, clippy, rustfmt and rust-analyzerWithout flakes, nix-build builds the executable from your <nixpkgs> channel.
$> cargo test # unit and property tests
$> cargo build --release
$> golden/run.sh target/release/ltext # CLI golden testsSee golden/README.md for the golden test corpus.
$> ltext -h
λtext - parameterized file evaluator
Usage: ltext [OPTIONS] <EXPRESSION>
Arguments:
<EXPRESSION> Expression to evaluate, e.g. `greet name` or `\x -> wrap x`
Options:
-t, --type Print the type of EXPRESSION instead of evaluating it
-v, --verbose Report what ltext is doing on stderr
-r, --raw <FILE> Treat FILE as plain text, even if its first line looks like a header
--left <LEFT> Left delimiter for rendering a partially applied result
--right <RIGHT> Right delimiter for rendering a partially applied result
-h, --help Print help (see more with '--help')
-V, --version Print version
$> ltext --type "\a -> a"
a0 -> a0For example, given a file greet:
{{ name }}
Hello,
{{ name }}
!
and a file name containing World, ltext "greet name" prints:
Hello,
World
!
Applying fewer arguments than a template takes leaves a template.
--left and --right give the delimiters to render it with:
$> ltext --left '<<' --right '>>' "\n -> greet n"
<< n >>
Hello,
<< n >>
!From λtext's point of view, any text file can be a template (given that
it's utf-8 encoded). Just declare parameters in the first line of
your files (usually in a different syntax than the file's native tongue,
via comments or obscure delimiters), then use those variables somewhere in
the content. With the ltext command you can then apply the function-y
files to each other.
There will be two primary uses of the ltext command - evaluating template
expressions, and querying for the type signature of a template/expression.
Just like the :t command in GHCi, you can find out the type of a template or
expression with -t.
All files have closed scope, meaning they only have access to the variables declared in the file. For instance:
{{ foo }}
...
Will only have access to the variable foo, while using the delimiters {{
and }} to escape your expression.
When we use a parameter in a file, we need it to be easily recognized by a parser; a different syntax than to the language you're working with.
The first line in a file will be parsed to see if it qualifies as a
lambda header. If you don't want a file have recognized arity, just invoke ltext
with the --raw argument listing the file:
$> ltext "foo bar" --raw "bar"All credits go to Martin Grabmueller's AlgorithmW package for the type inference algorithm used in λtext.
