# `Minga.Popup.Rule`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga/popup/rule.ex#L1)

Declarative rule for how a popup buffer should be displayed.

Each rule matches a buffer name (by exact string or regex) and specifies
the display mode, positioning, sizing, and behavior. Rules are registered
in the `Popup.Registry` and checked when a buffer is opened.

## Display modes

- `:split` — edge-anchored managed pane (Doom Emacs style). The popup
  appears as a temporary split on one side of the editor, governed by
  `side` and `size`. Closing the popup restores the original layout.

- `:float` — bordered floating panel (Neovim/LazyVim style). The popup
  appears as an overlay with configurable `width`, `height`, `position`,
  and `border` style. Requires the FloatingWindow primitive (#343).

## Examples

    Popup.Rule.new("*Warnings*", side: :bottom, size: {:percent, 30}, focus: false)

    Popup.Rule.new(~r/\*Help/, display: :float, width: {:percent, 60},
      height: {:percent, 70}, border: :rounded, focus: true, auto_close: true)

# `border`

```elixir
@type border() :: :rounded | :single | :double | :none
```

Border style for float display mode.

# `display`

```elixir
@type display() :: :split | :float
```

How the popup is rendered.

# `position`

```elixir
@type position() :: :center | {:offset, integer(), integer()}
```

Popup position for float display mode.

# `side`

```elixir
@type side() :: :bottom | :right | :left | :top
```

Which edge a split popup anchors to.

# `size`

```elixir
@type size() :: {:percent, 1..100} | {:rows, pos_integer()} | {:cols, pos_integer()}
```

Popup size as a percentage of available space or fixed rows/cols.

# `t`

```elixir
@type t() :: %Minga.Popup.Rule{
  auto_close: boolean(),
  border: border(),
  display: display(),
  focus: boolean(),
  height: size() | nil,
  modeline: boolean(),
  pattern: Regex.t() | String.t(),
  position: position(),
  priority: integer(),
  quit_key: String.t(),
  side: side(),
  size: size(),
  width: size() | nil
}
```

# `matches?`

```elixir
@spec matches?(t(), String.t()) :: boolean()
```

Returns true if the given buffer name matches this rule's pattern.

String patterns match exactly. Regex patterns match anywhere in the name.

# `new`

```elixir
@spec new(
  Regex.t() | String.t(),
  keyword()
) :: t()
```

Creates a new popup rule from a pattern and keyword options.

The pattern can be an exact string (e.g. `"*Warnings*"`) or a
`Regex` (e.g. `~r/\*Help/`). All other fields are optional and
default to a bottom split at 30% height with focus.

Raises `ArgumentError` if any option is invalid.

## Options

- `:display` — `:split` (default) or `:float`
- `:side` — `:bottom` (default), `:right`, `:left`, `:top` (split mode)
- `:size` — `{:percent, n}` or `{:rows, n}` / `{:cols, n}` (split mode, default `{:percent, 30}`)
- `:width` — float mode width (default nil, uses `{:percent, 50}` when display is `:float`)
- `:height` — float mode height (default nil, uses `{:percent, 50}` when display is `:float`)
- `:position` — `:center` (default) or `{:offset, row, col}` (float mode)
- `:border` — `:rounded` (default), `:single`, `:double`, `:none` (float mode)
- `:focus` — whether opening the popup steals focus (default `true`)
- `:auto_close` — close when the popup loses focus (default `false`)
- `:quit_key` — key to dismiss the popup (default `"q"`)
- `:modeline` — show a modeline in the popup (default `false`, split mode only)
- `:priority` — rule ordering; higher priority wins on conflict (default `0`)

---

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