Files
Dylan M. Taylor 08882273d1 Add craft-wordmodel: WordCraft's document model without its editing code (#963)
* Add craft-wordmodel: WordCraft's document model without its editing code

WordCraft's crates/doc (wordcraft-doc, at 07f97737) moved as it is, so the DOCX,
RTF, ODT and other text-format crates can read into and write from one model.
Module paths, type names and serde attributes are unchanged: an app that
re-exports the crate keeps its native file format.

Left in the app: range editing (edit.rs), IME text and equation editing. Not
model, and already in craft-libs: code pages (craft-rtf), the ZIP entry-count
check (craft-opc), the compound-file guard (craft-cfb). The paragraph walks
moved to walk.rs and the unit helpers of wordcraft-geom to geom.rs.

* craft-wordmodel: math_tree, the arguments of an equation node and a walk over its runs

The DOCX reader and writer walk an equation's runs. The walk and the child
accessors it uses were in WordCraft's equation editor (math_edit.rs), which
stays in the app; they are structure, not editing.

* craft-wordmodel: keep the document operations (edit.rs) with the model

The DOCX and RTF readers use them: alternative-format chunks are merged into
a document with adopt_blocks, and a reader formats ranges with format_range
and inserts objects. They operate on the document, not on a view, so they
belong beside it. The tests that drove them come back with them; the
paragraph walks stay in walk.rs and edit re-exports them.

base64 0.23, as WordCraft and craft-offcrypto use.
2026-11-11 19:43:08 -05:00
..

craft-wordmodel

A word-processing document model: stories, paragraphs, runs, tables, sections, styles, numbering, fields, content controls, notes, comments, revisions, floating objects, drawings and math. It is what the DOCX, RTF, ODT and other text-format crates read into and write from.

It is WordCraft's document model (crates/doc), moved without its editing code. Module paths, type names and serde attributes are as they were, so an app that re-exports the crate keeps its native file format.

use craft_wordmodel::{Block, Document};

let doc = Document::from_text("One\nTwo");
assert_eq!(doc.body.len(), 2);
assert!(matches!(&*doc.body[0], Block::Para(p) if p.text == "One"));

What is here

  • Document: the body story, secondary stories (parts: headers, footers, notes, comments, text boxes), the style sheet, list definitions, comments, revisions, settings, document properties, media and parts kept from the source file.
  • Block, Paragraph, Run, InlineObject, Table: the content. Paragraph text is UTF-8; an inline object stands in the text as U+FFFC (para::OBJ).
  • props, styles, resolve, numbering, section: formatting and its resolution.
  • math, math_latex, math_linear, math_symbols: the equation tree (MNode) and its linear and LaTeX forms.
  • chart, smart_art, graphic, fill, connector, freeform, wordart, effects, picfx, line_dash: drawing objects as the model holds them. Reading and writing their DrawingML is craft-drawingml's job, in the format crates.
  • kept: markup kept from the file a document was read from, so what is not edited is written back as it was.
  • walk, work, geom, bidi, cluster, collate, locale_number, symbol_fonts.

Not here

Range editing, copy and paste, IME text and equation editing stay with the app that edits. Code pages are craft-rtf's codepage, the ZIP entry-count check is craft-opc's.

Limits

The model carries the limits its readers rely on: nesting of tables (table::MAX_TABLE_DEPTH), text boxes (MAX_TEXT_BOX_DEPTH, BoxBudget), math (math::MAX_DEPTH, matrix sizes), group children, alt text length, linked boxes and the walk depth (PARA_WALK_DEPTH). Their tests moved with them.