Text OT Engine¶
Operational-transformation engine for plain-text co-editing. This is the
default engine registered by AddOpStream() under the document type
"text".
When to use¶
- Source-code or markdown collaborative editing.
- Editors that expose insert / retain / delete primitives natively: Monaco, CodeMirror, contenteditable, ProseMirror plain-text mode.
- Anything where edits are characterized by their position in a string.
For attributed text (bold / italic / lists), use Rich Text instead.
Types¶
TDoc = TextDocument — wraps a single Content string.
TOp = TextOp — a sequence of TextOpComponent:
| Component | Effect |
|---|---|
Retain(count) |
Keep the next count characters as-is. |
Insert(text) |
Insert text at the current cursor. |
Delete(count) |
Delete the next count characters. |
Cursor position is implicit; the components are walked left-to-right.
Worked example¶
// State: "Hello"
// Goal: "Hello, world"
var op = new TextOp(new TextOpComponent[]
{
new Retain(5),
new Insert(", world")
});
var newState = engine.Apply(state, op);
// newState.Content == "Hello, world"
A concurrent op from another peer is rebased automatically:
// Alice and Bob both base-rev N. Alice prepends "Hey ", Bob appends "!".
// Both ops arrive at the server.
// Alice's lands first; Bob's is transformed against Alice's:
var bobTransformed = engine.Transform(bob, alice, TransformPriority.ExistingWins);
// Bob's "append at length 5" becomes "append at length 9" — correct, no clash.
Registration¶
To register multiple text document types (e.g. one per file extension):
services.AddOpStream()
.AddEngine<TextDocument, TextOp, TextOtEngine>("text/markdown")
.AddEngine<TextDocument, TextOp, TextOtEngine>("text/typescript");
Client wire shape¶
Use the constants in OpStreamConstants on the .NET side or copy the
discriminator strings on JS / native clients.
Undo / redo¶
TextOtEngine.Invert(op, preState) reconstructs the inverse of any op
using the original string for the bytes that were deleted. This makes it
fully compatible with UndoRedoEngine<TextDocument, TextOp>.
No RestampToWin override is needed — OT engines are timestamp-free.