Otzel.Content protocol (otzel v0.3.2)

View Source

Protocol for content types that can be stored in delta operations.

The Content protocol defines how different content types behave within the OT system. By default, strings are supported, but you can implement this protocol for custom embedded content types like images, videos, or nested documents.

Built-in Implementations

Implementing Custom Content

For simple atomic embeds (size 1, cannot be split), use the atomic: true option:

defmodule MyApp.ImageEmbed do
  use Otzel.Content, atomic: true

  defstruct [:url, :width, :height]

  def invert(_, _), do: raise "not implemented"
  def compose(_, _), do: raise "not implemented"
  def transform(_, _, _), do: raise "not implemented"
end

The atomic: true option automatically implements:

  • size/1 - Returns 1
  • take/2 - Returns the whole content
  • merge_into/2 - Returns nil (cannot merge)
  • as_binary/1 - Returns nil
  • embed?/1 - Returns true (is embedded content)
  • diff/2 - Returns empty list for equal content, or delete+insert for different content

Checking Content Type

Use embed?/1 to check if content is an embedded type (returns true) or string-like (returns false):

Otzel.Content.embed?(string_content)  # => false
Otzel.Content.embed?(embed_content)   # => true

Summary

Types

t()

All the types that implement this protocol.

Functions

Converts content to a binary string, or nil if not applicable

Composes two content values

Concatenates a list of content values into a single content value.

Computes the diff between two content values

Returns true if the content is an embedded type (not string-like)

Extracts the content from an operation.

Inverts content changes for undo operations

Attempts to merge adjacent content values

Remaps Insert operations to use a specific string module.

Returns the size (character count) of the content

Splits content at the given position

Transforms content for concurrent edits

Types

t()

@type t() :: term()

All the types that implement this protocol.

Functions

as_binary(content)

@spec as_binary(t()) :: binary() | nil

Converts content to a binary string, or nil if not applicable

compose(content1, content2)

@spec compose(t(), t()) :: t()

Composes two content values

concatenate(list)

Concatenates a list of content values into a single content value.

Delegates to the appropriate content module's concatenate/1 function based on the type of the first element.

diff(src, dst)

@spec diff(t(), t()) :: [insert: t(), equals: t(), delete: t()]

Computes the diff between two content values

embed?(content)

@spec embed?(t()) :: boolean()

Returns true if the content is an embedded type (not string-like)

from(op)

Extracts the content from an operation.

For Insert operations, returns the content being inserted. For Retain operations, returns the target (count or embedded content).

invert(content1, content2)

@spec invert(t(), t()) :: t()

Inverts content changes for undo operations

merge_into(content1, content2)

@spec merge_into(t(), t()) :: t() | nil

Attempts to merge adjacent content values

remap_inserts(ops, module)

Remaps Insert operations to use a specific string module.

Converts the content of each Insert operation to the given module's representation (e.g., String or Otzel.Content.Iomemo).

size(content)

@spec size(t()) :: non_neg_integer()

Returns the size (character count) of the content

take(content, count)

@spec take(t(), non_neg_integer()) :: {t(), t() | nil}

Splits content at the given position

transform(content1, content2, priority)

@spec transform(t(), t(), Otzel.priority()) :: {t() | nil, t(), t()}

Transforms content for concurrent edits