SSGen
A [S]tatic [S]ite [Gen]erator written in Rust

Witty one-liner goes here

Why?

SSGen is a powerful static site generator that provides a flexible tool-set for any type of (static) webpage. It is intended for those looking for highly granular control over their websites.

Pros

  • Ultra-fast generation from source
  • Flexible and granular
  • (Actually) human-readable
  • Based in YAML

Cons

  • Not suitable for dynamic websites
  • Barely abstracted from HTML
  • Based in YAML

The Basics

SSGen aims to be as simple as possible.

Page files are written in YAML, with the .page extension. Each Page file gets converted into exactly one HTML file. This short tutorial assumes you have a basic understanding of YAML.

If you are familiar with YAML, you are familiar with SSGen and Pages.

Simple Demonstration

Take a look at the following example for how YAML gets converted into a Page

input_directory/index.page
# This is a comment html: body: h1: Title p: Paragraph contents

output_directory/index.html
<html> <body> <h1>Title</h1> <p>Paragraph Contents</p> </body> </html>

It really couldn't be simpler!

Tag Metadata

It is pretty important to be able to style your webpage. SSGen allows specifying arbitrary tag metadata through use of underscores.

Metadata can be specified in HTML Tags like so:

input_directory/index.page
html: body: _class: someclass _style: 'margin: 5%'; h1: Title p: Paragraph contents

output_directory/index.html
<html> <body class="someclass" style="margin: 5%;"> <h1>Title</h1> <p>Paragraph Contents</p> </body> </html>

No input validation is performed by SSGen for any tag metadata. This means you can define and use any custom tag metadata, albeit to limited functionality.

Variables and !DEF

SSGen allows simple variable declaration and substitution. Define a variable using the !DEF directive, and use it with brace substitution.

Variables in SSGen are scoped, meaning that they only exist in the node they are defined in. Children inherit the variables of their parents. If a variable is declared with the same name as another, the most recently declared variable will be used. Once the scope is left and the newer declaration is released, the older declaration will become the current value.

In other words: Variables work like they do in most programming languages. You will find using them very intuitive.


Define and use a variable like so

input_directory/index.page
# Syntax: !DEF [name, value] !DEF [content, "Paragraph contents"] html: body: h1: Title # Substitute variables into text using {variable_name} p: '{content}'

output_directory/index.html
<html> <body> <h1>Title</h1> <p>Paragraph Contents</p> </body> </html>

If starting a string off with a variable substitution, the string should be single or double quoted.

Braces can be escaped by using a backslash: p: "\{escaped}" becomes <p>{escaped}</p>

!INCLUDE other files

SSGen allows you to directly paste the contents of other files wherever you want. This is useful for breaking down large pages into smaller chunks, or for creating templates.

Since included files inherit the variables of their parent, you can also declare variables outside of a file, and use them inside the included file. You can see how this is done in practise by viewing the source code for this website

Files can be included like so:

(Assuming the contents of sample.block is p: Paragraph content)

input_directory/index.page
# Syntax: !INCLUDE path/to/file html: body: - h1: Title - !INCLUDE "include/sample.block" - !INCLUDE_RAW "/include/sample.block"

output_directory/index.html
<html> <body> <h1>Title</h1> <p>Paragraph Contents</p> p: Paragraph Content </body> </html>

Ensure that any provided path is not only an actual path to a file, but that the file does not exist outside of the source directory, and will not create an infinite loop of inclusion.

Looping with !FOREACH

Simple looping can be done using the !FOREACH directive. This is useful for managing complexity.

Create loops like so:

input_directory/index.page
# Syntax: !FOREACH [ # [x, y, (...), n], # "{x} {y} (...) {n}", # [xval1, yval1, (...), nval1], # [xval2, yval2, (...), nval2], # (...), # ] html: body: - h1: Title - !FOREACH [ [x], '<p>{x}</p>' ['Content A'], ['Content B'], ]

output_directory/index.html
<html> <body> <h1>Title</h1> <p>Content A</p> <p>Content B</p> </body> </html>

Obviously, this isn't that useful on its own, but all SSGen features can be used with eachother, allowing for !FOREACH to be at the heart of your templates.

Conditionals using !IF

SSGen allows evaluating conditional statements to choose whether to include something, or to not. Currently, no arithmetic can be performed, therefore the !IF statement only evaluates if the input is blank or not.

Conditionals can be used like so:

input_directory/index.page
# Syntax: !IF ['string', 'exec if true', '?exec if false'] # Where "?exec" is optional html: body: - !DEF ["var", "notempty"] - h1: Title - p: !IF ["{var}", "Paragraph contents"] - p: !IF ["{undeclared_var}", "True", "False"];

output_directory/index.html
<html> <body> <h1>Title</h1> <p>Paragraph Contents</p> <p>False</p> </body> </html>

As a reminder, SSGen only checks if the first entry in the !IF statement is blank or not. You cannot do arithmetic currently.

Special file: META.yaml

META.yaml is an optional file that exists (or doesn't) in the root of your source directory. It is evaluated like any other .page file, but exists as the parent to any non-included .page file.

It is also guaranteed to only be evaluated once, and as such is most suited for the !COPY directive. The !COPY !COPY_DIR directives are useful to copy assets from the source directory to the output directory.

input_directory/META.yaml
# Define some global variables - !DEF [GLOBAL, some_value] - !DEF [ANOTHER_GLOBAL, some_other_value] # Copy some files to the same location in the output directory # Syntax: !COPY[_DIR] "file_to_copy" - !COPY "somefile.txt" - !COPY_DIR "somedir/"

This file is incredibly useful, and you can view a full example of it in action in the source to this webpage

String Manipulation

SSGen has helpful directives for manipulating strings

The !SUBSTRING directive takes a substring (duh). The first two arguments are the bounds, and the third argument is the YAML that gets parsed before being cut.

input_directory/index.page
# This is a comment html: body: h1: Title p: !SUBSTRING [0, 4, Paragraph Contents]

output_directory/index.html
<html> <body> <h1>Title</h1> <p>Para</p> </body> </html>

Pretty fundamental stuff!

Advanced

SSGen has advanced features that must be explicitly enabled

The !SHELL_CMD directive executes a shell command, and is enabled with the --enable-shell flag. The output is taken from stdout and is pasted unparsed into the document.

input_directory/index.page
html: body: h1: Title p: !SHELL_CMD [echo, Hello, Echo]

output_directory/index.html
<html> <body> <h1>Title</h1> <p>Hello Echo</p> </body> </html>

Enable and use these features at your own risk!

Well technically the whole program is run at your own risk...