Cheatsheet
The whole authoring language on one page.
Everything you write, on one page. Pages and templating has the rules behind each line.
Commands
crisptastic init my-site # create a site
crisptastic dev # serve it on 127.0.0.1:6174 and reload on save
crisptastic check . # compile everything; use this in CI
crisptastic routes . # list every route
crisptastic deploy # build the signed, encrypted Capsule
Run them inside the site's folder: crisptastic.toml is read from the current
directory. The command line reference has every option.
Files become URLs
| File | URL |
|---|---|
index.html.crisp | / |
about.html.crisp | /about |
contact/index.html.crisp | /contact |
blog/[slug].html.crisp | /blog/:slug, read request.route.params.slug |
api/data.json.crisp | /api/data.json |
sitemap.xml.crisp | /sitemap.xml |
_partials/_nav.html.crisp | never served; the file name starts with _ |
404.html.crisp | error page, top level only (also 400, 500, error) |
assets/style.scss | /style.css, compiled |
assets/logo.svg | /logo.svg, no /assets/ in the URL |
Printing
{{ user.name }} escaped; a dotted path or a pipe only
{{= 1 + 2 }} escaped; any expression
{{~ post.html }} raw; only for what you trust
{{-- a comment --}} prints nothing
A missing path is null and prints nothing. Indexing null is an error.
Expressions
| Kind | Write |
|---|---|
| Equal, not equal | a = b, a != b. == is an error |
| Compare | <, <=, >, >= |
| Logic | and, or, not, ! |
| Maths and joining | + - * /. + joins when either side is a string |
| Index | items[0], a["key"]. items[0].title is an error, so write items[0]["title"] |
| Pipe | name | trim | upper is upper(trim(name)) |
Strings use double quotes only. Falsy values are null, false, 0, "",
[] and {}. Query and form values are always strings, so use num(...).
Functions
upper lower trim len contains starts_with ends_with json str
num bool exists empty merge form_urlencode sda asset
secure_token. You can't define your own in a page.
Control flow
@if (user) {
<p>Hello, {{ user.name }}</p>
} @else {
<p><a href="/login">Sign in</a></p>
}
@for (post in posts) {
<li>{{ post.title }}</li>
}
@for ((key, value) in settings) {
<dt>{{ key }}</dt><dd>{{ value }}</dd>
}
@switch (order.status) {
@case ("paid") { <b>Paid</b> }
@default { <b>Unknown</b> }
}
@let title = "About"
@include("_partials/_head.html.crisp")
There is no else if and no loop index. @include takes a quoted path relative
to the file, and the partial shares the page's scope.
What a page can read
| Path | Holds |
|---|---|
request.method, request.path | The request line |
request.query.x | Query string |
request.body.x | Submitted form or JSON |
request.cookies.x | Cookies |
request.route.params.x | Dynamic segments |
context.session.x | The visitor's session |
context.csrf.token | Goes in a hidden _csrf field on every form |
context.env.x | [env] values, in dev, run and serve only |
Effects
They apply after the page finishes, and not at all if it fails.
@status 404
@redirect "/dashboard"
@cookie theme = "dark"
@cookie theme delete
@session cart = 3
@session cart delete
Redirects are always 303. Cookies have no options. A host refuses session and
cookie changes during a GET, so write them in the POST branch.
Fetching and shaping
@fetch post = get_json("https://api.example.com/posts/1")
@if (post.ok) {
<h1>{{ post.value.title }}</h1>
} @else {
@status 502
<p>The API is having a moment.</p>
}
A failed fetch doesn't throw, so always check .ok. Reshape data with @shape
or sda(...); Fetching and shaping data
has the query language.
Declaring a route
[routes."/f/subscribe"]
methods = ["POST"]
body = "form"
max_body_bytes = 4096
rate = [{ per = "client", limit = 10, window = "1m" }]
The host answers a request that breaks this before your page runs. See
[routes].
Line-directive traps
- Put
@status,@session,@cookie,@fetch,@call,@shapeand@leton their own lines. They swallow a}on the same line. }closes the innermost block, even in text. Print a literal one with}.@header,@cacheand@telemetrydon't exist. They print as text.@include(is found by plain text search, even in comments.