# Snippets
A lean, fast, Keep It Simple Stupid, Static Site Generator platform, written with Rust.
Parsing is implemented using "String Streaming" (O(1) for loops that compute outputs using tokens in one go).
z
# What is a Static Site Generator
It's an engine that, given templates + static data, generates "ready to ship" HTML files (along with assets such as images, videos, CSS/JS).
This does not necessarily mean the generated site cannot include dynamic content (e.g., React components).
SSGs are usually used for things such as landing pages or websites with mostly informative content — the kind of sites you might use e.g. WordPress to create.

## Quick Start
- Put your source in `<src_dir>` with:
  - Templates: `.htmlt` files at the root of `<src_dir>`
  - Snippets: `<src_dir>/snippets`
  - Content: `<src_dir>/content`
  - Static assets: `<src_dir>/static`
- Run: `snippets <src_dir> <out_dir> --watch`
  - Opens a local static server on `127.0.0.1:8080` and rebuilds on changes.

## Features
- Templates + snippets with placeholders `{{...}}` and nested snippets
- Presence‑only flags with conditional blocks in snippets: `<!-- if flag --> ... <!-- else --> ... <!-- endif -->`
- Namespaces and content pointers: `content="file/sub.tree"` (last `/` splits file vs dotted subtree)
- List rendering with `is="list"` from either:
  - Snippet’s own TOML top‑level `items = [ {..}, {..} ]`
  - A `content` pointer to an array or a table (including `items`), turning table values into list items
- HTML‑escaped placeholders; multiline values render with `<br>` and paragraph wrapping
- Fast incremental rebuilds with pointer‑aware dependency tracking
- Efficient static copying (only changed files), simple local server for preview

## Install
- One‑liner (macOS/Linux):
  `curl -fsSL https://raw.githubusercontent.com/yuval-a/snippets/main/scripts/install.sh | sh`
- One‑liner (Windows PowerShell):
  `iwr https://raw.githubusercontent.com/yuval-a/snippets/main/scripts/install.ps1 -UseBasicParsing | iex`
 - Homebrew (macOS, prebuilt binary):
  `brew tap yuval-a/snippets && brew install snippets`
- Prebuilt binaries: download from GitHub Releases for your OS and place the binary on your `PATH` as `snippets` (or `snippets.exe` on Windows). Release artifacts include SHA‑256 `.sha256` files.
- Cargo (from git): `cargo install --git https://github.com/yuval-a/snippets.git`
- From source: `cargo build --release` and use `target/release/snippets`.

## Developing with Snippets
The content for your site template is saved in `.toml` files.
You can deploy your website source into a Source Control platform such as GitHub and configure triggers that run the Snippets engine to build and deploy the generated website.
You can also configure automatic builds whenever any content in the TOML files changes — creating a "GitHub as CMS" setup.
There are platforms that wrap these systems in a user‑friendly interface you can give to content creators (e.g., Decap).
When developing locally, the CLI has a `--watch` mode — it builds your website, serves it via a localhost web server, and rebuilds automatically whenever you change content or template parts.

# Folder structure
The development (template) version of your site should usually live in a `src` folder.
* The root folder is where you put your **Template Files** (.htmlt).
* `/static` - this is where you put any static assets such as images, js or css. Anything inside this folder will be copied **as-is** to your deployed website (the engine will know to check and copy only files that are changed since last time).
* `/content` - this is where you put the **content** files. .TOML files representing "name-spaced" content.
* `/snippets` - this is where you put **snippets**: .htmls files. These are essentially the "same" as 
htmlt template files - only they are always templates that are **injected** into htmlt template files.

# Content
Your content resides in `.toml` files.
## .TOML format
* Content files contain variable names and their values. e.g. `title = "Summertime Dreaming"`
* Single‑line values use `key = "value"`. Multiline values are wrapped with `"""..."""`.
* You can also define lists (equivalent to nested objects in JSON). Example (tables with dotted keys):

[djInfo]
    [djInfo.Tiago]
    title = "Tiago (Pandilla Ltd)"
    name  = "Tiago"
    image = "/img/djs/Tiago.png"
    [djInfo.Amaral]
    title = "Amaral"
    name  = "Amaral"
    image = "/img/djs/Amaral.png"

* For full information about the TOML format, see https://toml.io/en/

## Namespaces
Each file creates an accessible "namespace" with the same name as the file (minus the file extension). Each template (`.htmlt`) file automatically binds to a `.toml` file with the same name — so you can use variable names directly in placeholders. You can also explicitly reference variables from other namespaces with `namespace/key`.
To access an item in a list use the item name, e.g.: `namespace/djInfo.Tiago`
### Folder namespaces
If you create a folder inside the `content` folder - it automatically creates a new namespace with the same name as the folder. E.g.:
/head -> meta.toml, seo.toml
### globals
Since you can create namespaces by creating `.toml` files, a nice practice is to create a `globals.toml` file for commonly shared variables. Then you can access those in placeholders anywhere in your source, e.g. `{{globals/title}}`.

# Placeholders
Placeholders are parts in your templates or snippets intended to be replaced by actual data from content (`.toml`) files as part of the build. They can be used **anywhere** inside 
template (`.htmlt`) or snippets (`.htmls`) files, by putting them inside double curly brackets, e.g.:
`<title>{{globals/title}}</title>`

## Namespaces
As mentioned in the Content section — namespaces are like a "sub-category" for content. To refer to a namespace in your placeholder, write its name then follow it with `/` and the variable name.

The default namespace for each template or snippet is its filename. If you refer to variables from a `.toml` content file with the same name you don't have to explicitly use a namespace. You can explicitly reference any other namespace in your placeholders.

### Output escaping and multiline formatting
- Placeholder values are HTML‑escaped by default.
- Multiline values are normalized:
  - Single newlines become `<br>`
  - Two or more consecutive newlines split into paragraphs: each paragraph is wrapped with `<p>…</p>`

### Variable resolution order (summary)
- Qualified keys `ns/key`:
  - Load from that content file’s key if present.
  - Otherwise try dotted keys in snippet/template vars: `ns.key`, then plain `key`.
- Unqualified keys `key` in snippets:
  - First from the snippet’s base vars (from its own `.toml` or a `content="…"` pointer).
  - Then from the template’s vars (template‑matching `.toml`).
  - In list mode, the current item’s fields shadow both.

# Template files (.htmlt)
Template files sit in your source root. They can contain **any** valid HTML content — used as‑is in the built version. They can also contain:
* Placeholders
* Snippet Tags

## Snippet Tags
Snippet tags are used inside template files to inject "snippets" (`.htmls`) — pieces of HTML that reside in the `/snippets` folder.
### General Definition
`<!-- @snippet name="path/to/snippet" [is="list"] [content="file/subtree"] [flags…] -->`
### Format
The format of a snippet tag is: `<!-- @snippet <attribute="value"> or <attribute> -->`.
### Attributes
#### `name` (mandatory)
The only mandatory attribute is `name` (so a minimal snippet tag is e.g. `<!-- @snippet name="summertime-dreaming" -->`).
The `name` value tells the engine the path of the snippet file to inject, relative to the snippets directory.
### `content`
Use `content` to explicitly select a content source for the snippet instead of the default. The value format is `file/sub.tree` — the last `/` splits the content file key from an optional dotted subtree path.
### `is="list"`
This attribute renders the snippet once per item in a list. The list data comes from:
- The snippet’s own content file top‑level `items = [ {…}, {…} ]`, or
- A `content="file/sub.tree"` pointer that resolves to an array, or to a table (including a table with `items = [ … ]`), where table values become items.

Example:
`<!-- @snippet name="components/card" is="list" content="blog/posts" -->`
Renders the `components/card.htmls` snippet for each item under `content/blog.toml` at subtree `posts`.
### Conditional Flags `[flag]`
You can use any standalone attribute name (attribute without `="value"`) as a conditional flag.
Inside the snippet, you can branch on those flags (see "Conditional Content").

# Snippet Files (.htmls)
Snippet files reside in the `snippets` folder; they represent injectable content.
A snippet file can include:
* Any valid HTML
* Placeholders
* Snippet Tags
* Conditional Content

## Conditional Content
Declare "special case" content that is injected if a certain flag attribute is added to the snippet tag. (Conditional blocks are processed inside snippets.)
The syntax is:
```
 <!-- if flag --> 
 [content that should be shown only if the flag is present on the snippet tag]
  <!-- else -->
 [content that should be shown only if the flag is NOT present on the snippet tag]
  <!-- endif -->
```
If the flag is present on the directive, the first branch renders; otherwise the `else` branch (if present) renders.
The `<!-- else -->` is **optional**.

# CLI Build Engine
Run `snippets` with a source directory input (the directory where your templates, snippets, TOML content files and so on reside) and a destination directory input (where the generated site files will be saved), along with optional options.
## Options
These are the available options:
### --snippets-dir <SNIPPETS_DIR>
Override the default location of the snippets directory (default: `<src_dir>/snippets`).
### --content-dir <CONTENT_DIR>
Override the default location of the content directory (default: `<src_dir>/content`).
### --static-dir <STATIC_DIR>
Override the default location of the static directory (default: `<src_dir>/static`).
### -p, --port <PORT>
Specify a different port for the local server in watch mode (default: `8080`).
### --watch
Run in watch mode: start a local server serving the website from the destination folder, with hot reloading and incremental builds.
### -v, --verbose
Verbose logging.
### -V, --version
Show version number.
### -h, --help
Display help.

## Watch mode and rebuild behavior
- Tracks dependencies between templates, snippets, content files, and fine‑grained content pointers.
- Uses smart caching - on changes, only affected templates rebuild
- Static assets are mirrored to the output directory and only recopied when they change (by size/mtime).
