Smart Indentation Engine
View SourceA 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
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
def deps do
[
{:smart_indentation_engine, "~> 0.1"}
]
end
Quick Example
Using the <%|
tag for control flow:
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:
<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:
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
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.
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:
<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:
- Captures the indentation context of the control statement
- Remove the empty lines introduced by the control statement
- Processes the content inside the block (handles nested structures and re-indents included templates)
- Dedents the block output to match captured indentation
License
The package is available as open source under the terms of the MIT License.