Text splitting operations at offset boundaries.
Splits text nodes so that mark operations can be applied to precise ranges.
Summary
Types
Any node tuple, including a custom type a consumer has introduced
List of inline children, which need not all be text nodes
A text node tuple
Functions
Find the node at a given offset.
Split text nodes at a given offset within the children list.
Split text nodes at both start and end offsets for a range.
Types
Any node tuple, including a custom type a consumer has introduced
@type children() :: [any_node()]
List of inline children, which need not all be text nodes
A text node tuple
Functions
@spec find_node_at_offset(children(), non_neg_integer()) :: {children(), any_node() | nil, children(), non_neg_integer()}
Find the node at a given offset.
Returns {before_nodes, target_node, after_nodes, offset_in_node}.
Examples
iex> children = [
...> {:text, %{text: "Hello", marks: []}, []},
...> {:text, %{text: " world", marks: []}, []}
...> ]
iex> {before, target, after_nodes, offset_in_node} = Quillon.Transform.Split.find_node_at_offset(children, 7)
iex> before
[{:text, %{text: "Hello", marks: []}, []}]
iex> target
{:text, %{text: " world", marks: []}, []}
iex> after_nodes
[]
iex> offset_in_node
2
@spec split_at_offset(children(), non_neg_integer()) :: children()
Split text nodes at a given offset within the children list.
Returns unchanged list if offset falls on a node boundary. Preserves marks when splitting a node.
Only text nodes split. An offset landing inside a node of another type is clamped rather than split - the list comes back unchanged - because splitting such a node would need a schema the library does not have.
Examples
iex> children = [{:text, %{text: "Hello world", marks: []}, []}]
iex> Quillon.Transform.Split.split_at_offset(children, 5)
[
{:text, %{text: "Hello", marks: []}, []},
{:text, %{text: " world", marks: []}, []}
]
iex> children = [{:text, %{text: "Hello world", marks: [:bold]}, []}]
iex> Quillon.Transform.Split.split_at_offset(children, 5)
[
{:text, %{text: "Hello", marks: [:bold]}, []},
{:text, %{text: " world", marks: [:bold]}, []}
]
iex> children = [{:text, %{text: "Hello", marks: []}, []}]
iex> Quillon.Transform.Split.split_at_offset(children, 0)
[{:text, %{text: "Hello", marks: []}, []}]
iex> children = [{:text, %{text: "Hello", marks: []}, []}]
iex> Quillon.Transform.Split.split_at_offset(children, 5)
[{:text, %{text: "Hello", marks: []}, []}]
@spec split_range(children(), non_neg_integer(), non_neg_integer()) :: children()
Split text nodes at both start and end offsets for a range.
Splits at END first, then START to preserve start offset position. This is crucial for correct mark application.
Examples
iex> children = [{:text, %{text: "Hello world", marks: []}, []}]
iex> Quillon.Transform.Split.split_range(children, 2, 7)
[
{:text, %{text: "He", marks: []}, []},
{:text, %{text: "llo w", marks: []}, []},
{:text, %{text: "orld", marks: []}, []}
]
iex> children = [{:text, %{text: "Hello", marks: []}, []}]
iex> Quillon.Transform.Split.split_range(children, 0, 5)
[{:text, %{text: "Hello", marks: []}, []}]