Sitix is a KISS program, so there's not a lot of setup. Once you've got it installed (see
for information on that),
you need a project to build. The simplest Sitix project structure is just a
site
folder, which contains the actual Sitix "scripts". When
(you absolutely must be outside of the site directory to do this!) you run
sitix site
, Sitix will delete the
output
directory
and all contents, if it exists, and then create a new
output
directory for the compiled site code. Then, Sitix will walk down the tree of
your
site
directory, creating appropriate subdirectories and directly copying over any file that doesn't have an opening phrase -
[!]
,
for a Sitix page, or
[?]
for a data page (which will not be rendered itself, but may be used for templating or configuration). The opening phrase
MUST be the first three bytes of the file; if there are any whitespaces before it, the file will be treated as plain data. If you want
it to render to a different directory, pass the
-o location
flag.
Configuration can be managed with the
-c
command line directive, which directly inserts a Sitix object to the virtual root scope. For instance,
this site uses the
-c production
argument to enable the production endpoint as opposed to the local development endpoint. It could also be
something like
-c endpoint https://swaous.asuscomm.com/sitix
, directly inserting the endpoint.
Let's cover some syntax. All Sitix commands are enclosed in brackets like
[command]
(you can escape brackets with backslashes). There aren't very many
Sitix commands; at the moment, it's just:
[=variableName variableContent]
: This simply sets variableName
to be equal to variableContent
at that point on the scope tree.
[=variablename-]variableContent[/]
: The expanded form of above. This allows for much more complicated variables, including variables containing
Sitix commands (in the compressed form, anything inside MUST be plaintext). It's generally preferred to use this when the content is more than a word or two.
[^variableName]
: "Dereferences" a variable, forcing it to render. If that variable contains other variables (like [=parent-] [=child-] content [/] [/]
),
the child variables will NOT be rendered, but if variables with the same name as the children exist at some point in the parent tree of the dereferenced variable exist, they will be replaced.
Variables at the dereferencing position will NOT be replaced.
[#filename]
: Dereferences a Sitix file (or plain file, which would just copy over content without processing it) at this position. The filename must be relative
to the root directory (usually the site
directory), rather than the directory the including file is stored in. This is very useful for templating.
[i <...>]main section[e]else section[/]
: This is an if condition. The content of the condition is an Evals directive. If it's truthy, the main section of the
if statement will be rendered. If it's not truthy, the else section will be rendered. You can put whatever you want in either section. For more information on Evals, see below.
[f array iterator]
: For loop that iterates over an array (note: in Sitix, every subdirectory of the root dir can be treated as
an array of objects, each object being a file! This allows things like generating blog links). The iterator
variable will be, for every item,
the referenced array element. Note: When iterating over a directory, every file will be given a filename
property! This can be used like
[f directory i][^i.filename][/]
, which would spew out the filenames of every file in that directory.
[@command option]
: Set a file-specific flag. File-specific flags are used to do things like minify text. For example, the minifier is controlled by
[@on minify]
, which enables minifier for the file, and [@off minify]
, which disables minifier. Minifier simply reduces chains of whitespace
to a single whitespace. [@on markdown]
and [@off markdown]
allow Markdown-like processing across the file. Sitix Markdown is not quite ready
for widespread use, yet, but at the time of writing supports *italic*, **bold**, __underline__, ~~strikethrough~~, `code`, and automatic paragraphs/line breaks.
It works quite nicely with minifier, yes.
[>filename]object[/]
: Renders an object into a new file represented by filename. Filename should be a relative path as it will be transmuted into
the output directory. This is very useful for, say, turning a single Sitix object file containing webcomic post data into a directory full of posts.
[~object1 object2]
: Sets the ghost on object1 to object2, effectively cloning object2 to object1. It is not a true copy; changes in object2 will be
reflected in object1. However, unlike with normal dereference-setting ([=object1][^object2][/]
), you can access nested objects inside the ghost.
It's not unlike changing the value of a pointer in C.
You can use Sitix commands in any file with a Sitix opening phrase; Sitix commands in files that do not have an opening phrase will be ignored.
There are a number of "special objects" that resolve magically at different places. The most useful two are
__after__
and
__before__
,
which crop up in for loops. They allow you to reference the object that came before or after, like
[^i.__after__]
. __this__ is pretty much useless
except in
very niche situations, because of the unclear rules behind it; I will document those on a later date. __file__ is always the root object of the current file,
- you can most likely guess why that's useful.
Evals is a very simple stack-based language meant for evaluating string statements. When data is entered in the Evals program, it's immediately pushed
to the stack (like
"hello"
,
3.14
,
true
, or
some.sitix.variable
). At the end of Evals rendering, whatever is left on the stack
is considered the result (if there is more than one thing on the stack, Evals will give you a Bad Syntax error and return an ErrorObject). To manipulate data,
there are a number of commands that work on the top of the stack:
equals
: Checks if two values on the stack are equal to each other. It will remove both values from the stack and add a boolean value as the result.
not
: Pops the top value off the stack and replaces it with a boolean equal to the opposite of the truthyness of that object. "Hello World" not
would just be false
, for instance.
concat
: Stringifies the top two items on stack and concatenates them together in order.
strip_fname
: Cuts off the directories and the file extension of a file, going from "test/home/base.py.out" to "base.py", for instance.
copy
: Copy the top thing on stack.
count_back
: Pops the top two items off stack and searches for the first occurring index of the smaller string in the larger string. Don't get it? Read the code.
slice_left
: Pops the top two items off stack and, assuming one is a number, stringifies the other one and slices from the start of that to the index
represented by the number. This discards the character at the index, so "hello,world" 5 slice_left
returns just "hello".
slice_right
: Same behavior as slice_left, except it slices the "right" side, so "hello,world" 5 slice_left
would return "world".
filenameify
: Reduce it to a lowercased POSIX-compliant filename including only a-z, 0-9, ., _, and -. It will also shorten at points where two - would be
in sequence, for pretty-printing reasons.
trim
: Trim off whitespace around a string (note: this will render Sitix objects).
Truthyness in Evals is not dissimilar to JavaScript. Empty strings are falsey, and all other strings are truthy; 0 is falsey and all other numbers are truthy, and booleans are truthy or falsey based on their value.
Sitix variables are considered truthy if the lookup is successful, and falsey otherwise; this allows for a replacement to the old
[i exists]
and
[i config]
,
like
[i conf/prod]
would check if the
conf/prod
variable exists in scope (which could be set by
-c conf/prod
, for instance).
Evals will render Sitix variables as strings to run comparisons on them. This means you must be careful - if rendering that object would change a variable you don't want changed, for instance,
you'll end up with some very odd behavior. Rendering objects to strings is also dangerous because of the sheer size of some Sitix objects - you can store many gigabytes of data safely in
a PlainText object, which would be forced into main memory by an Evals comparison (Evals will not render Sitix objects unless they're used in a comparison with a string; comparing
two Sitix objects is safe). Be careful.
And that's it! To see how these are used creatively in the wild, check out
the source code for this website.
For a more thorough look at Sitix, check out
the source code. There's a rather large comment at the start of
main.cpp
that provides a deep look at Sitix syntax and usage.