# `PhiaUi.Editor.OtEngine`
[🔗](https://github.com/charlenopires/PhiaUI/blob/v0.1.17/lib/phia_ui/editor/ot_engine.ex#L1)

Pure Elixir Operational Transform (OT) engine for collaborative text editing.

Implements the core OT algorithms for plain-text documents using a delta-based
format compatible with Quill Delta / ShareDB. Each delta is a list of operations
that describe a document transformation:

  - `%{retain: n}` — skip forward `n` characters (keep them unchanged)
  - `%{insert: text}` — insert `text` at the current position
  - `%{delete: n}` — delete `n` characters at the current position

## Core Functions

  - `apply/2` — apply a delta to a document string
  - `transform/3` — transform concurrent deltas (OT core)
  - `compose/2` — merge two sequential deltas into one
  - `invert/2` — produce an undo delta from the original document

## Example

    iex> doc = "Hello World"
    iex> delta = [%{retain: 5}, %{insert: ","}, %{retain: 6}]
    iex> {:ok, result} = PhiaUi.Editor.OtEngine.apply(doc, delta)
    iex> result
    "Hello, World"

## Transform Example

    iex> # User A inserts "X" at position 0, User B inserts "Y" at position 0
    iex> op_a = [%{insert: "X"}]
    iex> op_b = [%{insert: "Y"}]
    iex> {:ok, b_prime} = PhiaUi.Editor.OtEngine.transform(op_a, op_b, :left)
    iex> b_prime
    [%{retain: 1}, %{insert: "Y"}]

# `apply`

```elixir
@spec apply(String.t(), list()) :: {:ok, String.t()} | {:error, String.t()}
```

Apply a delta to a document string, producing the transformed document.

Returns `{:ok, new_string}` on success, or `{:error, reason}` if the delta
does not match the document length.

## Example

    iex> PhiaUi.Editor.OtEngine.apply("abcdef", [%{retain: 3}, %{delete: 2}, %{insert: "XY"}, %{retain: 1}])
    {:ok, "abcXYf"}

# `compose`

```elixir
@spec compose(list(), list()) :: {:ok, list()}
```

Compose two sequential deltas into a single equivalent delta.

If delta A transforms document D into D', and delta B transforms D' into D'',
then `compose(A, B)` produces a delta C that transforms D directly into D''.

Returns `{:ok, composed}`.

## Example

    iex> a = [%{insert: "abc"}]
    iex> b = [%{retain: 1}, %{delete: 1}, %{retain: 1}]
    iex> {:ok, composed} = PhiaUi.Editor.OtEngine.compose(a, b)
    iex> composed
    [%{insert: "ac"}]

# `delete`

```elixir
@spec delete(pos_integer()) :: %{delete: pos_integer()}
```

Create a delete operation.

# `insert`

```elixir
@spec insert(String.t()) :: %{insert: String.t()}
```

Create an insert operation.

# `invert`

```elixir
@spec invert(list(), String.t()) :: {:ok, list()}
```

Produce an inverted delta that undoes the given delta when applied to the
document that results from applying the original delta.

Given `{:ok, new_doc} = apply(doc, delta)`, then
`{:ok, inverted} = invert(delta, doc)` satisfies
`apply(new_doc, inverted) == {:ok, doc}`.

Returns `{:ok, inverted_delta}`.

## Example

    iex> doc = "Hello"
    iex> delta = [%{delete: 5}, %{insert: "Bye"}]
    iex> {:ok, inverted} = PhiaUi.Editor.OtEngine.invert(delta, doc)
    iex> inverted
    [%{delete: 3}, %{insert: "Hello"}]

# `length`

```elixir
@spec length(list()) :: non_neg_integer()
```

Compute the input length a delta operates on (sum of retain + delete).

Insert operations do not consume input characters, so they are excluded.

## Example

    iex> PhiaUi.Editor.OtEngine.length([%{retain: 5}, %{insert: "hi"}, %{delete: 3}])
    8

# `retain`

```elixir
@spec retain(pos_integer()) :: %{retain: pos_integer()}
```

Create a retain operation.

# `transform`

```elixir
@spec transform(list(), list(), :left | :right) :: {:ok, list()}
```

Transform delta B against delta A so that B can be applied after A.

Given two concurrent operations A and B (both based on the same document),
`transform(A, B, priority)` produces B' such that:

    apply(apply(doc, A), B') == apply(apply(doc, B), A')

The `priority` parameter (`:left` or `:right`) resolves ties when both
operations insert at the same position:
  - `:left` — A's insert goes first (B' gets a retain to skip over A's insert)
  - `:right` — B's insert goes first

Returns `{:ok, transformed_b}`.

## Example

    iex> op_a = [%{retain: 3}, %{insert: "X"}]
    iex> op_b = [%{retain: 3}, %{insert: "Y"}]
    iex> {:ok, b_prime} = PhiaUi.Editor.OtEngine.transform(op_a, op_b, :left)
    iex> b_prime
    [%{retain: 4}, %{insert: "Y"}]

---

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