mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-12 08:52:32 +00:00
* Add craft-math: the equation tree with OMML, MathML, LaTeX and UnicodeMath
The math tree, LaTeX, linear-format, symbol and tree-walk modules come
from craft-wordmodel (storytold/craft-libs#963, WordCraft's crates/doc at
07f97737) unchanged, with the run colour (Rgb) and the symbol-font tables
they use. MathML is WordCraft's crates/formats/src/mathml.rs and OMML is
WordCraft's crates/docx/src/read/math.rs and write/math.rs (06c2ae6f /
07f97737), moved onto craft-xml. The HTML-specific MathML tests stay in
WordCraft; the rest moved with the code.
mathml::parse and omml::parse/read_str/write_str are new: string entry
points for callers that have no tree of their own.
* craft-math: read MathLive's and other spellings of LaTeX math commands
\abs{...} (an absolute value), \lvert \rvert \lVert \rVert, \nparallel,
\backprime, \infinity, \cross, \differentialD, \exponentialE and
\imaginaryI (MathLive's d, upright e and i), \emph, \textsf, \hbox,
\mathnormal and \underleftarrow / \underrightarrow /
\underleftrightarrow were unknown and read as literal text. They are read
as equaSHion's typed-input parser reads them (storytold/craft-libs#29).
* craft-math: equaSHion's equation corpus as test data
corpus/equations.tsv, corpus/latex.tsv and the OMML samples of
storytold/craft-libs#29 (7a6ef6b9), unmodified.
* craft-math: corpus round trips, GridCraft's OMML cases, entry points and limits tested; README
The corpus equations go through OMML, MathML and LaTeX and back; the OMML
samples are written back as kept and from the tree. GridCraft's OMML to
LaTeX test cases (crates/xlsx/src/omml.rs) give LaTeX that reads back the
same through the tree. omml::parse and read_str are tested against other
prefixes, the strict namespace, kept OMML, junk, the element cap and deep
nesting.
---------
Co-authored-by: shuff57 <62350898+shuff57@users.noreply.github.com>
56 lines
2.8 KiB
Markdown
56 lines
2.8 KiB
Markdown
# craft-math
|
|
|
|
Equations as one tree, and the syntaxes it is read from and written to:
|
|
|
|
| Module | Syntax | Read | Write |
|
|
| --- | --- | --- | --- |
|
|
| `math` | the tree: `MNode`, `MRun`, `Math` (an equation with its kept source OMML), modelled on the Office Math object model (ECMA-376 Part 1 §22.1) | | |
|
|
| `math_linear` | UnicodeMath, the linear format Word shows (`x=(-b±√(b^2-4ac))/2a`) | `math::parse_linear` | `math::to_linear` |
|
|
| `math_latex` | LaTeX math, including MathLive's spellings | `parse_latex` | `to_latex` |
|
|
| `omml` | Office Math Markup (`m:oMath`, DOCX/PPTX/XLSX) | `read_omath`, `read_str` | `write_equation`, `write_str` |
|
|
| `mathml` | presentation MathML (HTML, ODF formulas, the clipboard) | `parse`, `read`, `to_tree` | `to_mathml`, `linear_to_mathml` |
|
|
|
|
Beside them: `math_symbols` (LaTeX names of symbols), `math_tree` (the arguments of a node, a walk
|
|
over every run), `symbol_fonts` (Symbol, Wingdings and the other symbol fonts as Unicode) and
|
|
`Rgb` (a run's colour).
|
|
|
|
```rust
|
|
use craft_math::{Math, math, math_latex, mathml, omml};
|
|
|
|
let tree = math_latex::parse_latex(r"\frac{a}{b}+\sqrt{x}");
|
|
assert_eq!(math::to_linear(&tree), "a/b+√x");
|
|
|
|
// OMML out and back.
|
|
let eq = Math { nodes: tree.clone(), ..Default::default() };
|
|
let xml = omml::write_str("", false, &eq, None);
|
|
let read = omml::read_str(&xml).unwrap();
|
|
assert_eq!(read.nodes, tree);
|
|
|
|
// MathML carries the linear format in an annotation, so it reads back exactly.
|
|
let ml = mathml::linear_to_mathml("a/b+√x", true);
|
|
assert_eq!(mathml::parse(&ml).and_then(|m| mathml::read(&m)), Some(("a/b+√x".to_string(), true)));
|
|
```
|
|
|
|
## Reading OMML
|
|
|
|
`omml::read_omath` takes an `m:oMath` element of a `craft_xml` tree read with the canonical
|
|
prefixes of `omml::NAMESPACES` (`m`, `w` and `mc`, transitional and strict URIs), so a document
|
|
reader passes the element it already has. `omml::read_str` and `omml::parse` read a string. The
|
|
source XML is kept in `Math::omml`; `write_equation` writes it back unchanged while the
|
|
equation's colour is the same and the XML is well formed, so a saved document carries the
|
|
equation as Word wrote it.
|
|
|
|
## Limits
|
|
|
|
Nesting is bounded by `math::MAX_DEPTH` in every reader and writer; `omml::parse` reads at most
|
|
`omml::MAX_ELEMENTS` elements and `mathml::parse` keeps at most `mathml::MAX_NODES`; the LaTeX
|
|
reader looks at 20,000 characters. Nothing panics on any input.
|
|
|
|
## Provenance
|
|
|
|
The tree, the linear format, LaTeX, the symbol names, the tree walk, the symbol fonts and `Rgb`
|
|
are WordCraft's (`crates/doc`), as moved into craft-wordmodel; OMML is WordCraft's DOCX reader
|
|
and writer (`crates/docx/src/read/math.rs`, `write/math.rs`) and MathML its formats crate's
|
|
(`crates/formats/src/mathml.rs`), moved onto craft-xml. The MathLive command spellings and the
|
|
round-trip corpus in `tests/corpus/` come from equaSHion (storytold/craft-libs#29).
|