Repository navigation
Linked workbooks: references typed by file name or path go through a link, shown with the file - #829
Open
marcoarnulfo wants to merge 10 commits into
Open
marcoarnulfo wants to merge 10 commits into
marcoarnulfo wants to merge 10 commits into
Conversation
This was referenced Oct 13, 2026
…/footer labels CSV/TSV export ran General numbers through the 11-character cell display, so a barcode like 124412140710 was saved as 1.24412E+11. display::value_text now writes a General number as & converts it (number_to_text), as its doc already said; cell_text keeps the cell display. Fixes the two storytold#426 tests that broke when Adds the French "Different First Page" / "Different Odd & Even Pages" labels missing after storytold#413, which failed the i18n completeness test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…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.
…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)
…torytold#567's name quoting Main now quotes the sheet of a sheet-qualified name when printing it. A linked workbook's own name has no sheet, so [1]!Rate stays unquoted, and the shown name is stored bare so the printer quotes the path once.
marcoarnulfo
force-pushed
the
fix/external-workbook-refs
branch
from
October 15, 2026 09:23
435b6a9 to
48d4342
Compare
Contributor
Author
|
Rebased onto current main. One commit is new rather than a conflict fix: after #567 the printer quotes sheet-qualified names, which turned a linked workbook's name |
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.
Fixes #804.
Built on #464 (it needs its
ExternalBookand the reading of the link parts), so until #464 is merged this branch shows its three commits too; the last three commits are this PR. It sits next to #824 (#801): that one addsWorkbook::source_dirand rebases kept link targets on Save As, and this one addsExternalBook::path. They touchpassthrough.rsand its tests in different places, and I'll rebase whichever lands second.The model and the file keep only
[n], the position of the link. What changes is the way in and the way out. When a formula or a name is entered, a reference to another workbook typed by file name or path ([Source.xlsx]Sheet1!A1,'C:\links\[Source.xlsx]Sheet1'!A1,Source.xlsx!Rate,'C:\links\Source.xlsx'!Rate) is rewritten as[n]Sheet1!A1/[n]!Rate. The link is matched by path, or by file name when no folder is given. Otherwise a new link is added with the typed path. A new link has no values yet, so its sheets are markedrefreshError, and the reference is#REF!as in Excel when the file is missing.ExternalBooknow keeps the link's path, read from theexternalLinkPathrelationship (file:///C:\links\Source.xlsx→C:\links\Source.xlsx, a relative target stays relative). The formula bar, Show Formulas, the Name Manager anddocument.inspectprint[n]back as the file ('C:\links\[Source.xlsx]Sheet1'!A1), and that text goes back in unchanged when you press Enter. On save, the links read from the file are still passed through as they were. Each new link gets its ownexternalLinkpart and rels after them, so[1]stays[1].<f>only ever holds[n].In the formula language: the unquoted
[Source.xlsx]Sheet1!A1now lexes (it was refused withunexpected Sheet("Sheet1", None)), and a drive'sC:inside a quoted path is no longer read as the colon of a 3-D range. That colon is what produced the'C:\…\[links[Source.xlsx]Sheet1]…'text Excel showed.[Source.xlsx]Sheet1prints unquoted when the sheet name allows it.Choices I'd flag (happy to switch):
Target="Source.xlsx") is shown as[Source.xlsx]Sheet1!A1. Excel shows the absolute path there, resolved against the workbook's folder. With XLSX: Save As into another folder keeps links on the same workbook #824'ssource_dirthat's a small follow-up, so I left it out here.Book.xlsx!Nameis read as another workbook only when the qualifier isn't a sheet of this workbook and has a folder or a file extension. SoData.v2!Ratestays local when there's a sheetData.v2, andPlain!Rateisn't treated as a file.#REF!. It isn't added to the kept part, which is written byte for byte. A new link's part is generated from the model.Validation:
linked_workbooks.rs(engine, new), one assertion per row of the issue's table: what is kept ([1]Sheet1!A1,SUM([1]Sheet1!A1:A3),'[1]P&L Data'!A1,[1]!Rate), the value (#REF!for a new link; 10, 20, 30, 60 and 0.05 through an existing link), the saved<f>and theexternalLinkpart with its rels target, the formula bar text before and after reopening, and the Name Manager /document.inspectrefersTo. It doesn't build on XLSX: formulas into linked workbooks calculate from the values saved with the link #464's head (no path inExternalBook). With the entry rewrite removed, it fails as on main ([Source.xlsx]Sheet1!A1kept instead of[1]Sheet1!A1).another_workbook_by_file_name_or_path_parses(formula): fails on XLSX: formulas into linked workbooks calculate from the values saved with the link #464's head ([Source.xlsx]Sheet1!A1: unexpected Sheet("Sheet1", None)), passes here.a_new_link_follows_the_kept_ones(xlsx): a kept link plus a typed one are written as[1]and[2], both read back with their paths.damaged_kept_content_is_dropped_without_failing_the_readstill holds: when the file's links can't be kept, nothing is generated after them.[n]in the formula bar, the Name Manager or inspect; a defined name kept as typed; any qualifier read as a file; no new link part; the path not decoded; a new link withoutrefreshError(0 instead of#REF!); a drive colon splitting the sheet; the file name quoted by the printer.cargo test -p gridcraft-formula --lib,cargo test -p gridcraft-xlsx --lib a_new_link_follows,cargo test -p gridcraft-engine --test linked_workbooks,cargo test -p gridcraft-xlsx --lib passthrough_tests,cargo test -p gridcraft-calc --lib linked_workbooks,cargo clippy -p gridcraft-formula -p gridcraft-model -p gridcraft-calc -p gridcraft-xlsx -p gridcraft-engine -p gridcraft-ui-egui --all-targets -- -D warnings,cargo fmt --all -- --checksheetNames,definedNameswith norefersTo,refreshErrorsheet data,file:///path for absolute paths). Opening it in Excel 365 is the check I can't do here.