Skip to content

XLSX: strip _xlpm. from LET/LAMBDA parameters on read, keep line breaks in table columns, allow leading backslash in table names - #423

Merged
h-a-n-a-s-h-i merged 1 commit into
storytold:mainfrom
neilcawse:fix/xlsx-names-xlpm
Oct 11, 2026
Merged

h-a-n-a-s-h-i merged 1 commit into
storytold:mainfrom
neilcawse:fix/xlsx-names-xlpm

Conversation

@neilcawse

@neilcawse neilcawse commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

What changed

Three XLSX round-trip losses, all in crates/xlsx:

  • _xlpm. LET/LAMBDA parameters. Excel stores LET/LAMBDA parameter names as _xlpm.name in the file. The writer already adds the prefix, but read_formula (sheet_read.rs) used the raw <f> text, so a saved LET(x,1,x+1) came back as _xlfn.LET(_xlpm.x,1,_xlpm.x+1). Cell, shared and array formulas now go through fmla::from_file, the conversion CF, data validation and names already use. When the formula parses, the stored text is the parser/printer form with _xlfn./_xlpm. removed. When it doesn't parse, the text is kept as written. One side effect: cell formula text read from a file is now in printer form (for example, spacing may change) rather than byte-for-byte as stored.
  • Line breaks in table column names. table_columns (sheet_write.rs) replaced \r/\n with spaces in column names. Excel allows a line break in a table header, and the header cell still had the break, so the column name and its header cell disagreed after a save. The name is now written unchanged (XML escaping already handles it).
  • Leading backslash in table names. table_name turned a leading \ into _ (or fell back to TableN). Excel's rules for names in formulas allow a name to start with a letter, _ or \, so \_Prime.1 is now kept. Structured references such as COUNTA(\_Prime.1[Name]) already parsed.

Tests

  • tests::roundtrip::let_lambda_parameters_drop_xlpm_on_read: LET, an immediately called LAMBDA and an array MAP/LAMBDA formula are written with _xlpm. in the sheet XML and read back with bare parameter names.
  • tests::roundtrip::table_newline_column_and_backslash_name_survive: a table named \_Prime.1 with a Handle\nBars column keeps both after a round trip, along with the header cell value and a structured reference formula to it.

Commands run:

cargo fmt --all -- --check
cargo clippy -p gridcraft-xlsx -p gridcraft-engine --all-targets -- -D warnings
cargo test -p gridcraft-xlsx -p gridcraft-engine

Before this change, the gridcraft-cli check round trip (#416, not needed by this PR) reported 3 of 41 local corpus files differing after a save. With the change, it reported 0. That was measured on an older base, before rebasing onto current main.

Docs

  • docs/file-format-parity.md: header and a history row for this change. The header and the history table overlap other XLSX PRs that touch this file, so a rebase may be needed.

Not done

  • No change to how other formula sources (chart series, pivot formulas) are read. They were not part of the round-trip differences found.

Unverified: needs confirmation in Excel

  • That Excel opens a table header with a line break, written as-is in tableColumn@name, without a repair prompt. The header cell and the column name now match, which is what Excel itself writes, but this has not been opened in Excel.
  • That Excel accepts a table name starting with \ in table@name/displayName.

… breaks in table columns, allow leading backslash in table names

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

echelon commented Oct 11, 2026

Copy link
Copy Markdown
Member

Merged — thank you for the contribution! If you haven't already, please join our Discord: https://discord.gg/artcraft

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants