Finding 48 (CWE-407): P::word scanned and copied the rest of an alphabetic run
for every letter that didn't start a function name, so a 20,000-letter
equation did ~200 million steps outside the parser's step budget (5 parses:
8.3 s before, well under 0.1 s after). The scan now stops one past the
longest name in FUNCTION_NAMES (computed at compile time); a longer run is
never a name, as before.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore: resolve SonarCloud maintainability issues
* fix: restore compiling refactors, revert behaviour changes, run cargo fmt
- fontdb::norm: keep the closure for filter (char::is_alphanumeric takes
self, not &self, so it does not fit Iterator::filter).
- story.rs: write_mark_rpr needs &mut self (rev_attrs, rpr_change).
- Revert the viewport meta change and the return 0 added to
workspace_version/sha256, which changed behaviour or masked failures.
- cargo fmt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Import Document in odt page_parts after dropping glob re-export
* fix: apply_kind_properties binds ContentControl; cell_ref keeps char closures
* fix(engine): pass case helpers by value (clippy needless borrows)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Dylan Taylor <dylan@craftmaker.dev>
* WIP for #1609
* Equations: a script after _ or ^ is the whole run of letters and digits (#1609)
Word for Mac 16.113.4: V_dd and V_(dd) build up the same (dd is all
subscript), likewise x^ab, and Linear format shows V_dd bare.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Equations: bare scripts end at a space, digits continue a script run, upright function names (#1609)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Equations: a bare script also ends before a following period (#1609 review)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* ROADMAP: drop three progress rows main already has
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Math: bound the depth the equation parsers build (#1456)
x^1^1^1…, a/a/a… and \sum\sum… built left-nested trees thousands of levels deep within the
input cap; clean, Clone, PartialEq, Drop and serde then overflowed small stacks. Wrapping an
existing node (script base, numerator, accent, limit base, n-ary body) is skipped once it is
already 32 levels deep (iterative check); the operator is text (linear) or dropped (LaTeX).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* Math: escape \text{…} in LaTeX output so it reads back unchanged (#1456)
Normal-text runs were written verbatim, so a}b\c became \text{a}b\c} and read back as ab\c.
Escape \ { } % $ # & _ ~ (backslash as \backslash{}); \backslash is now a named symbol and
raw_arg ignores the empty braces after a control word. A # inside normal text no longer
numbers the equation.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* Math: merge runs inside every structure, not just some (#1456)
merge_runs only recursed into fractions, scripts, radicals, n-ary operators, delimiters and
functions, so the LaTeX parser left \overline{ab} as two runs where the linear parser gives
one. It now recurses through map_args for every node kind.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M5.5: Word equations (OMML) import, lay out and save like Word
Equations were flattened to plain text on import. Now OMML is read into a
math tree (fractions, scripts, radicals, n-ary operators, delimiters,
functions, limits, accents, bars, boxes, equation arrays, matrices,
phantoms), laid out with the OpenType MATH table (Cambria Math when
installed, else STIX Two Math and other open math fonts), drawn to screen
and PDF, and written back as the original OMML. Display equations sit on
their own centred line. insert.equation parses the linear format into
structure.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* M5.5: equation editor like Word's — Equation tab, in-place editing, # numbers
Insert › Equation now opens an equation for in-place editing, with the
Equation tab: ready-made equations, Unicode/LaTeX input and conversion
(professional ↔ linear), Normal Text, eight symbol sets, and the eleven
structure galleries (fraction, script, radical, integral, large operator,
bracket, function, accent, limit and log, operator, matrix) with tiles
rendered by the math engine. Typing builds up like Word (a/b, x^2, √, ∑…
then space), Math AutoCorrect turns \alpha, \sqrt… into symbols, Tab moves
between empty slots, arrows/Backspace work through structures, and the
right-click menu has structure commands (fraction type, radical degree,
limit position, matrix rows/columns, remove brackets…). A trailing #(n)
numbers a display equation with the number at the right margin; # alone
numbers it automatically. DOCX output keeps numbers Word-compatible.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n: equation editor strings in Spanish, Brazilian Portuguese and Ukrainian
The catalogs that landed on main after #191 was opened lacked the Equation
tab and equation command labels.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Equations: our own names and order for the built-in equations
Clean room: the ready-made equation list used another product's gallery entry
names and order. Same formulas (and ids), with our own descriptive labels,
grouped by subject (geometry, algebra, calculus, trigonometry, probability).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ROADMAP: equations row matches the landed equation editor
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fmt after merge
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>