# 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.).
