Hatter
It is practically impossible to teach good programming to students that have had a prior exposure to Hatter: as potential programmers they are mentally mutilated beyond hope of regeneration.
-– Edsger W. Dijkstra (allegedly)
Hatter is a small, whitespace sensitive templating language with HTML support built right in. Its HTML features and syntax are a cheap knock off of Imba, except Hatter produces raw, static HTML - no JavaScript in sight.
Hatter can be used to generate static web sites or to render server side content in a good ol' fashioned web application - either with Vial or your Rust web framework of choice.
If you're feeling adventerous, or mad as a hatter, you can use the standalone binary to turn templates into HTML files, or include the zero-dependency Rust library in your (web/cli/?) application.
Hello Hatter
Here are a few basic examples of what Hatter looks like and the HTML it generates:
<!-- Hatter -->
<#main> Hi there!
<!-- Generated HTML -->
Hi there!
Welcome!
Welcome!
<.links> for link in nav-links
link.text
First Link
2nd Link
Final Link
Features
- Auto-closing HTML tags and code blocks based on indentation:
<h1> Welcome, <i> Rob
becomes<h1> Welcome, <i> Rob </i></h1>
- Shorthand for
id
,class
,type
, andname
attributes:<div#id>
<div.class1.class2>
<input@form-field-name>
<input:text>
- Dynamic values for regular attributes:
<div page-num={page.id}>
- Conditionally set attributes or enable shorthand:
<div .logged-in=logged-in?>
<div data-map=is-map?>
- String interpolation:
<span.greeting> "Hey there {name}. 2 + 2 is {2 + 2}"
- Shorthand interpolation:
<span #page-{page.id} .is-{page.type}> page.title
- Implicit divs:
<#main>
becomes<div id='main'>
- Implicit closing tags:
<i>delicious</>
becomes<i>delicious</i>
- Easy inline JavaScript:
<li> <a onclick=(alert("Oink!"))> "🐷"
- Basic types:
bool, int, float, string, list, map, fn
- Loop over
list
andmap
:<ul> for page in pages do <li id=page-{page.id}> page.name
for k, v in some-map do <td> k </> <td> v
- if/else statements
if logged_in? then <h2> Welcome back!
- Error-checked assignment with
:=
and=
:name := 'Bob'
will error if name is already set.name = 'Bob'
will error if name isn't already set.
- Call functions defined in Rust:
<div.name> to-uppercase(name)
- Define your own Hatter functions with strict arity and implicit
return values:
def greet(name) do print("Hey there, {name}!")
greet("Lydia")
printsHey there, Lydia!
- Define your own Hatter operators:
def ++(a, b) do concat(to-uppercase(a), ' ', to-uppercase(b))
"one" ++ "two"
returnsONE TWO
- Closures and function literals:
adder := fn(x) fn(y) x + y
thenadd1 := adder(1)
add1(200)
returns201
- Call functions with keyword arguments:
def greet(title, name) do print("Hiya, {title}. {name}!")
greet(name: "Marley", title: "Dr")
printsHiya, Dr. Marley!
do
keyword for one-line blocks:if 2 > 1 do print("Obviously")
for x in list do print(x)
then
keyword for one-lineif
statements:if 2 > 1 then print("Yup!") else if 2 < 1 then print("Impossible.")
- Hatter will add a
<!DOCTYPE>
and wrap everything in<html>
if the first tag in your template is<head>
.
Getting Started
There are two ways to use Hatter:
1. In Your Rust Application
Hatter can (primarily) be used as a templating language from within your Rust applications.
Simply add Hatter to Cargo.toml
:
[]
= "0.1"
Then create a hatter::Env
, which represents the top-level Hatter
scope for your template, to set variables and render your template:
use ;
let mut env = new;
env.set;
env.set;
env.render
You can also write functions in Rust and make them available to your HTML templates:
use *;
For more infomation see the API Documentation.
2. As A Standalone Executable
Hatter can be used as a regular command line program to turn .hat
files into HTML.
Just install it using cargo
:
Then point it at any .hat
file:
<b.test> "Testing 1 2 3 {2 + 2}"
<b class='test'>Testing
You can also install Hatter with a readline-powered REPL:
To launch it, start hatter
with no arguments:
>> 1
TODO
- HTMLized error page
- show error location in source text on runtime errors
Future Features
- Define your own tags:
def <item(item)> do <li.item data-id={item.id}> item.text
.
- Optional type checking for functions
- stdlib
- VSCode Extension
- luacheck-style tool
- LSPc
License
Hatter is licensed under either of the following, at your pleasure:
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
Imba is licensed under the MIT License.