Skip to main content

Text

Struct Text 

Source
pub struct Text { /* private fields */ }
Expand description

Rich-text CRDT — a List<char> augmented with Peritext-style format spans.

Text shares its underlying List’s Lamport clock for both character ops and format ops, so every op gets a unique monotonic OpId.

Implementations§

Source§

impl Text

Source

pub fn new(replica: ReplicaId) -> Self

Create an empty text document.

Source

pub fn new_random() -> Self

Create a new instance with a random ReplicaId from OS entropy. See crate::new_replica_id.

Source

pub fn replica_id(&self) -> ReplicaId

This replica’s id.

Source

pub fn len(&self) -> usize

Length of visible text in Unicode scalar values (Rust chars) — not bytes and not grapheme clusters. Multi-char graphemes like 👨‍👩‍👧 (5 chars) count as 5.

For grapheme-aware length, see Self::grapheme_count.

Source

pub fn is_empty(&self) -> bool

Is the document empty?

Source

pub fn grapheme_count(&self) -> usize

Length in extended grapheme clusters (UAX #29). This is the “user-perceived character” count — emoji like 👨‍👩‍👧 count as 1. Use this in user-facing position math (cursor coordinates, selection ranges).

Cost: O(N) — walks the visible string once.

Source

pub fn grapheme_to_char_pos(&self, grapheme_pos: usize) -> usize

Convert a grapheme position to the underlying char (scalar) position. Returns self.len() if grapheme_pos >= self.grapheme_count().

Cost: O(N).

Source

pub fn char_to_grapheme_pos(&self, char_pos: usize) -> usize

Convert a char position to the grapheme position whose first char is at or before the given char position. Returns 0 for empty docs and self.grapheme_count() for positions at end.

Cost: O(N).

Source

pub fn insert_grapheme_str(&mut self, g_pos: usize, s: &str) -> Vec<TextOp>

Insert s at grapheme position g_pos. Multi-char graphemes in s are inserted as a single contiguous run, so they cannot be split by concurrent edits at the same boundary (the standard non-interleaving guarantee from Fugue-Maximal).

Returns one TextOp per char inserted.

Source

pub fn delete_grapheme(&mut self, g_pos: usize) -> Vec<TextOp>

Delete the grapheme at grapheme position g_pos (atomically, all of its chars). No-op if g_pos is out of bounds.

Source

pub fn as_string(&self) -> String

Render the text as a String. Format spans are not included; use Self::iter_with_marks to access them.

Text also implements std::fmt::Display, so format!("{text}") works.

Source

pub fn insert(&mut self, pos: usize, ch: char) -> TextOp

Insert a single character at visible position pos.

Source

pub fn insert_str(&mut self, pos: usize, s: &str) -> Vec<TextOp>

Insert a string at visible position pos. Returns one op per char.

Source

pub fn delete(&mut self, pos: usize) -> TextOp

Delete the character at visible position pos.

Source

pub fn delete_range(&mut self, range: Range<usize>) -> Vec<TextOp>

Delete a contiguous range of characters.

Source

pub fn set_mark(&mut self, range: Range<usize>, name: &str, on: bool) -> TextOp

Set a boolean mark over a visible-position range. Returns the format op.

on = true adds the mark; on = false removes it (cancels a previous add). When on = true and on = false ops conflict on the same range, the one with the higher OpId wins.

Default anchors are no-expand on either side: chars typed at the span boundaries do not inherit the mark. To get “expand right” (typing extends bold), use Self::set_mark_with_anchors with an explicit anchor referencing the next char.

§Panics

Panics if range.start > range.end or range.end > self.len().

Source

pub fn set_value_mark( &mut self, range: Range<usize>, name: &str, value: Option<&str>, ) -> TextOp

Set a valued mark over a visible-position range. Pass Some(s) to set the value, None to unset (cancel a previous set).

§Panics

Panics if range.start > range.end or range.end > self.len().

Source

pub fn set_mark_with_rule( &mut self, range: Range<usize>, name: &str, value: SpanValue, rule: ExpandRule, ) -> TextOp

Most general format-op API. Set a span with explicit value and stickiness rule.

§Panics

Panics if range.start > range.end or range.end > self.len().

Source

pub fn set_mark_with_anchors( &mut self, start: Anchor, end: Anchor, name: &str, value: SpanValue, ) -> TextOp

Set a mark with explicit anchors. Use this when you want fully-custom stickiness or anchors that aren’t expressible via ExpandRule.

Source

pub fn apply_inverse(&mut self, op: &TextOp) -> Option<TextOp>

Apply the inverse of op as a NEW local op. Use this with a caller-managed undo/redo stack:

let mut undo: Vec<TextOp> = Vec::new();
let mut redo: Vec<TextOp> = Vec::new();
undo.push(text.insert(0, 'H'));   // type
// ... user clicks "undo" ...
if let Some(op) = undo.pop() {
    if let Some(inv) = text.apply_inverse(&op) {
        redo.push(inv);
    }
}
  • Char(Insert) → tombstones the inserted character.
  • Char(Delete) → re-inserts the original character with a fresh OpId.
  • Mark(Set/On) → emits a Mark(Off) over the same anchored range.
  • Mark(Set(s)) → emits a Mark(Unset).
  • Mark(Off/Unset) → no-op (we don’t reconstruct the previous value).

Returns None if the op cannot be inverted (target not in the doc).

Source

pub fn apply(&mut self, op: TextOp) -> Result<(), Error>

Apply a remote operation. Idempotent.

Source

pub fn merge(&mut self, other: &Self)

Merge another Text into this one.

Source

pub fn ops(&self) -> &[TextOp]

All ops in this replica’s log, in observation order.

Source

pub fn ops_since<'a>( &'a self, since: &'a VersionVector, ) -> impl Iterator<Item = &'a TextOp> + 'a

Iterate over ops not yet seen by since.

Source

pub fn spans(&self) -> &[Span]

All format spans (visible + cancelled), sorted by OpId.

Source

pub fn version(&self) -> &VersionVector

This replica’s current version vector.

Source

pub fn iter_with_marks(&self) -> Box<dyn Iterator<Item = (char, MarkSet)> + '_>

Iterate over visible characters paired with their active mark set.

The mark set at each position is computed from the union of all spans containing that position, with later (higher-OpId) spans overriding earlier ones for the same name.

Cost: O(num_chars × num_spans). For typical documents (a few dozen spans) this is fast; for documents with thousands of spans, consider a more sophisticated index.

Source

pub fn render(&self) -> Vec<(char, MarkSet)>

Convenience: collect (char, marks) pairs into a Vec.

Source§

impl Text

Source

pub fn to_delta(&self) -> Vec<DeltaOp>

Export the document as a Quill / Yjs Delta: a sequence of {insert: "...", attributes: {...}} runs where each run is a maximal contiguous span of characters with identical attributes.

This is the format produced by Quill, Y.Text.toDelta(), Slate’s Text adapter, etc. It’s a snapshot — round-tripping through Delta loses the underlying CRDT op log, so a from_deltato_delta round-trip preserves visible content but not history.

Source

pub fn from_delta(replica: ReplicaId, deltas: &[DeltaOp]) -> Self

Build a Text from a Quill / Yjs Delta. Inverse of Self::to_delta.

All marks are added with ExpandRule::None stickiness. Attribute values that don’t match bool or string are skipped.

Trait Implementations§

Source§

impl Clone for Text

Source§

fn clone(&self) -> Text

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Text

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Text

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for Text

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Display for Text

format!("{text}") produces the unformatted character sequence.

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Serialize for Text

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

§

impl Freeze for Text

§

impl RefUnwindSafe for Text

§

impl Send for Text

§

impl Sync for Text

§

impl Unpin for Text

§

impl UnsafeUnpin for Text

§

impl UnwindSafe for Text

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,