Yex.UndoManager (y_ex v0.12.1)

Copy Markdown View Source

Represents a Y.UndoManager instance.

Tracked origins

A transaction's origin is the term passed to Yex.Doc.transaction/3, or nil when none was given. The manager only captures changes from origins it tracks:

  • With no tracked origins (the default), it captures only transactions whose origin is nil.
  • Once at least one origin is tracked, it captures only transactions with a tracked origin, and transactions with a nil origin are no longer captured. Removing every tracked origin with exclude_origin/2 goes back to capturing only nil.

This matches Yjs, where trackedOrigins defaults to new Set([null]), except that nil cannot be tracked alongside other origins. The manager's own undo and redo transactions are always tracked, so undone changes can be redone.

To track origins from the moment the manager is created, pass them as tracked_origins in Yex.UndoManager.Options instead of calling include_origin/2 afterwards; otherwise a nil-origin change made in between is captured.

Undo and redo origins

Undo and redo commit a transaction whose origin is the manager itself. Update subscribers (Yex.Doc.monitor_update/2) and observers (Yex.SharedType.observe/2) receive that %Yex.UndoManager{} as the origin, so it can be matched against the manager in use:

receive do
  {:update_v1, _update, ^undo_manager, _doc} -> :undo_or_redo
end

Summary

Functions

Returns whether the redo stack holds at least one item.

Returns whether the undo stack holds at least one item.

Clears all StackItems stored within current UndoManager, effectively resetting its state.

Excludes an origin from being tracked by the UndoManager.

Expands the scope of the UndoManager to include additional shared types. The scope can be a Text, Array, or Map type.

Includes an origin to be tracked by the UndoManager.

Creates a new UndoManager for the given document and scope with default options. The scope can be a Text, Array, Map, XmlText, XmlElement, or XmlFragment type.

Creates a new UndoManager with the given options.

Redoes the last undone change.

Redoes the last undone change and reports whether the document changed.

Stops capturing changes for the current stack item. This ensures that the next change will create a new stack item instead of being merged with the previous one, even if it occurs within the normal timeout window.

Undoes the last tracked change.

Undoes the last tracked change and reports whether the document changed.

Types

t()

@type t() :: %Yex.UndoManager{doc: Yex.Doc.t(), reference: reference()}

Functions

can_redo?(undo_manager)

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

Returns whether the redo stack holds at least one item.

can_undo?(undo_manager)

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

Returns whether the undo stack holds at least one item.

clear(undo_manager)

@spec clear(t()) :: :ok | {:error, term()}

Clears all StackItems stored within current UndoManager, effectively resetting its state.

Example:

text = Doc.get_text(doc, "text")
undo_manager = UndoManager.new(doc, text)

Text.insert(text, 0, "Hello")
Text.insert(text, 5, " World")
UndoManager.clear(undo_manager)
# All undo/redo history is now cleared

Raises Yex.TransactionAcqError instead of blocking when a write transaction on the document is open, for example inside Yex.Doc.transaction/3.

exclude_origin(undo_manager, origin)

Excludes an origin from being tracked by the UndoManager.

This removes an origin added with include_origin/2 or tracked_origins. Origins that were never included are already not captured, so excluding one has no effect. Excluding the last tracked origin makes the manager capture nil-origin transactions again.

expand_scope(undo_manager, scope)

Expands the scope of the UndoManager to include additional shared types. The scope can be a Text, Array, or Map type.

Raises Yex.TransactionAcqError when a transaction on the document is open.

include_origin(undo_manager, origin)

Includes an origin to be tracked by the UndoManager.

After the first included origin, transactions with a nil origin are no longer captured. See "Tracked origins" in the module documentation.

is_valid_scope(scope)

(macro)

new(doc, scope)

@spec new(
  Yex.Doc.t(),
  struct()
) :: {:ok, t()} | {:error, term()}

Creates a new UndoManager for the given document and scope with default options. The scope can be a Text, Array, Map, XmlText, XmlElement, or XmlFragment type.

Errors

  • Returns {:error, "Invalid scope: expected a struct"} if scope is not a struct
  • Returns {:error, "Failed to get branch reference"} if there's an error accessing the scope

new_with_options(doc, scope, options)

@spec new_with_options(Yex.Doc.t(), struct(), Yex.UndoManager.Options.t()) ::
  {:ok, t()} | {:error, term()}

Creates a new UndoManager with the given options.

Options

See Yex.UndoManager.Options for available options.

Errors

redo(undo_manager)

@spec redo(t()) :: :ok | {:error, term()}

Redoes the last undone change.

Returns :ok whether or not anything was redone; use redo_with_result/1 to learn which. Raises Yex.TransactionAcqError when a transaction on the document is open.

redo_with_result(undo_manager)

@spec redo_with_result(t()) :: {:ok, boolean()} | {:error, term()}

Redoes the last undone change and reports whether the document changed.

Returns {:ok, false} when the redo stack is empty. Raises Yex.TransactionAcqError when a transaction on the document is open, whether or not the stack is empty.

stop_capturing(undo_manager)

Stops capturing changes for the current stack item. This ensures that the next change will create a new stack item instead of being merged with the previous one, even if it occurs within the normal timeout window.

Example:

text = Doc.get_text(doc, "text")
undo_manager = UndoManager.new(doc, text)

Text.insert(text, 0, "a")
UndoManager.stop_capturing(undo_manager)
Text.insert(text, 1, "b")
UndoManager.undo(undo_manager)
# Text.to_string(text) will be "a" (only "b" was removed)

undo(undo_manager)

@spec undo(t()) :: :ok | {:error, term()}

Undoes the last tracked change.

Returns :ok whether or not anything was undone; use undo_with_result/1 to learn which. Raises Yex.TransactionAcqError when a transaction on the document is open (for example when called inside Yex.Doc.transaction/3), because undo commits a transaction of its own.

undo_with_result(undo_manager)

@spec undo_with_result(t()) :: {:ok, boolean()} | {:error, term()}

Undoes the last tracked change and reports whether the document changed.

Returns {:ok, false} when the undo stack is empty. Raises Yex.TransactionAcqError under the same condition as undo/1, whether or not the stack is empty.