Skip to content
Anjunar/ DOCS

Sessions and commands

An EditorSession owns the current state. Every change runs through update or dispatch and ends in one commit, or in a value that says why not.

Transactions

A private draft

update hands you a transaction. It latches its first failure and rejects everything after, and its handle is only valid inside the closure.

scala
session.update { tx => tx.spliceText(NodeId("t1"), 5, 0, "!") tx.select(RangeSelection.caret(Point.textAfter(NodeId("t1"), 6))) } // Either[UpdateError, Commit]
Commands

Intent with a typed payload

A command is an EditorCommand[A], found by reference, never by string. Handlers run from Critical down to Fallback; the first that handles it ends the chain.

scala
session.dispatch(RichText.InsertText, "Hello") session.dispatch(RichText.InsertParagraph) session.dispatch(RichText.ToggleMark, StandardMarks.Strong) session.dispatch(RichText.SetHeading, Some(HeadingLevel.H2))
Commits

Two revisions

revision grows with every publish, documentRevision only when the document changed. Code that persists compares the second, so a moved caret never triggers a write.

scala
var saved = session.state.documentRevision val subscription = session.onCommit { commit => if commit.current.documentRevision != saved then save(commit.current.document) saved = commit.current.documentRevision }
Rules of the boundary
A commit is not a render: whether a view shows it is DocumentView.onProjected's question.
update inside update returns UpdateError.NestedUpdate; use enqueueUpdate from listeners.
Expected failures are Either values; misuse such as a stale transaction handle throws.
A state field's reducer may reject a commit before it happens.