# `Minga.Core.Decorations.ConcealRange`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga/core/decorations/conceal_range.ex#L1)

A conceal range decoration: hides buffer characters from the display
without removing them from the buffer.

Concealed text occupies zero display columns (or one column if a
replacement character is specified). The buffer content is never
modified; `BufferServer.content/1` always returns the raw text
including concealed characters.

## Replacement character

When `replacement` is nil, the concealed range is invisible. When
`replacement` is a string (typically a single character like "·"),
the entire concealed range is replaced by that single character in
the display. The replacement inherits the style of the first
concealed character.

## Cursor behavior

In normal mode, the cursor skips over concealed ranges. In insert
mode, entering a concealed range expands it (reveals the raw
characters) so the user can edit. For V1, concealment follows
Neovim's conceallevel=2 equivalent: conceal when the cursor is
not on the line.

## Column mapping

Concealed ranges affect the mapping between buffer columns and
display columns. `buf_col_to_display_col` subtracts concealed
width (and adds replacement width). `display_col_to_buf_col`
reverses the mapping. These are the central functions that the
rendering pipeline, mouse handling, and selection logic depend on.

# `t`

```elixir
@type t() :: %Minga.Core.Decorations.ConcealRange{
  end_pos: Minga.Core.IntervalTree.position(),
  group: atom() | nil,
  id: reference(),
  priority: integer(),
  replacement: String.t() | nil,
  replacement_style: Minga.Core.Face.t(),
  start_pos: Minga.Core.IntervalTree.position()
}
```

A conceal range decoration.

- `id` - unique reference for removal
- `start_pos` - inclusive start position `{line, col}` (display columns)
- `end_pos` - exclusive end position `{line, col}` (display columns)
- `replacement` - nil for invisible, or a string shown in place of the concealed text
- `replacement_style` - Face.t() struct for the replacement character
- `priority` - higher values take precedence on overlap (default 0)
- `group` - optional atom for bulk removal (e.g., `:markdown`, `:agent`)

# `concealed_width_on_line`

```elixir
@spec concealed_width_on_line(t(), non_neg_integer(), non_neg_integer()) ::
  non_neg_integer()
```

Returns the concealed width: the number of buffer columns hidden by this range
on the given line. For multi-line conceals, returns the portion relevant to
the specified line.

# `contains?`

```elixir
@spec contains?(t(), Minga.Core.IntervalTree.position()) :: boolean()
```

Returns true if the given position is inside the conceal range.

# `display_width`

```elixir
@spec display_width(t()) :: non_neg_integer()
```

Returns the display width contribution of this conceal range.

When replacement is nil, the concealed text contributes 0 display columns.
When replacement is a string, it contributes 1 display column (the
replacement character).

# `spans_line?`

```elixir
@spec spans_line?(t(), non_neg_integer()) :: boolean()
```

Returns true if this conceal range spans the given line.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
