Lil Terminal is a command-line interface for the Lil programming language, allowing easy experimentation outside of Decker. Lilt also includes bindings for basic CLI and filesystem IO, making it potentially usable for shell scripting and other applications.
The source code for Lilt is available On GitHub.
Lilt depends upon the C standard library and some POSIX extensions. It should work on OSX or most Linux distros. To build and install Lilt, run the included make
script. By default, a binary is installed in /usr/local/bin
.
make lilt && make install
$ lilt [FILE.lil...] [-e EXPR...] if present, execute a FILE and exit -e : evaluate EXPR and exit -h : display this information
Executing a FILE
or EXPR
argument will not automatically produce any output. Use show[]
or print[]
to produce results on stdout:
$ lilt -e "show[100+range 5]" (100,101,102,103,104) $ lilt -e "print[sys.version]" 0.6
If a FILE
or EXPR
argument has not been provided, Lilt will run in interactive "REPL" mode, which can be exited with Ctrl+C or the exit[]
function.
$ lilt 2+3 5 exit[] $
For convenience, after each line is executed at the REPL, the result will be stored in a variable named _
:
1,2,3 (1,2,3) 10+_ (11,12,13) _/5 (2.2,2.4,2.6)
You can write reasonably portable shell scripts by starting a file with a "shebang" something like:
#!/usr/bin/env lilt
If an environment variable named LIL_HOME
is set, Lilt will search that directory path at startup, executing any .lil
files. These could in turn easily load datasets or other useful definitions every time you open a REPL. Startup scripts are always loaded prior to executing FILE
or EXPR
arguments.
Name | Description |
---|---|
args | List of CLI arguments to Lilt as strings. |
env | Dictionary of POSIX Environment variables. |
sys | An Interface which exposes information about the Lilt runtime. |
rtext | An Interface with routines for working with rich text. |
bits | An Interface with routines for bit-wise manipulation of numbers. |
pi | The ratio of a circle's circumference to its diameter. Roughly 3.141. |
e | Euler's number; the base of the natural logarithm. Roughly 2.718. |
colors | A dictionary of named pattern indices. |
Name | Description | Purpose |
---|---|---|
input[x] | Read a line from stdin as a string, optionally displaying x as if with print[] , without the newline. Gets 0 on EOF. | Console |
show[...x] | Print a human-comprehensible representation of the value x to stdout followed by a newline, and return x . | Console |
print[...x] | Print a string x to stdout followed by a newline. If more args are provided, format all but the first using x .(0) | Console |
error[...x] | Print a string x to stderr followed by a newline. If more args are provided, format all but the first using x .(0) | Console |
dir[x] | List the content of a directory as a table.(1) | Files |
path[x y] | Canonical path x (joined with y , if given) via realpath(). | Files |
read[x hint] | Read a file x using hint as necessary to control its interpretation.(2) | Files |
write[x y] | Write a value y to a file x . Returns 1 on success.(3) | Files |
exit[x] | Stop execution with exit code x . | System |
shell[x] | Execute string x as a shell command and block for its completion.(4) | System |
eval[x y z] | Parse and execute a string x as a Lil program, using any variable bindings in dictionary y .(5) | System |
import[x] | Execute a .lil script x in an isolated scope and return a dictionary of definitions made within that script. (6) | System |
random[x y] | Choose y random elements from x . In Lilt, sys.seed is always pre-initialized to a constant. | System |
readcsv[x y d] | Turn a RFC-4180 CSV string x into a Lil table with column spec y .(5) | Data |
writecsv[x y d] | Turn a Lil table x into a CSV string with column spec y .(5) | Data |
readxml[x] | Turn a useful subset of XML/HTML into a Lil structure.(5) | Data |
writexml[x fmt] | Turn a Lil structure x into an XML string, formatted with whitespace if fmt is truthy.(5) | Data |
readdeck[x] | Produce a deck interface from a file at path x . If no path is given, produce a new deck from scratch. | Decker |
writedeck[x y] | Serialize a deck interface y to a file at path x . Returns 1 on success.(7) | Decker |
array[x y] | Create a new array with size x and cast string y , or decode an encoded array string x . | Decker |
image[x] | Create a new image interface with size x ((width,height) ) or decode an encoded image string. | Decker |
sound[x] | Create a new sound interface with size x (sample count) or decode an encoded sound string. | Decker |
0) If print[]
or error[]
are given a single array interface as an argument, the raw bytes of that array will be sent to stdout or stderr, respectively, with no trailing newline added. In this way it is possible to print characters which do not have a valid representation as Lil strings, like Unicode block characters.
1) dir[]
of a file results in an empty table. Directory tables contain:
dir
: if an item is a directory 1
, and otherwise 0
.name
: the filename of the item.type
: the extension including a dot (like .txt
), if any, always converted to lowercase.2) read[x hint]
recognizes several types of file by extension and will interpret each appropriately:
hint
argument is the string "array"
, the file will be read as an array interface with a default cast
of u8
..gif
files are read as image interfaces (or a dictionary containing image interfaces, as noted below)..wav
files are read as sound interfaces.\r
(Carriage-Return) characters are removed, tabs become a single space, "smart-quotes" are straightened, and anything else outside the range of valid Lil characters becomes a question mark (?
).There are several possible hint
arguments to control the interpretation of colors in an image:
"color"
(or no hint): convert to Decker's 16-color palette (patterns 32-47). Read only the first frame of an animated GIF."gray"
: convert to 256 grays based on a perceptual weighting of the RGB channels. Read only the first frame of an animated GIF."frames"
: 16 colors, but read all frames of an animated GIF."gray_frames"
: 256 grays, but read all frames of an animated GIF.The "frames"
or "gray_frames"
hints will cause read[]
of a GIF to return a dictionary containing the following keys:
frames
: a list of images.delays
: a list of integers representing interframe delays in 1/100ths of a second.If an image contains transparent pixels, they will be read as pattern 0.
The WAV file format is much more complex than one might imagine. For this reason, and in order to avoid drawing in large dependencies, read[]
in Lilt accepts only a very specific subset of valid WAV files corresponding to the output of write[]
: monophonic, 8khz, with 8-bit unsigned PCM samples and no optional headers. Any other format (or an altogether invalid audio file) will be read as a sound
with a size
of 0. For reference, you can convert nearly any audio file into a compatible format using ffmpeg like so:
ffmpeg -i input.mp3 -bitexact -map_metadata -1 -ac 1 -ar 8000 -acodec pcm_u8 output.wav
3) write[]
recognizes several types of Lil value and will serialize each appropriately:
frames
(a list of image interfaces) and delays
(a list of integers representing interframe delays in 1/100ths of a second).4) shell[]
returns a dictionary containing:
exit
: the exit code of the process, as a number. If the process halted abnormally (i.e. due to a signal), this will be -1.out
: stdout of the process, as a string.5) See the Decker Manual for details of eval[]
, readcsv[]
, writecsv[]
, readxml[]
, and writexml[]
.
6) Scripts loaded with import[]
will not have access to args
or env
. Scripts may use args~0
as an idiom to detect when they have been imported as a library.
7) If the path given to writedeck[]
ends in a .html
suffix, the deck will be written as a "standalone" deck with a bundled HTML+JS runtime. Otherwise, the deck will be written as a "bare" deck, which is smaller.
The readdeck[]
and writedeck[]
functions allow Lilt to operate on Decker documents. Lilt can load, create, and manipulate multiple decks simultaneously, providing options for automated testing, data import/export, accessibility, and interacting with other technology from outside the Decker ecosystem.
Just as in Decker, you can simulate "injecting" events into widgets, cards, or the deck with the x.event[name ...args]
function they provide, running the appropriate scripts to completion and producing any appropriate side-effects on the deck. For example, clicking on the first widget on the active card:
d:readdeck["demo.deck"] (first d.card.widgets).event["click"]
v1.0:
v1.9:
rlwrap
.v1.10:
x.event[]
.v1.14:
read[]
hints for decoding the frames of animated GIF images.v1.18:
print[]
and error[]
to accept a array interfaces as arguments.v1.22:
import[]
to simplify building multi-file scripts.