Repository navigation
Sheet transfer: preserve workbook references (builds on #1803 and #1200) - #1813
Draft
derechopiano wants to merge 19 commits into
Draft
derechopiano wants to merge 19 commits into
derechopiano wants to merge 19 commits into
Conversation
…with the link A formula reading another workbook ([1]Prices!B2, '[2]P&L'!A1:B9, a name over such a range) recalculated to #REF!: the externalLink parts were passed through on save but never read. Excel calculates these from the cached copy of the linked cells it saves in the file, as it does whenever the source is closed. On a 4,224-file real-world corpus this was the largest root cause of calculation mismatches. The reader now loads each link's sheet names, cached cells, refresh-error flags and defined names into Workbook::external_books; the lexer reads unquoted [1]Sheet!A1 and [1]!Name; references, linked names and [0]!Name evaluate from that data; the *IF(S) range arguments refuse linked-workbook values and written errors, as Excel does with a closed source; and linked sheets print unquoted when the sheet name allows, so saved formulas keep their text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… prints back References into a linked workbook became value arrays when evaluated, so `@` and implicit intersection took the top-left value (`=@[1]Data!B:B` in row 4 gave the header), ROWS/COLUMNS/INDEX saw the block trimmed to the last cached cell (`ROWS([1]Data!A:A)` = 3), and every lookup rebuilt the whole block. They are now Areas whose sheet number (from LINKED_SHEETS up) stands for the linked workbook and sheet; cells are read from the saved values only when the reference is dereferenced (Evaluator::cell, Evaluator::block_values), and a linked sheet's extent is remembered per pass like a local used range. The printer dropped the quotes from '[1]Jan:Dec'!A1 and the lexer couldn't read [1]Jan:Dec!A1. The lexer now accepts the unquoted MS-XLSX sheet-range form, and the printer quotes a range when either sheet name needs it.
…]Jan:Dec
OFFSET took a reference into a linked workbook as its base and read the
saved link values. Excel errors there while the source is closed: the Enron
West NatGas Prices cells wrap OFFSET('[21]Curve Summary'!...) in ISERROR and
cached the backup value. OFFSET now answers #VALUE! for a linked base, the
answer of the other reference-only parameters given a closed workbook's values.
Renaming a local sheet rewrote the second end of [1]Jan:Dec!A1, which names a
sheet of the linked workbook; rename_sheet and delete_sheet now skip spans
whose first end is in a linked workbook.
Workbook::external_books is behind an Arc, like sheets and preserved parts,
so each edit's workbook clone and the undo history share the link cache.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…[0] is this workbook
…ixes; [0] names stored local; CF/DV refuse other workbooks; paste into another workbook drops [n]
…New Window of the same workbook)
…se as references to another workbook
…ng as new link parts
…link, shown with the file (fixes storytold#804)
…d on write (My%20Files)
… refused, [1]!Rate isn't)
's [n] check storytold#829 was written against an older storytold#464. Its typed references by file name or path (`[Source.xlsx]Sheet1!A1`, `'C:\links\[Source.xlsx]Sheet1'!A1`) were refused by the entry check storytold#464 added since (a bracketed prefix that isn't a link index). The check now lets a typed file through where entry links it (`typed_book`), and linking runs last in `input_to_cell`, so a formula refused for another reason never leaves a new link behind. Conditional formats, data validation and paste still refuse other workbooks. A typed file must look like one (a folder or an extension), so `[-1]Sheet1`, `[ 1]Sheet1` and `[Book2]Sheet1` stay refused as storytold#464's review asked. `[1]!Rate` prints without quotes around `[1]`, and the shown name of a link (`'C:\links\Source.xlsx'!Rate`) is quoted once by the printer, as main now quotes sheet-qualified names itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…inks, startup prompt
The engine side of Data › Queries & Connections › Workbook Links and File › Info › Edit Links
to Files. Every action is a command, reachable from the CLI and MCP:
- data.workbookLinks / data.editLinks list the links (file, path, type, update, status, last
refreshed, formulas using it) and ask the UI for the pane or the dialog.
- data.refreshLinks {link?} (Update Values / Refresh) reads the source workbook with
gridcraft-xlsx: the cells and names this workbook reads from it, including whole columns
trimmed to the source's used range, names used inside linked names, and 3-D spans. A source
saved without values is calculated first. One undo step; dependents recalculate.
- data.checkLinkStatus: OK, Error: Source not found, Error: Worksheet not found, Warning:
Values not updated (the file has other values than the link), Error: Undetermined.
- data.changeLinkSource {link, path} points the link at another file and reads it; onto a file
another link reads, the two links become one.
- data.breakLink {link?}: as observed in Excel, every cell formula that reads the link, also
through a defined name, becomes its value (arrays become the values of their range); names
stay and keep the link. A link nothing names any more is removed and the later [n] move up.
- data.linkStartupPrompt {mode}: userSet / never / always, saved as workbookPr updateLinks
(ECMA-376 ST_UpdateLinks); the default isn't written.
- data.openLinkSource opens the source; data.enableLinkUpdates is the security warning's
Enable Content.
Opening a workbook never reads its links: like Excel, their automatic update is disabled until
Enable Content or Update Values (not at all when the prompt says never). Status and last refresh
are session state (DocState::links). Files are read through Session::link_files, the file system
off wasm; in the browser the commands that read sources are disabled with a reason.
Saving: ExternalBook::kept (replacing storytold#829's `added`) says which link part of the file holds a
link unchanged. Unchanged links are still written back byte for byte; a link added, refreshed or
moved to another source is written from the model in its place, and the part of a removed link
is dropped. Save As rebases relative paths of links written from the model too (storytold#824).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…warning Data gets Excel 365's Queries & Connections group: the Refresh All split button (Refresh All, Refresh, and Refresh Status, Cancel Refresh, Connection Properties… shown disabled), then Queries & Connections, Properties (disabled) and Workbook Links, which is off while the workbook links to no other workbook, as in Excel. Key tip A K now runs Workbook Links (it was Edit Links). Workbook Links opens the task pane: Refresh All, Break All, a search box and a card per linked workbook with its location, status (OK, Warning: Values not updated, Error: Source not found…), last refresh and Refresh, Open Workbook, Change Source… and Break Links. File › Info shows Related Documents › Edit Links to Files for a workbook with links, which opens the classic Edit Links dialog (Source, Type, Update, Status; Update Values, Change Source…, Open Source, Break Link, Check Status, Startup Prompt…). Break Link asks first; Change Source and Startup Prompt open over Edit Links and return to it. All of it runs the data.* link commands. Opening a workbook with links shows the message bar "Security Warning: Automatic update of links has been disabled" with Enable Content. message_bar.rs is a small reusable mechanism: bars come from the active document's engine state, each with a command button and a close button. German labels follow German Excel (Arbeitsmappenlinks, Verknüpfungen mit Dateien bearbeiten, Werte aktualisieren, Quelle ändern…, Quelle öffnen, Verknüpfung löschen, Status prüfen, Eingabeaufforderung beim Start…, Sicherheitswarnung, Inhalt aktivieren). Generic words carry a context (`Workbook Links|Source`) so they don't collide with other features' translations. The open warning "links to external workbooks were kept; they are not followed or refreshed" is gone: links are now refreshed on request, and the security warning says what Excel says. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
file-format-parity (externalLink parts written from the model when a link changes, workbookPr updateLinks), gaps §12 (what works and what's left for links), ROADMAP progress log, ui-parity and target-app-parity rows. An MCP test runs the link commands through execute_command. The command-sequence fuzzer leaves out the link commands that read files or open a document, as it does for file.open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Moving or copying a sheet that refers to sheets left behind currently has to be refused by #1803. This follow-up preserves supported cell and defined-name references through Workbook Links instead.
Dependencies and review scope
Stacked draft: builds on #1803 and #1200; not ready to merge independently. #1200 includes #464 by @neilcawse and #829 by @marcoarnulfo, with their original commits/authorship retained. This branch merges those foundations rather than implementing a second link model or refresh runtime.
The full main-branch diff includes these prerequisites. Our follow-up is merge commit
3e7d0dc, primarilycrates/engine/src/sheet_transfer.rs, its integration tests and transfer documentation. To isolate the transfer integration from the prerequisite code, usegit show --remerge-diff 3e7d0dc.Result
Limits
A required link target needs a distinct absolute XLSX path. Unsupported table, multi-sheet, INDIRECT and worksheet-object dependencies remain explicit refusals, including unsupported external references hidden behind names. This is not live recalculation between open workbooks. Save both workbooks before refreshing moved-sheet links from disk.
Validation
cargo xtask cion Windows: all eight checks passed (fmt, clippy, workspace tests, assets, layers, wasm, parity, keytips).b91e250(run 39089929280).19f4387succeeded without conflicts. Local CI was run on this PR's head, not on a newly committed merge with that main revision.Related: #1739. #1803 remains the initial self-contained transfer PR.