Commit Graph
2699 Commits
Author SHA1 Message Date
NetterSilverandClaude Haiku 5.5 45ee4eceed Keep mid-field quotes when splitting with Text to Columns (#2438)
Found while testing crates/engine/src/cmd/data.rs:992 (split_delimited, used by text_to_columns)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-11-14 16:54:24 +01:00
Michael HigginsandClaude Opus 5.5 fdba683246 calc: linear dependency extraction for range-operator chains (#2183) (#2198)
* calc: linear dependency extraction for range-operator chains (#2183)

precedents() handled a range operator with non-reference operands by recursing into both operands and then letting Expr::walk descend into them again, so a left-associative chain of k operands cost 2^k (a 60-operand INDEX(...):INDEX(...) chain would hang on open). It is now a hand-written collector that visits every node once, growing the per-sheet bounding boxes of the enclosing range operator as it goes. Past a depth (4096) or node (1,000,000) bound it marks the formula dynamic (always recalculated) instead of recursing further.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* calc: drop wall-clock timing from precedents tests (clippy)

std::time::Instant::now is a disallowed method (clippy.toml: traps on wasm).
The regression test only needs to finish; the old 2^k walk would never return.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* calc: bound precedents to 100 ms and box plain-reference range chains (#2183)

- range_operator_chain_precedents_are_linear times the direct precedents
  call against the 100 ms bound in the issue.
- A Range node with two plain Ref operands (A1:B2:C3, which the parser
  can't fold) now collects its bounding box like any other range node, so
  an edit to C1 recalculates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 16:53:03 +01:00
Mex 10849d5003 fix(functions): reject negative fractions in GCD and LCM (#2072)
* M0: reject negative fractional GCD and LCM arguments

Validate the original input before truncation. Add scalar and range regressions, including signed zero, positive fractions and zero-first LCM validation.

* M0: document negative-fraction GCD and LCM regression

Record tested edge-case behavior and update the parity revision history. Function counts and readiness estimates remain unchanged.

* M0: preserve GCD and LCM regression after math test extraction

Move the original negative-fraction regression into the existing extracted math tests. Scalar and range cases, zero-first validation, signed zero and positive truncation coverage are unchanged.
2026-11-14 16:51:29 +01:00
gyurix 494b830240 Linux: the title bar carries the window controls, as in Excel (#192) 2026-11-14 16:48:20 +01:00
Zinadin Zidan 40783ab184 functions: ACCRINTM accrues zero when issue equals settlement (#4096) (#4102)
ACCRINTM returned #NUM! whenever issue >= settlement. Excel rejects only
an issue date after settlement: when the two dates are equal after
truncation to whole days (including distinct times on the same day) it
returns 0 in every basis and both date systems. Relax the guard to
issue > settle; zero rate, zero par and an invalid basis stay #NUM!.
2026-11-14 15:22:59 +01:00
Codex bf76e6e63b test: keep ref-edit three-sheet check clippy-clean 2026-11-12 19:41:19 +01:00
Codex 467d36a9c8 Merge main after PDF cleanup; retain both roadmap entries 2026-11-12 19:30:40 +01:00
Codex 0c5436de76 Merge main into chart frame cache; preserve both roadmap entries 2026-11-12 18:13:44 +01:00
Codex ce0beb6900 Merge main into PDF writer cleanup; preserve both roadmap entries 2026-11-12 18:13:44 +01:00
FredApps a60db4f1c7 Merge pull request #3323 from vangel76/fix/linest-qr
LINEST, LOGEST, TREND, GROWTH: solve by Householder QR (#3322)
2026-11-12 17:59:31 +01:00
FredApps a3366cff65 Merge pull request #1135 from vangel76/fix/group-resize-on-release-1082
Grid: resizing several selected columns applies the width on release (#1082)
2026-11-12 17:58:46 +01:00
FredApps 591b8354f2 Merge pull request #3624 from vangel76/fix/3619-merged-shift-enter
Shift+arrows, Enter and Tab no longer get stuck on a merged cell
2026-11-12 17:57:39 +01:00
FredApps 0b31cebe5d Merge pull request #789 from vangel76/feat/wordart-784
Insert: WordArt (insert.wordArt) (#784)
2026-11-12 17:56:55 +01:00
Dylan M. Taylor b1bd8d8b20 share legacy XLS test helpers 2026-11-12 06:29:50 +00:00
Dylan M. Taylor 794b65ecac fix XLS validation warnings 2026-11-12 06:13:59 +00:00
Dylan M. Taylor 73a18c4f4c Merge remote-tracking branch 'origin/switch-craft-libs-opc' into codex/reviewfix-3844 2026-11-12 05:41:20 +00:00
Dylan M. Taylor 0b4b36b865 Merge remote-tracking branch 'origin/switch-craft-libs-offcrypto' into codex/reviewfix-3843 2026-11-12 05:41:13 +00:00
Dylan M. Taylor 4251dad939 Merge remote-tracking branch 'origin/switch-craft-libs-csv' into codex/reviewfix-3842 2026-11-12 05:41:06 +00:00
Dylan M. Taylor 1b7e4f00dc Merge remote-tracking branch 'origin/switch-craft-libs-xls' into codex/reviewfix-3841 2026-11-12 05:40:59 +00:00
Dylan M. Taylor 4deedbb549 warn about dropped XLS rules 2026-11-12 05:40:53 +00:00
Dylan M. Taylor 8d4fb0b12e Merge remote-tracking branch 'origin/switch-craft-libs-opc' into codex/propagate-3844 2026-11-12 05:37:34 +00:00
Dylan M. Taylor 203872b4db Merge remote-tracking branch 'origin/switch-craft-libs-offcrypto' into codex/propagate-3843 2026-11-12 05:37:27 +00:00
Dylan M. Taylor d3954beacf Merge remote-tracking branch 'origin/switch-craft-libs-csv' into codex/propagate-3842 2026-11-12 05:37:21 +00:00
Dylan M. Taylor 26e7112e0f Merge remote-tracking branch 'origin/switch-craft-libs-xls' into codex/propagate-3840 2026-11-12 05:37:12 +00:00
Dylan M. Taylor 3d31729de3 test(xls): expect malformed encryption error 2026-11-12 05:36:34 +00:00
Dylan M. Taylor 3ba4945e72 GridCraft: use shared XLS validation operator type 2026-11-12 05:24:28 +00:00
Dylan M. Taylor 0752f3181b Merge current OPC switch into XLS validation switch 2026-11-12 05:20:25 +00:00
Dylan M. Taylor b24ec5df6d Merge current encrypted workbook switch into OPC switch 2026-11-12 05:19:49 +00:00
Dylan M. Taylor d0c567992e Merge current CSV switch into encrypted workbook switch 2026-11-12 05:18:19 +00:00
Dylan M. Taylor cf3b11c858 Merge remote-tracking branch 'origin/switch-craft-libs-opc' into codex/gridcraft-3844 2026-11-12 05:16:08 +00:00
Dylan M. Taylor eec5db66f0 Merge remote-tracking branch 'origin/switch-craft-libs-offcrypto' into codex/gridcraft-3843 2026-11-12 05:15:18 +00:00
Dylan M. Taylor 652c08a89b Merge remote-tracking branch 'origin/switch-craft-libs-csv' into codex/gridcraft-3842 2026-11-12 05:14:07 +00:00
Dylan M. Taylor 23487b0cb5 Merge current XLS switch into CSV switch 2026-11-12 05:12:51 +00:00
Dylan M. Taylor 0407b63663 GridCraft: update XLS import to current shared crate 2026-11-12 05:11:53 +00:00
Dylan M. Taylor b45698d109 tests: give the xls fixture its compound-file byte order mark
craft-cfb refuses a header without the 0xFFFE mark at offset 28
([MS-CFB] 2.2), so craft-xls's sniff called the fixture LegacyBinary.
The old hand-written parser never read that field, which is why the test
only broke with the switch. The fixture is a real workbook otherwise:
sniff now says Xls and read_xls parses it.
2026-11-12 05:08:22 +00:00
Dylan M. Taylor c913bf6615 tests: give the xls fixture its compound-file byte order mark
craft-cfb refuses a header without the 0xFFFE mark at offset 28
([MS-CFB] 2.2), so craft-xls's sniff called the fixture LegacyBinary.
The old hand-written parser never read that field, which is why the test
only broke with the switch. The fixture is a real workbook otherwise:
sniff now says Xls and read_xls parses it.
2026-11-12 05:08:20 +00:00
Dylan M. Taylor 1bd4ca8946 Test xls import with a valid compound file header 2026-11-12 05:05:01 +00:00
Dylan M. Taylor 0431741359 tests: give the xls fixture its compound-file byte order mark
craft-cfb refuses a header without the 0xFFFE mark at offset 28
([MS-CFB] 2.2), so craft-xls's sniff called the fixture LegacyBinary.
The old hand-written parser never read that field, which is why the test
only broke with the switch. The fixture is a real workbook otherwise:
sniff now says Xls and read_xls parses it.
2026-11-12 04:37:07 +00:00
Dylan M. Taylorandkiwi4boy ae7fbd81b7 xlsx: .xls data validation from craft-xls
craft-xls reads Dv/DVal records (storytold/craft-libs#999, a port of #3636).
xls.rs maps each rule onto the model as the .xlsx reader maps a dataValidation:
a non-literal list source becomes =ref. The tests are #3636's, run through
read_xls; the cap test now expects craft-xls's skipped-rules warning.

Co-authored-by: kiwi4boy <kiwi4boy@gmail.com>
2026-11-12 02:47:52 +00:00
Dylan M. Taylor f800472b0a xlsx: OPC package access through craft-opc; craft-libs at aa84415b
package.rs keeps GridCraft's Package, Rel and ZipOut, now on craft_opc::LazyPackage
and craft_opc::ZipOut (on craft-zip). Limits stay GridCraft's (200,000 entries,
512 MB a part, 1 GB a package) and so do the budget rules, which craft-opc took
from GridCraft. The budget tests moved with them. normalize, resolve and
split_dir are craft-opc's (the same code).

Every craft-libs crate moves to aa84415b. craft-xls now reads data validation;
until GridCraft maps it, a sheet with rules still warns that .xls data validation
is not imported. ods.rs matches entity names through a slice, since the new
dependencies make the old as_ref() call ambiguous.
2026-11-12 02:37:30 +00:00
Dylan M. Taylor 9c87c22662 xlsx: encrypted workbooks and compound files through craft-offcrypto and craft-cfb
Decrypting password-protected workbooks ([MS-OFFCRYPTO], Agile and Standard) moved
to storytold/craft-libs as craft-offcrypto (#931), on craft-cfb. GridCraft keeps
its DecryptError and the engine's messages; crypto.rs maps the crate's errors onto
it. The private compound-file reader and its tests are gone: sniffing looks for
the encryption streams with craft_cfb::has_entry_named (with the same fallback for
a damaged directory), and the test builders encrypt with craft-offcrypto and write
compound files with craft-cfb.

One difference, as craft-offcrypto has it: the dataIntegrity HMAC key is used at
the length it decrypts to (up to the hash size); GridCraft accepted only a
salt-size or hash-size key. Both verify what Office writes.
2026-11-12 01:34:24 +00:00
Dylan M. Taylor c1adf9b239 xlsx, engine: CSV decoding, parsing and quoting, and SYLK, through craft-csv
Text decoding (byte order marks, UTF-8, Windows-1256/1252), delimiter sniffing,
the record parser and field quoting moved to storytold/craft-libs as craft-csv
(#889), with the SYLK reader as craft_csv::sylk. GridCraft keeps typed values,
date-order inference, the used-range limit and the sheet writer in csv.rs, and in
io/sylk.rs the workbook a SYLK file becomes: formulas parsed (an unparsable one
is skipped and counted, as before), error values, number-format styles and column
widths.
2026-11-12 01:17:21 +00:00
Dylan M. Taylor 21df49c636 xlsx: read .xls workbooks through craft-xls
The BIFF8 reader moved to storytold/craft-libs as craft-xls (#878). GridCraft
keeps the mapping onto its model in xls.rs: formulas parsed, Excel's implicit @
for legacy formulas, pixel widths and heights, styles interned per XF, sheet-name
checks, print areas and titles, calculation settings and GridCraft's warning text.

The workbook now opens on the sheet it was saved on when that sheet is visible,
else on the first visible sheet (from #3551 by @Morzilla, whose test is kept).
RString cells are read as text.

Every craft-libs crate moves to one revision, 119415f4.
2026-11-12 00:58:43 +00:00
Dylan M. Taylor 572bec289b engine: work limits for Advanced Filter, Remove Duplicates, filters, AutoFit, macro footprints; range sizes saturate (#3295)
* engine: bound Advanced Filter, Remove Duplicates, AutoFilter, Circle Invalid Data; one-pass AutoFit; saturating range dimensions

* address review: AutoFit scans each run of adjacent selected columns separately

* address review: report a truncated circle-invalid scan, no spill scan for plain cells in Replace, one pass for many AutoFit runs

* address review: warn in the app when Circle Invalid Data stopped early; Replace test requires success

* address review: the scan note joins an open-time notice; say cell visits
2026-11-11 16:10:10 -05:00
Dylan M. Taylor 55eb394044 engine: index merges and bound the page in HTML export and clipboard HTML (#3266)
* engine: index merges and bound the page in HTML export and clipboard HTML

Save as Web Page and the clipboard's HTML scanned every merge of the
sheet for every cell, counted a merge's span over all the rows the file
gave it, placed each picture by summing every custom row before it, and
grew the page without a byte limit. Merges are now indexed once over
the exported rectangle (overlapping merges past a few visits per cell
are refused), spans use prefix counts clipped to the table, anchors use
LineIndex, and the page stops at 256 MiB with an error.

* address review: check the web page size after each chart and before returning it

* address review: bound the merge index, escape cell text within the page's room, size images before encoding

* address review: escape image attributes within the page's room
2026-11-11 16:09:43 -05:00
Dylan M. Taylor 35e9815603 Security: one work budget across every call of a lifted function (#3197)
* functions: one work budget across every call of a lifted function

A function lifted over a computed array runs once per element, and only the
six lookups counted their repeated work against LIFTED_SCAN_BUDGET. Criteria
aggregates rescanned their ranges per criterion, CUMIPMT/CUMPRINC stepped
through up to 1e7 periods per element, and array-producing functions such as
MUNIT built a whole result per element before keeping its first cell.

The budget now covers all of it: COUNTIF/SUMIF/AVERAGEIF(S)/MAXIFS/MINIFS
charge their range cells per call, the period loops of every element are
added up before any runs, and array results charge their cells as they are
built. Past the budget the call is #NUM!, as lifted lookups already are.

* address review: charge numeric-text periods of lifted CUMIPMT/CUMPRINC to the work budget

* address review: charge only calls that reach the cumulative period loop

* address review: charge the numeric text a lifted period call parses

* address review: SUMIF/AVERAGEIF charge only the sum-range cells they read; weight cumulative period work
2026-11-11 16:08:50 -05:00
Dylan M. Taylor 6ea8d11522 print: bound the print area to the grid; render charts once and budget picture and chart output (#3314)
* print: hold the print area to the grid; render each chart once and budget picture and chart output across pages

* address review: budget chart path points and drop charts that do not fit the budget
2026-11-11 16:08:24 -05:00
Dylan M. Taylor 7c3af8a421 fix(formula): bound the wrappers stacked on one path of a parsed formula (#3813) 2026-11-11 16:07:58 -05:00
Dylan M. Taylor ca7ea0131e fix(mcp): send the control token only to a loopback address (#3814) 2026-11-11 16:07:32 -05:00
Dylan M. Taylor aa0347cc2e fix(engine): calculated pivot fields may not build arrays from scalars (#3812) 2026-11-11 16:07:06 -05:00