#text #document #model #format


Text document structure and management

5 releases

0.0.5 Jul 4, 2022
0.0.4 Jul 1, 2022
0.0.3 Jul 1, 2022
0.0.2 Jul 1, 2022
0.0.1 Jun 30, 2022

#381 in Data structures


3.5K SLoC

crates.io API license build status codecov Lines of code


A text document structure and management for Rust

This model is thought as a backend for a text UI. [TextDocument] can't be modified directly by the user, only for setting the whole document with set_plain_text(...). The user must use a [TextCursor] using document.create_cursor() to make any change.

Document structure


  • [Frame]: contains Block elements and other Frame elements, formatable with FrameFormat
  • [Block]: contains Text elements or Image elements, formatable with BlockFormat
  • [Text]: contains the actuel text, formatable with TextFormat
  • [Image]: represent the position of an image, formatable with ImageFormat

All these items are encapsulated in its corresponding [Element] for ease of storage.

The simpler plain text

|- Block
   |- Text
|- Block
   |- Text

The more complex rich text

|- Block
   |- Text  --> I really lo
   |- Text  --> ve (imagine it Formatted in bold)
   |- Text  --> Rust
   |- Image
   |- Text
|- Frame
   |- Block
      |- Text
      |- Text
      |- Text
   |- Block
      |- Text
      |- Text
      |- Text
|- Block
   |- Image

Signaling changes

Each modification is signaled using callbacks. [TextDocument] offers different ways to make your code aware of any change:

  • [TextDocument::add_text_change_callback()]

    Give the number of removed characters and number of added characters with the reference of a cursor position.

  • [TextDocument::add_element_change_callback()]

    Give the modified element with the reason. If two direct children elements changed at the same time.


use text_document::{TextDocument, ChangeReason, MoveMode};

let mut document = TextDocument::new();

document.add_text_change_callback(|position, removed_characters, added_characters|{
  println!("position: {}, removed_characters: {}, added_characters: {}", position, removed_characters, added_characters);
} );

document.add_element_change_callback(|element, reason|{
  assert_eq!(element.uuid(), 0);
  assert_eq!(reason, ChangeReason::ChildrenChanged );
} );

let mut cursor = document.create_cursor();
cursor.set_position(9, MoveMode::MoveAnchor);



Licensed under either of

at your option.


Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.


~34K SLoC