docrs-cli 0.3.8

The docrs command: find, replace, review, compare and compose .docx files without disturbing the rest, and convert Markdown or editor HTML to Word with a template.
# Notices and provenance

This repository is a Rust port of the behavior of **paper-docx 0.2.1**
(upstream commit `3c0f9a56c73105564a6a44661c6d058a0d3fc800`,
https://github.com/paper-instruments/paper-docx), which is distributed under
the MIT License:

    Copyright (c) 2013 Steve Canny, https://github.com/scanny
    Portions Copyright (c) 2026 Paper Instruments, Inc.

The full license text is reproduced in `LICENSE`.

## Adapted material

| Path in this repository | Upstream source | Nature of reuse |
| --- | --- | --- |
| `crates/docrs/assets/default.docx` | `src/docx/templates/default.docx` | Verbatim copy (sha256 `2094b5bd…a40d35d`); the blank-document package used by `Document::new()` |
| `crates/docrs/assets/default-{settings,styles,header,footer,comments}.xml` | `src/docx/templates/` | Verbatim copies; parsed like python-docx (`remove_blank_text`) when a missing part is created |
| `crates/docrs/src/difflib.rs` | CPython 3.13 `Lib/difflib.py` (PSF License) | Algorithm port of `SequenceMatcher`/`unified_diff` so outputs match the oracle |
| `crates/docrs/src/unicode/tables.rs` | CPython 3.13 Unicode database (Unicode 15.1) | Generated data tables (`tools/gen_unicode_tables.py`) |
| `crates/docrs/src/p1_pyclass.rs` | CPython 3.13 `str` character classes (Unicode 15.1) | Generated data tables, taken from the pinned oracle |
| `crates/docrs/src/clock.rs` | `src/docx/_clock.py` | Behavior re-implemented in Rust |
| `crates/docrs/src/package/{zip_read,names}.rs` | `src/docx/_zipguard.py` | Validation rules re-implemented in Rust |
| `crates/docrs/src/package/{mod,rels,content_types}.rs` | `src/docx/opc/pkgreader.py`, `_rels.py`, `_contenttypes.py` | Validation rules re-implemented in Rust |
| `crates/docrs/src/package/{diff,patch}.rs` | `src/docx/_paperpkg.py` | Comparison/patch-save semantics re-implemented in Rust |
| `crates/docrs/src/{story,search,normalize,replace,anchor,protection}.rs` | `src/docx/{story,search,_textatoms,_normalize,protection,blocks}.py` | Behavior re-implemented in Rust |
| `crates/docrs/src/{controls,bookmarks,links,notes}.rs` | `src/docx/{controls,bookmarks,links,notes}.py`, `search.py::Span._isolate_edge_runs` | Behavior re-implemented in Rust (P1) |
| `crates/docrs/src/{numbering,blocks,fields}.rs` | `src/docx/{numbering,blocks,fields,_fieldcode}.py` | Behavior re-implemented; the `PaperBulletList`/`PaperDecimalList` definitions are copied from `numbering.py` (P2) |
| `crates/docrs/src/{tableops,styles,formatting}.rs` | `src/docx/{tableops,formatting}.py`, `styles/` | Behavior re-implemented in Rust (P3) |
| `crates/docrs/src/{authoring,image,drawing}.rs` | `src/docx/{document,blkcntnr,text,table,section,image,drawing,shape}` and `oxml/` | Behavior re-implemented in Rust (P4) |
| `crates/docrs/src/{sections,coreprops,styles_write}.rs` and the P7 additions to `authoring.rs` | `src/docx/{section,settings,shared,table,shape}.py`, `parts/{hdrftr,document}.py`, `opc/coreprops.py`, `opc/parts/coreprops.py`, `oxml/{section,settings,coreprops,styles,table,shape}.py`, `oxml/text/{parfmt,font,pagebreak}.py`, `text/{parfmt,tabstops,font,hyperlink,pagebreak}.py`, `dml/color.py`, `styles/` | Behavior re-implemented in Rust (P7); header/footer parts are created from the `default-{header,footer}.xml` templates listed above |
| `crates/docrs/src/composition.rs` | `src/docx/composition.py` (with the `blocks`, `bookmarks`, `_fieldcode`, `fields`, `revision`, `story` helpers it calls) | Behavior re-implemented in Rust (P6) |
| `crates/docrs/src/{compare,textdiff}.rs` | `src/docx/{_compare,_textdiff}.py` | Behavior re-implemented in Rust |
| `crates/docrs/src/{revision,comments,commentops}.rs` | `src/docx/revision.py`, `comments.py`, `parts/comments.py`, `oxml/comments.py`, `commentops.py`, `search.py` (`Span.comment`) | Behavior re-implemented in Rust |
| `tests/fixtures/upstream/` | `tests/paper/fixtures/` | Frozen fixture corpus with its MANIFEST and sidecars, unmodified |

The upstream Python project is used only as a **development oracle** pinned
under the ignored `.reference/` directory, driven by the unpublished
`docrs-compat` harness; nothing in the published crates (`docrs`,
`docrs-cli`) or the npm package calls Python.

## Font metrics

`crates/docrs/src/layout/font_metrics.bin` holds numeric font
metrics only: units per em, vertical metrics, advance widths and pair
kerning values for a set of code points, generated by
`tools/layout/make_font_metrics.py`. It contains no font software, outlines
or other glyph data. The numbers were measured from fonts installed with
macOS and Microsoft Word for Mac and from Office's downloaded cloud fonts
(as decided for this project on 2026-10-20), and from the Liberation Fonts
2.1.5 (Copyright (c) 2012 Red Hat, Inc., SIL Open Font License 1.1), whose
families LibreOffice-made templates name. The font names in the table are
the families' names as documents refer to them; the fonts' trademarks
belong to their owners.