range.fill parsed the input once at the active cell, then put back the old
style of every target that already held a cell, so 5%, $5, 3/4/2026 or
=DATE(...) lost their automatic format there (0.05, 5, 46085), and empty
targets took the active cell's style. Each target now gets what
input_to_cell gives for it (parsed once per distinct style), as typing does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Alt+H, O, A (AutoFit Row Height) and Alt+H, O, I (AutoFit Column Width)
ran nothing when Alt was still held for H, as Excel allows: any key with
Alt down cancelled keytips. KeyTips now tracks the left Alt key, and a
letter typed with it held that continues a known sequence is handled as
a keytip letter. Other Alt combinations still cancel; AltGr (right Alt)
and macOS Option are unchanged (#1864).
fr.rs and sr.rs translated three `context|label` keys with the context
kept ("Options|Général", "Opcije|Opšte", "Options de la feuille|Affichage"
...). `Language::tr` shows a found translation as it is, so File › Options
section headings and the Sheet Options "View" checkboxes showed the prefix.
The values now hold only the label.
Tests: `translations_never_show_the_context_prefix` (no catalog shows a `|`
for any key) and `translated_options_headings_show_no_context_prefix`
(File › Options in French and Serbian); both fail on main.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
rowGrandTotals is the Grand Total row under the report and colGrandTotals the
Grand Total column at its right. Both were mapped the other way round; a
GridCraft round trip hid it, but an Excel file with only one grand total opened
with the other one.
file.open takes {csvAsText: true}: a CSV, TSV or TXT file opens with every field as the text
it holds, with no number, date or boolean conversion, so identifiers such as GTINs, SKUs and
ZIP codes keep their digits and leading zeros and save back unchanged. The default is
unchanged. The CsvOptions.parse_values switch already existed in the reader.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Adds Language::Vi (vi), following the per-language module pattern (crates/ui-egui/src/i18n/<lang>.rs). All 398 strings in the master table are covered, checked by the completeness test; vi-VN locale tags resolve to Vietnamese.
egui's bundled fonts have no Lao, and none of the script fallback faces
(CJK, Thai, Hebrew, symbols) carry it on macOS, so Lao text in a cell,
the formula bar or the interface drew as boxes unless the cell's own font
had Lao glyphs. Add a `sys-lao` fallback: Leelawadee UI / DokChampa on
Windows, Lao Sangam MN / Lao MN on macOS, Noto Sans Lao / Phetsarath OT
on Linux. `fallback_covers_its_script` now checks a Lao sample.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Checked black-box in Excel for Windows (Microsoft 365) with synthetic
workbooks: a bare name in <c:f> draws the whole chart blank, without a
repair prompt, for workbook- and sheet-scoped names alike, while
`[0]!Name` and `Sheet1!Name` plot.
- Write: a sheet-scoped name is written `Sheet!Name` (quoted when
needed) instead of bare; an already qualified name keeps its sheet;
an undefined name gets `[0]!`. A reference to an unknown sheet is
kept as written. A qualified series name is written as a strRef.
- Resolve: a series name `Sheet1!Name` is looked up on that sheet, as
the evaluator does, instead of being shown as literal text.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Excel writes a workbook-scoped defined name in a chart reference as
`[0]!Name`. The reader kept that text, the lexer took `[0]` for a
structured reference, and the series evaluated to #NAME?: a chart over
dynamic (OFFSET) names opened blank with one #NAME? category.
- Read: `[0]!Name` becomes `Name` in c:f (cat, val, xVal, yVal,
bubbleSize, tx), chartex cx:f and _xlchart names. External books
([1]Sheet1!...), quoted sheet names and strings are untouched.
- Write: a bare workbook-scoped name is written back as `[0]!Name`; a
sheet-scoped name stays bare. A series name that is a defined name is
written as a strRef instead of literal text.
- Resolve: a series name that is a defined name is evaluated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A line that is not a JSON object with a string method, including an HTTP
request line, bytes that are not UTF-8 or a line over 64 MiB, gets one
error reply and the connection closes before anything after it is read.
Request lines are read with a bound instead of buffering them whole.
A hostile file could abort any process that opens it: a cell formula of a
million `%` (`1%%%…`) or a 200,000-term sum parsed into trees deep enough to
overflow the stack when printed, saved, evaluated or dropped, even in release
builds. Postfix operators (`%`, invoking a result) built their nesting in a
loop that the 256-level limit did not see.
- `parse` refuses formula text longer than Excel's 8,192 characters
(`MAX_FORMULA_LEN`, counted in characters, the leading `=` excluded). This
also bounds the depth of the left-deep trees long operator chains build.
- Each postfix `%` and each call of a result counts towards the nesting limit.
- A file's formula that is refused keeps its text and cached value, as other
unparsable formulas do.
Regression tests: formula (small-stack thread: long `%`, invoke and operator
chains are errors; the limit counts characters, not bytes) and xlsx
(`hostile_formula_text_does_not_overflow_the_stack`: open, save and drop a
workbook with such formulas and a defined name on a 1 MiB stack). Both abort
with a stack overflow without the fix.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The argument hint, autocomplete, Insert Function and the Formulas-tab menus
read per-language tables of function descriptions and argument names
(i18n/<lang>_functions.rs), keyed by the catalog's English text and
binary-searched. The hint is assembled from the formula syntax's function
name and separator plus the language's argument names, all of them or none,
so it never mixes two languages. Insert Function searches the translated
descriptions and shows readable category names. SPANISH_HELP moves to
es_functions.rs with its 10 functions.
OK runs a dialog's command with build_params(&d), which reshapes the
field values for several dialogs (the rule wrapper of cfQuick, the
delimiters list of Text to Columns, the columns of Remove Duplicates and
Subtotal, Data Validation's unused fields, Zoom presets, Series, Define
Name). ui.dialog.confirm passed the raw field values instead, so a
Highlight Cells rule confirmed over the control channel added nothing
and Text to Columns ignored the ticked delimiter.
Make build_params pub(crate) and use it from ui.dialog.confirm, say so
in the control protocol doc, and add tests driving the Greater Than and
Text to Columns dialogs over the control channel.
Adds Language::It ("it", native name "Italiano") with a new per-language
module crates/ui-egui/src/i18n/it.rs, following the existing pattern
(translate(text) -> Option<&'static str>). The catalog has 971 entries:
every key the most complete catalog (pt) translates, plus the PivotTable
Fields pane strings (from es) and Options|Editing. Labels follow Excel's
Italian terminology (Foglio, Cartella di lavoro, Blocca riquadri, Unisci e
allinea al centro, Somma automatica...). Function names are not touched.
Also: it / it-IT / it_CH tags resolve to Italian (system-language default),
Language::ALL and the coverage/tag/age tests include Italian, and
docs/localization-parity.md lists the new language.
Not compiled locally (no Rust toolchain on the author's machine); relying on CI.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Prepare report data before editing so refused reports cannot leave solution cells or the saved model changed. Commit accepted reports with the optional solution and model, retaining array/protection checks and row autofit after sheet insertion.
Closes#1050
Co-Authored-By: OpenAI Codex <noreply@openai.com>
A formula read with `cm` (Excel's XLDAPR dynamic-array record in
xl/metadata.xml) now carries `Formula::dynamic`, and the writer keeps the
`cm` and the metadata part for it even when the formula returns one value
and the export shape analysis would not need array evaluation. Before, such
formulas were saved as legacy formulas, so Excel recalculated some of them
with implicit intersection (SUMPRODUCT(IFERROR(range/range,0)) changed
value), and workbooks whose every dynamic formula was scalar lost
xl/metadata.xml altogether.
The mark survives moves, row and column insertion or deletion, sheet and
name renames and LAMBDA call-case fixes; retyping a formula drops it and
the writer decides from the formula's shape, as before. It is serialized
only when set, so saved documents without it are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>