Repository navigation
Conversation
…rmulas A What-If data table is now part of the model (Sheet::data_tables: its range and its row and column input cells) and of recalculation. After the formulas, every table with an edge cell (an input value or a formula) in the changed or dirty set is calculated again: each result substitutes the edge value into the input cell on a copy of the workbook and reads the formula (Trial, moved from the engine to calc). Results are written as values and their dependents recalculated; a table whose formulas read another table's results is calculated after it. F9 and opening a workbook calculate every table. Automatic Except for Data Tables and Manual calculation leave tables to F9. A table whose edge cells depend on its own results, directly or through other tables, is a circular reference: its results are #CIRC!. Calculation is bounded: at most 100,000 result cells per table and 1,000,000 per refresh, no table calculation inside a trial, and at most 64 passes.
data.dataTable now adds a live data table over the results instead of
writing a snapshot: the results recalculate when an input value, a formula
or a precedent of the formulas changes (on F9 in Automatic Except for Data
Tables mode), and undo removes the table with its results. The result
cells show {=TABLE(row_input,column_input)} in the formula bar, in Show
Formulas and in cell.get. Input cells must be single cells on the table's
sheet, outside it; a table may not overlap another one, and running Data
Table again over a table's range replaces that table.
`static: true` keeps the previous behaviour: every result is computed once
and written as a value, with input cells on any sheet. The response also
gains `formula`, and `static` is now false for a live table.
Like Excel, an edit of some of a table's results (typing, pasting,
clearing part of them, sorting) is refused with "Cannot change part of a
data table."; clearing all of them removes the table. Inserting or
deleting rows, columns or cells through a table, and pasting one table
onto another, are refused the same way; a table above or beside the edit,
or cut and pasted whole, moves with its input cells, and a table whose
input cell is deleted or ends up inside it keeps its results as values.
TABLE() typed into a cell is refused ("That function isn't valid.").
A data table is written as Excel stores it: the first result cell carries <f t="dataTable" ref="..." dt2D=".." dtr=".." r1=".." r2=".."/> for the whole results area, and every result cell its cached value. Reading rebuilds the table from that formula (previously it was dropped with a warning and only the values kept), so the table is live again after opening. Tables without a results area, with a deleted or misplaced input cell, with more than 100,000 result cells, overlapping an earlier table, or beyond 1,000 per sheet keep their values with a warning. Docs: target-app and file-format parity, ROADMAP progress log.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
At present,
data.dataTablecomputes every result of a What-If data table once, by substitution, and writes the results as static values. The command documents the result as "a snapshot, not a live {=TABLE()}" and returns"static": true. Consequently, the results do not change when an input value or a formula changes, and opening an XLSX file that contains a data table keeps only its cached values, with a warning.This pull request makes data tables live, as they are in Excel. A data table is a multi-cell formula
{=TABLE(row_input, column_input)}over its results. It is recalculated whenever one of its input values, one of its formulas or a precedent of those formulas changes. Edits of part of a table are refused, and tables round-trip through XLSX as<f t="dataTable">. The previous snapshot behaviour remains available throughstatic: true.Changes
Model (
crates/model)DataTable(range, row input cell, column input cell) andSheet::data_tables. Helpers return the results area, the edge cells, theTABLE(B1,B2)text and the substitutions that fill the results.MAX_DATA_TABLE_CELLS(100,000 result cells, the limit the command already used) is shared by calc, the engine and XLSX.Calculation (
crates/calc)Trialmoves from the engine to calc so that recalculation can use it; Goal Seek, Scenario Manager, Solver and static data tables use it unchanged.#CIRC!. The result does not depend on the order of calculation, so incremental and full recalculation agree.Command (
crates/engine)data.dataTablecreates a live table by default and returnsformula(for example{=TABLE(,B2)}) together with"static": false. Input cells must be single cells on the table's sheet and outside the table ("Input cell reference is not valid."). A table may not overlap another table. Running Data Table again over a table's range replaces that table.static: trueruns the previous code path unchanged; input cells may then be on any sheet.commit, so every command is covered.TABLE()typed into a cell is refused ("That function isn't valid."), as in Excel.{=TABLE(...)}incell.get, in Show Formulas and in the formula bar. A Hidden format on a protected sheet hides the formula, as it does for other formulas.XLSX (
crates/xlsx)<f t="dataTable" ref="..." dt2D="..." dtr="..." r1="..." r2="..."/>and its cached value; the other result cells carry their cached values.del1/del2) or misplaced input cell, with more than 100,000 result cells, overlapping an earlier table, or beyond 1,000 per sheet keep their values and produce a warning.Documentation
docs/target-app-parity.md,docs/file-format-parity.mdand theROADMAP.mdprogress log. The scores are unchanged.Compatibility
{"static": true}gives exactly the previous behaviour: the same code path, values written once, input cells on any sheet, and"static": truein the response. The only addition is that a snapshot taken over the range of a live table replaces that table.static, the command now creates a live table. Callers that only readrange,cellsandmodereceive the same values as before, and the cells hold the same results. The response'sstaticfield is nowfalse, andformulais new. The default also requires input cells on the table's sheet, as Excel does; callers that relied on an input cell on another sheet should passstatic: true.data_tablestest passes unchanged against the new default, so no existing test was adapted. The engine-to-calc move ofTrialkeeps the Goal Seek, Scenario Manager and Solver tests unchanged.Sheetfield is skipped when empty). XLSX files with data tables no longer report the warning "what-if data tables are not supported".data.dataTablewithout parameters, which returns an error as it does today. A Data Table dialog can follow separately.Testing
crates/calc/src/tests.rs: one-variable tables (column and row oriented) and two-variable tables update after edits of an input value, a formula and a precedent; dependents of the results recalculate; Automatic Except for Data Tables and Manual modes wait for F9; a table that reads its own results, and two tables that read each other's results, give#CIRC!and recover when the loop is broken; a table that reads another table follows it, even when it is listed first; formulas withINDIRECTare not treated as circular; hostile tables (whole-sheet ranges, no input, an input inside the table, a single-cell range) are skipped.crates/engine/src/cmd/whatif.rs: live updates of one- and two-variable tables,cell.getand Show Formulas text, undo and redo of edits and of the table itself, refusal of partial edits, sorting, inserted and deleted rows and cells through a table and overlapping tables, movement with rows inserted above, cut and paste of a whole table, clearing all results, a deleted input cell,TABLE()typed into a cell, Automatic Except for Data Tables mode, hostile parameters (empty, missing input, input inside the table or on another sheet, a range as input, a one-column range, a whole-sheet range, 100,001 result cells) and the largest table allowed (100,000 result cells), static mode, and an XLSX save and reopen after which the tables are still live.crates/xlsx/src/tests/data_table_tests.rs: the written XML for the three kinds of table, cached values (including text), the round trip of the tables and their values, and damageddataTableformulas that keep their values with a warning.cargo fmt --check,cargo clippy --workspace --all-targets -D warnings,cargo test --workspace --no-fail-fast(including the command-sequence fuzz with its default seeds) andcargo xtask assets,layers,wasm,parity --checkandkeytips --checkpass on each commit. The exceptions are three tests that already fail onmain(the French i18n test and two CSV separator tests, addressed by CSV/text export: General numbers without exponents (integers below 1e16 exact);&switches to scientific past 21 characters #449 and fix(i18n): correct scattered wrong French translations and add 2 missing keys #454).main, none of which involves a data table. A local randomised sequence of edits around data tables (1,500 seeds of 80 commands: values, formulas, live and static tables, undo, redo, inserted and deleted rows, columns and cells, cut and paste, sorting, clearing) checks after every step that a full recalculation and an XLSX save and reload give the values that incremental recalculation left. It found the cases that the overlap, moved-input and circular-table handling now cover. It is not part of this pull request.dataTableattributes follow ECMA-376. They have not yet been checked against files written by Excel, because no corpus file with a data table is available.Generative AI use: The code and descriptions in this pull request were written with the assistance of Claude Opus 5.5 (Claude Code). I directed the work, chose its scope, and reviewed and tested the changes.