# Smart Indentation Engine
[](https://github.com/goodtouch/smart_indentation_engine/actions/workflows/ci.yml)
[](https://github.com/goodtouch/smart_indentation_engine/blob/main/LICENSE.md)
[](https://hex.pm/packages/smart_indentation_engine)
[](https://hexdocs.pm/smart_indentation_engine)
A custom EEx engine that does its best to handle indentation in an intuitive
way, so that you can enjoy both clean readable templates and well-formatted
output.
## Features
The engine ships with the following features:
* **Smart Indentation** - Preserves proper indentation in template output.
* **Template Inclusion** - Supports including (and re-indenting) partial
templates.
* **Assigns Binding** - Access values from the `assigns` binding using the `@`
syntax (e.g., `@foo`).
* **Flexible Spacing** - Works with both spaces and tabs.
## Overview
This engine extends the default [`EEx.SmartEngine`][hexdocs.eex.smart_engine] by
implementing the `<%|` tag to handles indentation in template blocks.
When you use it with control flow structures like `if`, `for`, `case`, etc., the
the engine automatically aligns the output to match the indentation of the
control statement.
Templates included with `<%= include :template %>` are also re-indented to match
the surrounding context.
## Usage
### Installation
```elixir
def deps do
[
{:smart_indentation_engine, "~> 0.1"}
]
end
```
### Quick Example
Using the `<%|` tag for control flow:
```elixir
Mix.install([
{:smart_indentation_engine, "~> 0.1"}
])
"""
<ul>
<%| for name <- ["world", "darkness my old friend"] do %>
<li>hello <%= name %></li>
<% end %>
</ul>
"""
|> EEx.eval_string([], engine: SmartIndentationEngine)
```
Will produce the following output:
```html
<ul>
<li>hello world</li>
<li>hello darkness my old friend</li>
</ul>
```
### The `~TT` Sigil
By importing the `SmartIndentationEngine.Template` module you'll have access to
the `~TT` sigil that automatically uses the engine:
```elixir
defmodule Template.BasicList do
import SmartIndentationEngine.Template
def render(_assigns \\ []) do
~TT"""
<ul>
<%| for name <- ["world", "darkness my old friend"] do %>
<li>hello <%= name %></li>
<% end %>
</ul>
"""
end
end
Template.BasicList.render()
```
### Using `@` for Assigns
```elixir
defmodule Template.AssignedList do
import SmartIndentationEngine.Template
def render(assigns \\ []) do
~TT"""
<ul>
<%| for name <- @names do %>
<li>hello <%= name %></li>
<% end %>
</ul>
"""
end
end
Template.AssignedList.render(names: ["world", "darkness my old friend"])
```
### Template Inclusion
You can also include other templates using the `include` function. Included
templates will be reindented to match the surrounding context.
```elixir
defmodule Template.IncludedList do
import SmartIndentationEngine.Template
def render(assigns \\ []) do
~TT"""
<div>
<h1>Nice to meet you, hope you guess my name!</h1>
<%= include :list, names: @names %>
</div>
"""
end
def list(assigns) do
~TT"""
<ul>
<%| for name <- @names do %>
<li>hello <%= name %></li>
<% end %>
</ul>
"""
end
end
Template.IncludedList.render(names: ["world", "darkness my old friend"])
```
This produces:
```html
<div>
<h1>Nice to meet you, hope you guess my name!</h1>
<ul>
<li>hello world</li>
<li>hello darkness my old friend</li>
</ul>
</div>
```
## How It Works
When you use the `<%|` marker with control structures, the engine:
1. Captures the indentation context of the control statement
2. Remove the empty lines introduced by the control statement
2. Processes the content inside the block (handles nested structures and
re-indents included templates)
3. Dedents the block output to match captured indentation
## License
The package is available as open source under the terms of the MIT License.
[hexdocs.eex.smart_engine]: https://hexdocs.pm/eex/EEx.SmartEngine.html