Commit Graph
1777 Commits
Author SHA1 Message Date
aiongg 34de196c9f Merge PR #1119: Fix xlsx: combine escaped UTF-16 surrogate pairs when decoding strings (#1025) 2026-10-22 02:34:35 +00:00
aiongg a0a4b6a7d0 Merge PR #1105: Fix row keys merging distinct text rows in UNIQUE and grouping (#1012) 2026-10-22 02:34:35 +00:00
aiongg 2c22070a62 Merge PR #1060: LAMBDA helpers: #CALC! for nested arrays, #VALUE! for wrong parameter counts 2026-10-22 02:34:35 +00:00
aiongg 307b25dc92 Merge PR #488: Build: the ui-egui build script reads CARGO_MANIFEST_DIR when it runs 2026-10-22 02:34:34 +00:00
aiongg a48f418a77 Merge PR #831: i18n: test that translations keep the shape of their English 2026-10-22 02:34:34 +00:00
aiongg df39416e36 Merge PR #1115: Cap CSV import fields per record at the worksheet column limit (#1037) 2026-10-22 02:34:34 +00:00
aiongg 340ce131ef Merge PR #1340: calc: calculate long dependency chains with bounded stack 2026-10-22 02:34:33 +00:00
aiongg 136a8fa07e Merge PR #1337: Selection: whole columns and rows don't widen to merged cells 2026-10-22 02:34:33 +00:00
aiongg ec5e939677 Merge PR #1104: xlsx: keep the first group's series kind when importing a combination chart (#1014) 2026-10-22 02:34:33 +00:00
aiongg a4c53ad020 Merge PR #1061: Recalc: an array that spills as before doesn't requeue its dependents 2026-10-22 02:34:33 +00:00
aiongg 954f30f9f4 Merge PR #1058: Format Cells: take the documented camelCase style keys 2026-10-22 02:34:33 +00:00
aiongg f8f7193f52 Merge PR #1084: Data validation: a list typed without quotes is saved as a quoted list, and an unknown type is refused 2026-10-22 02:34:32 +00:00
aiongg 0288ad2f31 Merge PR #630: Cap queued pointer events from ui.click/ui.drag control requests (#525) 2026-10-22 02:34:31 +00:00
aiongg 9aed6fb534 Merge PR #1102: CSV export: check the size cap before each field, not after the row (#1023) 2026-10-22 02:34:31 +00:00
aiongg f295fa0947 Merge PR #629: Make check --json list warning messages instead of a count (#526) 2026-10-22 02:34:30 +00:00
Higgs32584andClaude Opus 5.5 06b7d09a7e clipboard: drop wall-clock timing from span test (clippy)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 21:28:47 -04:00
Higgs32584andClaude Opus 5.5 5392d95bf8 scripts: require workbook trust before running embedded scripts (#2178)
A workbook opened with GridCraft scripts (`_sc_scripts`) starts untrusted:
automate.runScript refuses them until the user trusts the workbook for the
session (Macros dialog > Trust Scripts, i.e. automate.trustScripts) or the
caller passes `trusted: true` for that one run. Workbooks without scripts,
and scripts written in the session, are unaffected.

Whatever the trust, a script whose steps reach outside the workbook
(file.*, link.*, or any `path` param: Get Data, From Text/CSV, Insert
Picture) is refused before any step runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 21:13:13 -04:00
Higgs32584andClaude Opus 5.5 b817c04a9b clipboard: bound HTML colspan/rowspan expansion (#2171)
Clipboard HTML is read only as far as the pasted text's shape (clamped
to the sheet) and at most 1,000,000 cells; colspan/rowspan are clamped
to the sheet extent before expanding, and rowspan now keeps later rows
in their columns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 21:06:51 -04:00
Higgs32584andClaude Opus 5.5 836b269806 calc: cap array broadcast result size (#2182)
zip2 (binary operators, TEXT), zip3 (array IF) and MAP now compute the
broadcast cell count with checked multiplication and return #NUM! when it
exceeds MAX_CELLS, instead of allocating (abort) or wrapping on wasm32.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 20:27:26 -04:00
Higgs32584andClaude Opus 5.5 5b908c04f8 core: iterative number coercion for nested parentheses (#2180)
Parenthesised negatives were parsed by recursing once per level, so runtime
text such as REPT("(",32767)&"1"&REPT(")",32767) overflowed the stack. Strip
the parentheses in a loop, toggling the sign per level; results are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 20:24:15 -04:00
Higgs32584andClaude Opus 5.5 be94b011c5 calc: bound SUBTOTAL/AGGREGATE input work (#2175)
Every area, array and value of one SUBTOTAL/AGGREGATE call is charged against MAX_CELLS before any cell is read; past it the call returns #NUM!. A value stored in XFD1048576 no longer makes SUBTOTAL(9,A:XFD) read ~17 billion cells into a vector.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 20:10:00 -04:00
Higgs32584andClaude Opus 5.5 e1b8aad143 calc: cap LINEST-family regressor matrices (#2177)
LINEST, LOGEST, TREND and GROWTH built k x k normal-equation matrices
(plus two copies in sym_inverse, O(k^3)) with k taken straight from the
known_xs shape, so one formula could allocate gigabytes and abort on open.
More than 255 predictors is now #VALUE!, and more than 1e9 rows x k^2
multiply-adds is #NUM!, both checked before any allocation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 20:07:30 -04:00
Dylan M. Taylor 912b817abe security: enforce HTTPS on curl downloads (SonarCloud S6506) (#2188)
Add --proto '=https' to curl invocations so redirects cannot downgrade to
plaintext HTTP. Resolves SonarCloud S6506 (shell/docker/githubactions).
2026-10-21 19:36:04 -04:00
Francisco Herrera c3184b74f9 Address CodeRabbit review: borrow the workbook and keep both swatch outlines (#2148) 2026-10-21 15:16:30 -05:00
Dylan M. Taylor 8ae67c5534 ci: add sonar-project.properties for CI-based analysis
Marks the project ineligible for SonarCloud Automatic Analysis, resolving the
CI-vs-automatic-analysis conflict so the SonarCloud workflow succeeds.
2026-10-21 16:00:41 -04:00
Dylan M. Taylor eb48beffb5 ci: add SonarCloud scan via shared reusable workflow
Calls storytold/craft-common-actions/.github/workflows/sonarcloud.yml@main
with secrets: inherit. Adds SonarCloud badge to README where missing and
removes the redundant sonar-project.properties (config now passed by the
reusable workflow).
2026-10-21 15:47:00 -04:00
Francisco Herrera a9223eabf8 Table Design: draw the Table Styles gallery in the ribbon (#2148) 2026-10-21 14:44:47 -05:00
Ufuk Efe 7ba381d9ae i18n: Turkish (tr) interface language 2026-10-21 21:22:19 +03:00
Aimar Mendez 0812d3aee5 PivotTable Fields pane: scan the source once per change, not every frame
The pane ran `pivot.fields` on every frame while the active cell was in a
PivotTable report. That command reads the whole source list and collects
distinct labels for every field, so a 250,000 x 20 source made each frame
cost ~2.4 s and the window looked frozen (#2113).

Keep the answer in GridState, keyed by (doc uid, revision, pivot), the way
Page Break Preview keeps its pages. Any undoable edit, undo or redo bumps
the revision and drops it.

Known limit: Calculate Now / Calculate Sheet don't bump the revision, so
volatile formulas in the source can leave the tooltip samples stale until
the next edit; the field list itself only changes through undoable edits.

VERIFIED
- New test pivot_fields_pane_reuses_its_field_list_until_the_workbook_changes
  fails without the change and passes with it.
- Release build, 250,000 x 20 synthetic source, pane open (ui.inspect):
  main ~2,400 ms per frame throughout; this branch 2,528 ms for the first
  frame, then 0.4-0.9 ms.
- `cargo xtask ci` passes all 8 steps on macOS with the separate clippy
  fix from #2141 applied locally (main fails clippy on macOS without it).

NOT IN THIS CHANGE
- The report is still empty after opening a file saved with
  refreshOnLoad="1" (second part of #2113).
- `pivot.fields` itself is unchanged; the first frame still pays one scan.
2026-10-21 19:03:36 +01:00
Brandon ThomasandClaude Opus 5.5 2ebdf164c2 Release 0.10.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v0.10.0
2026-10-21 13:57:26 -04:00
midasdf b092633561 Print: Japanese Envelope #4 is 90×205 mm and add B6 (ISO) to the Size menu
長形4号 is a 90×205 mm envelope (90×225 mm is 長形40号, a different one), so
the paper table gave it a height 20 mm too tall — and XLSX paper id 74, the PDF
MediaBox and the print preview all followed it. Use 205 mm (581.10 pt) and pin
the corrected size with a dedicated assertion; the ROADMAP progress row is
corrected too. 長形40号 is not added: it is a different envelope.

The Page Layout ▸ Size menu stopped at `B5 (ISO)` and never offered
`B6 (ISO)`, which the engine and the command docs support; add it.
2026-10-22 00:24:30 +09:00
midasdf f91f7c05d4 Print: JIS B4/B5/B6 and Japanese paper sizes
Japanese Excel's B4/B5/B6 are the JIS sizes (257×364, 182×257 and 128×182 mm),
but Page Setup's `b4`/`b5` were the ISO ones (250×353, 176×250): a Japanese B5
worksheet printed 8 mm narrow. `known_paper` now reads `B4`/`B5`/`B6` as JIS and
keeps the ISO sizes reachable as `B4 (ISO)`/`B5 (ISO)`/`B6 (ISO)`. This also
fixes the XLSX round-trip, whose `paperSize` ids 12/13 are the JIS sizes.

Adds the Japanese papers Page Setup lacked: Japanese Postcard (はがき,
100×148 mm), Japanese Double Postcard (往復はがき, 148×200 mm), Japanese
Envelope #3/#4 (長形3号/4号, 120×235 and 90×225 mm), Japanese Envelope Kaku
#2/#3 (角形2号/3号, 240×332 and 216×277 mm), A6, and aliases such as
`postcard`, `chou #3`, `kaku #2`; the xlsx paper table gains ids 42 (ISO B4) and
43/69–74/88 so these names survive save and reopen (the ISO B5/B6 names have no
ECMA-376 paper id and stay engine-side).

The pageSetup/pageLayout.size parameter docs list the names, the Page Layout
Size menu lists them, and tests pin the point sizes, the PDF MediaBox for A4
(unchanged), B5, postcard, double postcard and kaku #2, landscape and
fit-to-page, the unknown-name Letter fallback, and the XLSX round-trip.

Docs: docs/target-app-parity.md print row + revision history, and ROADMAP.md
progress log, dated 2026-10-21.
2026-10-21 23:38:26 +09:00
midasdf 97aa04dc80 i18n(ja): add the §11 revision row and align the docs header dates
The Japanese catalog's ribbon labels the review flagged are already in the head
("Save (⌘S)" is 上書き保存 (⌘S), "Insert\nSlicer" is スライサーの\n挿入, and the
catalog test asserts the new value), so only the docs needed work: docs/gaps.md
had no revision row for the §11 Japanese-catalog update. Add one dated
2026-10-20, and set the "Last updated" header of ROADMAP.md, docs/gaps.md and
docs/localization-parity.md to the same date as their new rows. Every existing
revision row keeps its original date.
2026-10-21 22:51:09 +09:00
midasdf e42ebf9311 XLSX: keep a phoneticPr that has no rPh runs, and document the limits
si_body returned as soon as no valid run was written, so a shared string with a
<phoneticPr> and no <rPh> — a shape §18.4.8 allows — lost its properties on
save even though the reader keeps them. The runs and the properties are now
written independently: valid runs as before, then the valid <phoneticPr> when
the workbook has one; with neither, the <si> is exactly the plain t_el output.
property_only_shared_string_survives_open_and_save covers read, save and
reopen, and the si_body damaged-data test now expects the property-only output.

The write-time checks the reader also runs (sb/eb clamped into the UTF-16
length, empty readings skipped, type/alignment filtered through the shared
PHONETIC_KINDS/PHONETIC_ALIGNMENTS) were already in the head; the tests above
pin them, so no further change there.

Docs: the .xlsx row and the revision history now state that the shared string
table holds each text once, so duplicate <si> items with the same text but
different readings keep only the first reading (reported as a warning on open),
and that a <phoneticPr> without runs is kept. Both parity docs' "Last updated"
headers match their 2026-10-20 revision rows; the earlier rows keep their dates.
2026-10-21 22:35:13 +09:00
Lord-Taw 377bb9226e Update i18n.rs
## CI Validation

`cargo xtask ci` completed successfully.

<details>
<summary>Build Warning</summary>

```text
warning: variants `At` and `Unknown` are never constructed
   --> crates\ui-egui\src\backstage.rs:416:5
```

This warning appears to be pre-existing and is unrelated to the changes introduced in this PR. As it falls outside the scope of the current work, no changes were made to address it.

</details>

The build completed successfully, including the `wasm32-unknown-unknown` target checks.

```text
wasm32-unknown-unknown check (gridcraft-calc, gridcraft-chart, gridcraft-core, gridcraft-engine,
gridcraft-formula, gridcraft-functions, gridcraft-model, gridcraft-numfmt,
gridcraft-pdf, gridcraft-web, gridcraft-xlsx): ok
```

<details>
<summary>CI Parity</summary>

```text
CI summary:
  ok    fmt
  ok    clippy
  ok    test
  ok    assets
  ok    layers
  ok    wasm
```

</details>
2026-10-21 10:24:12 -03:00
Nikolai Nyegaard c812881fa9 Backstage: list the languages alphabetically by their own name
- English (and Auto where offered) stays first as the source language and fallback; the rest sort by native name with accents folded, so Čeština is under C and Magyar under M; Cyrillic and CJK names follow the Latin ones
- The list used the registry order, which is the order the languages were added
2026-10-21 12:01:41 +02:00
Viorel ToaderandClaude Opus 5.5 c26290cd04 Show form notes that contain a pipe as they are
tr reads | as a context separator, so translating the Open Hyperlink note
cut a URL with a pipe down to the part after it. Notes carry user data
(URLs, file and sheet names); one with a pipe is now drawn verbatim.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JadgGo4G2GHaAMNb3qyygk
2026-10-21 11:13:57 +03:00
Viorel ToaderandClaude Opus 5.5 43e64c50a2 Romanian: print settings and status, five form labels; Page Setup… matches its dialog
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JadgGo4G2GHaAMNb3qyygk
2026-10-21 10:57:20 +03:00
Viorel ToaderandClaude Opus 5.5 8e38fc21fa Romanian: feminine stângă/dreaptă for the margin labels
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JadgGo4G2GHaAMNb3qyygk
2026-10-21 10:57:20 +03:00
Viorel ToaderandClaude Opus 5.5 028a02ba72 Romanian (ro) interface language
Adds Romanian as an interface language: crates/ui-egui/src/i18n/ro.rs with 970 labels covering
every key of the other catalogs, registered in Language (switcher, app.language.set, ro-* system
locales). Context keys translate without their prefix; the File › Options kittest covers ro.
English formulas and formats; no proofing.

The catalog is an AI-assisted draft written from the meaning of the English labels; a native
speaker has not yet reviewed it line by line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JadgGo4G2GHaAMNb3qyygk
2026-10-21 10:57:20 +03:00
Viorel ToaderandClaude Opus 5.5 29adb19872 Translate form-dialog field labels, choices and notes
Page Setup, Insert and the other form dialogs drew their field labels in
English in every interface language, though their titles and OK/Cancel
were translated and most catalogs already carry the labels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JadgGo4G2GHaAMNb3qyygk
2026-10-21 10:57:10 +03:00
Dylan M. Taylor 37e41424ed Merge pull request #1620 from dylanmtaylor/ci/shared-nix-workflow
ci: switch to shared nix workflow from craft-common-actions
2026-10-21 03:40:22 -04:00
Gert Pellin a35d241caf XLSX: a note keeps its box's place and size through open and save (#1608)
The reader took only <x:Visible/> from a note's VML shape and vml_xml
wrote every note with a fixed anchor (two columns right of the cell,
four rows tall) and a 108 x 59.25 pt style, so a plain open and save
moved and resized every note box Excel had stored.

Comment gets an optional NoteBox: the <x:Anchor> corners relative to the
note's cell (so the box follows the note when rows or columns move) and
the shape's width and height. The writer puts it back, clamped to the
sheet; notes made here, and boxes equal to the default, keep the
default box.
2026-10-21 09:20:06 +02:00
kezmdorandClaude Opus 5.5 d1ab0ea85d Merge upstream main (0.9.0) into fix/2030-incomplete-formula-error
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 09:16:47 +02:00
chessiveandClaude Opus 5.5 a4a36e8460 Fonts: a cell font named in another language matches its installed font (fixes #1898)
Korean Excel saves a cell's font under its Korean name (맑은 고딕 for
Malgun Gothic), but the font scan kept one family name per face, the
English one, so those cells were drawn in the default face. Each face now
keeps its typographic and legacy family names in every language, and a
workbook font is bound under the name the workbook uses, which is the
name cell_family looks up. A name two families share goes to the family
whose English name it is, else to the first face by path, so the scan's
directory order no longer decides it. Names bound under two spellings
share one copy of the font data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 14:45:39 +09:00
ZaxaerithandCodex 1abb771f58 docs: fix Trunk website link (#2076)
Co-Authored-By: Codex <noreply@openai.com>
2026-10-21 12:43:15 +08:00
dantebertuzziandClaude Opus 5.5 68f956a410 Number Stored as Text: green indicator, warning button and Convert to Number (#1994)
Numbers stored as text are skipped by SUM and friends, and GridCraft gave
no hint. Like Excel's background error checking, a constant whose text
would be a number if typed now gets a green triangle in its top-left
corner; with such a cell active, a warning button beside it opens a menu
naming the problem with Convert to Number, which converts every flagged
cell in the selection as one undo step.

- core: `parse::number_stored_as_text` (signs, thousands separators,
  currency, percent, exponent, one parenthesised negative). Dates, times
  and fractions kept as text are not flagged, as in Excel.
- engine: `cmd::formulas::number_stored_as_text(cell)` (constants only,
  not formula results) and `formulas.convertToNumber {range?}`, which
  keeps each cell's format.
- ui: the triangle in the grid and the warning button with its menu;
  pt-BR and German strings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 21:39:30 -03:00
dantebertuzziandClaude Opus 5.5 bdc0552a92 Dialogs: OK and Cancel in a row, so form dialogs fit their content
`ok_cancel` put the buttons in a right-to-left layout straight in the
window. That layout takes all the height it is offered, so every form
dialog (Greater Than…, New Name, Remove Duplicates, …) grew to the
screen's height with OK and Cancel floating halfway down. The buttons
now sit in a horizontal row as tall as they are.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 21:38:34 -03:00
dantebertuzziandClaude Opus 5.5 cacb620fec Paste Special: Excel's two-column layout, translated, Paste Link button
The dialog was a generic form: one column of fifteen radio buttons and
three check boxes, taller than the window, with English labels (the form
didn't run them through `tr`). It is now laid out as Excel's: Paste and
Operation each in two columns inside a frame, Skip blanks and Transpose
side by side under them, and Paste Link as a button that pastes
references to the copied cells at once. The letter shortcuts keep
working: the options still come from the dialog's fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 21:38:17 -03:00
Vedran DobosandClaude Opus 5.5 226c055fb7 fix(ui): Esc and Enter close a data validation alert, and the keyboard goes back to the entry (#2089)
A data validation alert is the general message box, drawn over the cell
editor, which stays open so the entry can be fixed. The editor read Enter and
Esc first: the first Esc cancelled the edit behind the alert and only the
second closed it, and Enter tried the entry again so the alert came back. The
editor now skips its own key handling while a message is open over it, so Esc
and Enter close the alert (like its OK button). The message box also had the
keyboard focus and didn't give it back, so typing went nowhere until the cell
was clicked; closing it now asks the open editor for focus again.

Tests: ui-egui tests/validation_alert.rs
esc_closes_a_validation_alert_and_leaves_the_entry and
enter_closes_a_validation_alert_and_leaves_the_entry (both fail on main, and
without the focus change).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 00:51:17 +02:00