{"id":33938487,"url":"https://github.com/xvxx/hatter","last_synced_at":"2026-03-17T22:05:07.869Z","repository":{"id":54825405,"uuid":"292396717","full_name":"xvxx/hatter","owner":"xvxx","description":"🎩 positively mad html templating language for rust","archived":false,"fork":false,"pushed_at":"2026-02-25T23:23:31.000Z","size":1411,"stargazers_count":13,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-02-26T01:42:05.071Z","etag":null,"topics":["hatter","html","templating-language"],"latest_commit_sha":null,"homepage":"https://hatter.rs","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xvxx.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-09-02T21:17:53.000Z","updated_at":"2026-02-25T23:23:35.000Z","dependencies_parsed_at":"2022-08-14T04:00:45.545Z","dependency_job_id":null,"html_url":"https://github.com/xvxx/hatter","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/xvxx/hatter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvxx%2Fhatter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvxx%2Fhatter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvxx%2Fhatter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvxx%2Fhatter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xvxx","download_url":"https://codeload.github.com/xvxx/hatter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvxx%2Fhatter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30633240,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-17T17:32:55.572Z","status":"ssl_error","status_checked_at":"2026-03-17T17:32:38.732Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hatter","html","templating-language"],"created_at":"2025-12-12T15:01:50.585Z","updated_at":"2026-03-17T22:05:07.865Z","avatar_url":"https://github.com/xvxx.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hatter\n\n\u003cimg src=\"./img/rhetoric.jpg\" align=\"right\" width=\"350\" alt=\"The Mad Hatter discussing Hatter\" /\u003e\n\n\u003e It is practically impossible to teach good programming to students\n\u003e that have had a prior exposure to _Hatter_: as potential programmers\n\u003e they are mentally mutilated beyond hope of regeneration.\n\u003e\n\u003e -– Edsger W. Dijkstra (allegedly)\n\nHatter is a small, whitespace sensitive templating language with HTML\nsupport built right in. Its HTML features and syntax are a cheap\nknock off of [Imba], except Hatter produces raw, static HTML - no\nJavaScript in sight.\n\nHatter can be used to generate static web sites or to render server\nside content in a good ol' fashioned web application - either with\n[Vial] or your Rust web framework of choice.\n\nIf you're feeling adventerous, or mad as a hatter, you can use the\nstandalone binary to turn templates into HTML files, or include the\nzero-dependency Rust library in your (web/cli/?) application.\n\n---\n\n## Hello Hatter\n\nHere are a few basic examples of what Hatter looks like and the HTML\nit generates:\n\n```html\n\u003c!-- Hatter --\u003e\n\u003c#main\u003e Hi there!\n\n\u003c!-- Generated HTML --\u003e\n\u003cdiv id='main'\u003eHi there!\u003c/div\u003e\n```\n\n```html\n\u003cspan.big.bold\u003e Welcome!\n\n\u003cspan class='big bold'\u003eWelcome!\u003c/span\u003e\n```\n\n```html\n\u003c.links\u003e for link in nav-links\n  \u003ca href={link.href}\u003e link.text\n\n\u003cdiv class='links'\u003e\n  \u003ca href='/link1'\u003eFirst Link\u003c/a\u003e\n  \u003ca href='/link2'\u003e2nd Link\u003c/a\u003e\n  \u003ca href='/link3'\u003eFinal Link\u003c/a\u003e\n\u003c/div\u003e\n```\n\n```html\n\u003cform GET=\"/search\"\u003e\n  \u003cinput@query:text placeholder=\"Search...\" /\u003e \u003cinput:submit /\u003e\n\n\u003cform method='GET' action='/search'\u003e\n  \u003cinput name='query' type='text' placeholder='Search...' /\u003e\n  \u003cinput type='submit' /\u003e\n\u003c/form\u003e\n```\n\n## Features\n\n- Auto-closing HTML tags and code blocks based on indentation:\n  - `\u003ch1\u003e Welcome, \u003ci\u003e Rob` becomes `\u003ch1\u003e Welcome, \u003ci\u003e Rob \u003c/i\u003e\u003c/h1\u003e`\n- Shorthand for `id`, `class`, `type`, and `name` attributes:\n  - `\u003cdiv#id\u003e`\n  - `\u003cdiv.class1.class2\u003e`\n  - `\u003cinput@form-field-name\u003e`\n  - `\u003cinput:text\u003e`\n- Dynamic values for regular attributes:\n  - `\u003cdiv page-num={page.id}\u003e`\n- Conditionally set attributes or enable shorthand:\n  - `\u003cdiv .logged-in=logged-in?\u003e`\n  - `\u003cdiv data-map=is-map?\u003e`\n- String interpolation:\n  - `\u003cspan.greeting\u003e \"Hey there {name}. 2 + 2 is {2 + 2}\"`\n- Shorthand interpolation:\n  - `\u003cspan #page-{page.id} .is-{page.type}\u003e page.title`\n- Implicit divs:\n  - `\u003c#main\u003e` becomes `\u003cdiv id='main'\u003e`\n- Implicit closing tags:\n  - `\u003ci\u003edelicious\u003c/\u003e` becomes `\u003ci\u003edelicious\u003c/i\u003e`\n- Easy inline JavaScript:\n  - `\u003cli\u003e \u003ca onclick=(alert(\"Oink!\"))\u003e \"🐷\"`\n- Basic types:\n  - `bool, int, float, string, list, map, fn`\n- Loop over `list` and `map`:\n  - `\u003cul\u003e for page in pages do \u003cli id=page-{page.id}\u003e page.name`\n  - `for k, v in some-map do \u003ctd\u003e k \u003c/\u003e \u003ctd\u003e v`\n- if/else statements\n  - `if logged_in? then \u003ch2\u003e Welcome back!`\n- Error-checked assignment with `:=` and `=`:\n  - `name := 'Bob'` will error if name **is** already set.\n  - `name = 'Bob'` will error if name **isn't** already set.\n- Call functions defined in Rust:\n  - `\u003cdiv.name\u003e to-uppercase(name)`\n- Define your own Hatter functions with strict arity and implicit\n  return values:\n  - `def greet(name) do print(\"Hey there, {name}!\")`\n  - `greet(\"Lydia\")` prints `Hey there, Lydia!`\n- Define your own Hatter operators:\n  - `def ++(a, b) do concat(to-uppercase(a), ' ', to-uppercase(b))`\n  - `\"one\" ++ \"two\"` returns `ONE TWO`\n- Closures and function literals:\n  - `adder := fn(x) fn(y) x + y` then `add1 := adder(1)`\n  - `add1(200)` returns `201`\n- Call functions with keyword arguments:\n  - `def greet(title, name) do print(\"Hiya, {title}. {name}!\")`\n  - `greet(name: \"Marley\", title: \"Dr\")` prints `Hiya, Dr. Marley!`\n- `do` keyword for one-line blocks:\n  - `if 2 \u003e 1 do print(\"Obviously\")`\n  - `for x in list do print(x)`\n- `then` keyword for one-line `if` statements:\n  - `if 2 \u003e 1 then print(\"Yup!\") else if 2 \u003c 1 then print(\"Impossible.\")`\n- Hatter will add a `\u003c!DOCTYPE\u003e` and wrap everything in `\u003chtml\u003e` if\n  the first tag in your template is `\u003chead\u003e`.\n\n## Getting Started\n\nThere are two ways to use Hatter:\n\n### 1. In Your Rust Application\n\nHatter can (primarily) be used as a templating language from within\nyour Rust applications.\n\nSimply add Hatter to `Cargo.toml`:\n\n```toml\n[dependencies]\nhatter = \"0.1\"\n```\n\nThen create a `hatter::Env`, which represents the top-level Hatter\nscope for your template, to set variables and render your template:\n\n```rust\nuse hatter::{Args, Env, Value};\n\nlet mut env = Env::new();\nenv.set(\"name\", \"Bobby Boucher\");\nenv.set(\"age\", 31);\nenv.render(r#\"\n\u003cp\u003e \u003cb\u003eName:\u003c/\u003e name\n\u003cp\u003e \u003cb\u003eAge:\u003c/\u003e age\n\"#)\n```\n\nYou can also write functions in Rust and make them available to your\nHTML templates:\n\n```rust\nuse hatter::prelude::*;\n\nfn quote(args: Args) -\u003e Result\u003cValue\u003e {\n  let file = std::fs::read_to_string(\"quotes.txt\")?;\n  let list_of_quotes: Vec\u003c_\u003e = file.split('\\n').collect();\n  let line = match args.need_number(0)? as usize {\n    n if n \u003e list_of_quotes.len() =\u003e 0,\n    n =\u003e n,\n  };\n\n  Value::from(list_of_quotes[line]).ok()\n}\n\nfn main() {\n    let mut env = Env::new();\n    env.set(\"quote\", quote);\n    println!(\"{}\", env.render(\"\u003cdiv\u003e quote(1)\").unwrap());\n}\n```\n\nFor more infomation see the [API Documentation][api-docs].\n\n### 2. As A Standalone Executable\n\nHatter can be used as a regular command line program to turn `.hat`\nfiles into HTML.\n\nJust install it using `cargo`:\n\n```bash\ncargo install hatter\n```\n\nThen point it at any `.hat` file:\n\n```bash\n$ cat test.hat\n\u003cb.test\u003e \"Testing 1 2 3 {2 + 2}\"\n\n$ hatter test.hat\n\u003cb class='test'\u003eTesting 1 2 3 4 \u003c/b\u003e\n```\n\nYou can also install Hatter with a readline-powered REPL:\n\n```bash\ncargo install hatter --features repl\n```\n\nTo launch it, start `hatter` with no arguments:\n\n```bash\n$ hatter\nHatter v0.0.1 REPL\n\u003e\u003e 1 + 2\n3\n```\n\n## TODO\n\n- [ ] HTMLized error page\n- [ ] show error location in source text on runtime errors\n\n## Future Features\n\n- Define your own tags:\n  - `def \u003citem(item)\u003e do \u003cli.item data-id={item.id}\u003e item.text`.\n- Optional type checking for functions\n- stdlib\n- VSCode Extension\n- luacheck-style tool\n- LSPc\n\n## License\n\nHatter is licensed under either of the following, at your pleasure:\n\n- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or\n  \u003chttp://www.apache.org/licenses/LICENSE-2.0\u003e)\n- MIT License ([LICENSE-MIT](LICENSE-MIT) or\n  \u003chttp://opensource.org/licenses/MIT\u003e)\n\n[Imba] is licensed under the [MIT License](https://github.com/imba/imba/blob/master/LICENSE).\n\n[imba]: https://imba.io\n[vial]: http://github.com/xvxx/vial\n[api-docs]: https://docs.rs/hatter/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxvxx%2Fhatter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxvxx%2Fhatter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxvxx%2Fhatter/lists"}