Skip to content

feat(spreadsheet): read the formula of every cell of a shared group - #885

Open
andiwand wants to merge 1 commit into
feat/formula-parserfrom
feat/shared-formulas
Open

feat(spreadsheet): read the formula of every cell of a shared group#885
andiwand wants to merge 1 commit into
feat/formula-parserfrom
feat/shared-formulas

Conversation

@andiwand

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

Stacked on #884 — review that first; this PR's diff is the second commit.

Step 3.1 of docs/design/spreadsheet-editing.md, finishing what the parser was for.

The problem

[ECMA-376] 18.3.1.40 spells a shared formula on the group's master alone:

<c r="C1"><f t="shared" ref="C1:C3" si="0">A1+$B$1</f><v>3</v></c>
<c r="C2"><f t="shared" si="0"/><v>7</v></c>
<c r="C3"><f t="shared" si="0"/><v>9</v></c>

Excel writes this whenever you fill a column down, so most formula cells in a real workbook are members. A member reported an empty formula, which leaves a formula bar with nothing to show and the dependency graph (next PR) with nothing to read.

What it does

The parser collects the masters per sheet, and sheet_cell_value reads a member through the one its si names: parse the master's expression, move every relative reference by the offset between the two cells, write it again. So C2 above answers A2+$B$1 and C3 A3+$B$1 — the $B$1 does not move, because a $ axis never does.

That needs two pieces beside the parser, both in internal/formula:

  • shift over the tree. A reference moved off the grid becomes #REF!, as a sheet makes it.
  • a writer, to_string(node, syntax), which spells a tree back in either syntax. It drops a parenthesis the precedence already states, so 1+(2*3) comes back as 1+2*3 while 1-(2-3) keeps its own.

Two cells that keep what they had

  • a master the parser cannot read is handed out as it stands rather than dropped;
  • a member whose si names no master stays set and empty — it computes, and nothing here can spell what.

An array formula (t="array") writes no <f> at all on its members, so those still report none. Noted in the module's AGENTS.md.

Test

test/src/internal/formula/formula_writer_test.cpp round-trips both syntaxes and pins the shift; the shared-formula cases are in ooxml_spreadsheet_value_test.cpp, from inline fixtures. test/data/input/odr-public/xlsx/sample.xlsx is a real file of the shape — 32 members of one RAND() group.

[ECMA-376] 18.3.1.40 spells a shared formula on the group's master alone, and
a member states its `si` and nothing else. A member reported an empty formula,
so a formula bar had nothing to show and a dependency has nothing to read.

The parser collects the masters per sheet, and `sheet_cell_value` reads a
member through the one its `si` names: parse the master's expression, move
every relative reference by the offset between the two cells, and write it
again. An absolute axis does not move, and a reference moved off the grid
becomes `#REF!`, as a sheet makes it.

That takes two pieces beside the parser, both in `internal/formula`: `shift`
over the tree, and a writer that spells a tree back in either syntax. The
writer drops a parenthesis the precedence already states, so what it writes
is the tree rather than the producer's own text.

A master the parser cannot read is handed out as it stands, and a member
whose `si` names no master stays set and empty: it computes, and nothing here
can spell what.

Step 3.1 of `docs/design/spreadsheet-editing.md`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VVmjmddv2Ui17Nptc1ggue
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.

1 participant