* Paste: whole-column paste and validation without per-cell blowup
edit.paste of a whole-column or whole-row copy walked every cell of the
copied block (up to the whole sheet) and, for each one, re-cut every
validation rule and pushed a one-cell rule. Over a 2M-cell block that is
quadratic and the fuzz soak aborted on 34-68 GB allocations.
- Paste visits only cells that hold something in the source or the
destination; blank onto blank changes nothing (and with an operation
stays blank, as in Excel, instead of becoming 0).
- Validation pastes as ranges: the pasted rectangle is cut once out of
the destination's rules and each source rule comes along as one rule
over its translated parts (Skip Blanks or not, as Excel does).
- Whole columns and rows paste whole, so destination content further
down the columns is replaced, as in Excel.
- A paste that does not fit on the sheet is refused, as Excel does,
instead of pasting part of the block (whole columns below row 1, whole
rows right of column A, a whole column transposed, a block at XFD).
- Paste Link, the one paste that writes every cell, is capped at
1,048,576 cells; tiled validation at 100,000 ranges.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* Paste: visit destination cells once per paste, add link, transpose and tiling tests
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* Paste: visit link-only cells so a cut keeps their hyperlink
* Paste validation: Skip Blanks keeps the destination rule under a blank source cell with no rule
* Paste validation: Skip Blanks collects clearing cuts only when a rule is under the paste, merges them into runs, and limits only generated areas
* Paste validation: annotate the clearing cut list
* Qualify paste validation context type
* Fix paste-special clippy warnings
* engine: batch validation range cuts
* Fix range type inference
* Annotate validation range index type
* Avoid shadowing test session helper
* Keep validation rows after the final cut
---------
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
A source that takes in the cell being checked (=$A1:$A2 on A2:A3 is A2:A3 at A3) listed the value being typed, so any new value passed. The list is now read from the workbook as it was before the entry, as in Excel.
A list source such as =$B1:$B2 is written for the rule's top-left cell.
list_items evaluated it there for every cell, so the dropdown and the
check showed and accepted the top-left cell's items everywhere. It now
takes the cell and shifts the source to it, as Excel does.
Clearing validation from cells (or setting a new rule, or pasting a
validation over them) and Clear Rules on selected cells shrink a rule's
areas. When that removes the rule's top-left cell, the relative formulas
were left written for the old cell, so the cells left checked other
cells: clearing A1 off a custom `A1>10` on A1:A9 made A2 check A1.
Rewrite the relative references of validation formulas, and of
conditional format expressions and comparison values, for the new
top-left cell. Absolute references and literal lists stay as they are.
Excel writes the relative formulas of a multi-area rule for the top-left
cell of the whole sqref (lowest row, lowest column), whatever order the
areas are listed in. GridCraft anchored them on the first area listed, so
a validation on `H62:H68 H26:H27 H93:H95` with `MOD($H26,$F26)=0` checked
row 26 - 36 at H26 and refused valid input.
Add `RangeRef::top_left` and use it in validation checks, list sources,
pasting a validation, conditional format lookups and the formulas the
xlsx writer generates for text, blank and error rules.