Packages
mob
0.9.21
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.1
0.9.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.39
0.7.38
0.7.37
0.7.36
0.7.35
0.7.34
0.7.33
0.7.32
0.7.31
0.7.30
0.7.29
0.7.28
0.7.27
0.7.26
0.7.25
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.26
0.6.25
0.6.24
0.6.23
0.6.22
0.6.21
0.6.20
0.6.19
0.6.18
0.6.17
0.6.16
0.6.15
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.2
0.6.1
0.6.0
0.5.18
0.5.17
0.5.16
0.5.15
0.5.14
0.5.11
0.5.10
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.0
BEAM-on-device mobile framework for Elixir
Current section
Files
Jump to
Current section
Files
guides/tooling.md
# Tooling & Formatting
Mob ships with first-class support for `mix format` so that `~MOB` sigils are
formatted alongside the rest of your Elixir code. Generated projects include a
`.formatter.exs` that wires this up automatically.
## Setting up the formatter
Add `Mob.Formatter` to your `.formatter.exs`:
```elixir
# .formatter.exs
[
plugins: [Mob.Formatter],
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
```
Then run:
```bash
mix format
```
That's it. Every `~MOB` sigil in your project is now formatted with the rest
of your code in one pass.
## What gets formatted
### Indentation
Children are indented 2 spaces per nesting level, matching Elixir convention:
```elixir
# Before
~MOB"""
<Column>
<Text text="Hello" />
<Button text="OK" on_tap={tap} />
</Column>
"""
# After
~MOB"""
<Column>
<Text text="Hello" />
<Button text="OK" on_tap={tap} />
</Column>
"""
```
### Attribute wrapping
When a tag's attributes would exceed `line_length`, each attribute moves to its
own line with the closing `/>` or `>` on a dedicated line:
```elixir
# Short enough to stay inline
~MOB(<Button text="Save" on_tap={save_tap} />)
# Wraps when attributes are too long
~MOB"""
<Image
source={assigns.avatar_url}
width={120}
height={120}
corner_radius={:radius_pill}
fill_width={false}
/>
"""
```
### Expression children
`{expr}` slots are indented to match their sibling nodes:
```elixir
~MOB"""
<Column>
<Text text="Items" text_size={:xl} />
{Enum.map(assigns.items, fn item ->
~MOB(<Text text={item} />)
end)}
</Column>
"""
```
## Configuration
### Line length
`Mob.Formatter` respects the standard `line_length` option:
```elixir
[
plugins: [Mob.Formatter],
line_length: 120,
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
```
The default is 98 characters.
### CI enforcement
Add `mix format --check-formatted` to your CI pipeline to catch unformatted
sigils in the same pass as unformatted Elixir:
```bash
mix format --check-formatted
mix credo --strict
mix test
```
## How it works
`Mob.Formatter` implements the `Mix.Tasks.Format` behaviour introduced in
Elixir 1.14. Elixir's formatter calls it for every `~MOB` sigil it encounters,
passing the raw sigil content. The formatter re-parses the content using the
same `NimbleParsec` grammar as the sigil itself and emits normalised output.
If a sigil can't be parsed (e.g. the file is in a mid-edit incomplete state),
the formatter returns the content unchanged rather than raising. `mix format`
never breaks a file it can't fully understand.
See `Mob.Formatter` for the full API reference.
## Credo
Projects generated by `mix mob.new` include Credo in dev/test dependencies.
Run it with:
```bash
mix credo --strict
```
The generated `.credo.exs` is pre-configured to work well with Mob's conventions
(the `~MOB` sigil, module attribute patterns, etc.).