XLSX: strip _xlpm. from LET/LAMBDA parameters on read, keep line breaks in table columns, allow leading backslash in table names
# Conflicts:
# docs/file-format-parity.md
A `;`-separated CSV (the usual CSV where `,` is the decimal separator) was
rewritten with `,` on save: read_csv sniffed the delimiter but the result was
dropped, and save_bytes passed a hard-coded b','. file.save, Save As .csv,
file.exportCsv, file.saveBytes and gridcraft-cli convert all went through it.
The workbook now remembers the separator it was read with
(Workbook::csv_delimiter, set by read_csv) and a CSV save writes it back.
Workbooks not read from CSV, and .tsv/.txt sources saved as .csv, keep `,`.
Regression tests: `;`, `,` and tab .csv round trips byte for byte, new and
.xlsx-origin workbooks save with `,`, and open-by-path + edit + file.save on a
`;` file keeps `;` (also through exportCsv and saveBytes).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Text turned by an angle was drawn at a fixed anchor (bottom-left for upward,
top-left for downward text) and ignored the horizontal and vertical alignment,
so upright text with Middle Align in a tall merged cell sat at the bottom.
rotated_text_pos places the turned galley's bounding box in the cell per the
alignment, then derives the TextShape anchor from it. General/Bottom keep the
old placement for upright text.
Fixes#435
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A password-protected file named on the command line (a Windows or Linux
double-click) now asks for its password, and open errors are shown
instead of only logged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gridcraft_xlsx::check_encryption parses EncryptionInfo without a
password, so RC4, Extensible, certificate-only and rights-management
(IRM) files, and damaged ones, get their real message instead of a
password prompt first.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OK on the untouched field says the password is incorrect instead of
asking again; the Backstage closes once the workbook opens; app.open on
the control channel takes a password and never opens the dialog. Control
protocol docs cover file.open {password}.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without a password, file.open returns an error carrying
io::PASSWORD_REQUIRED (never a dialog). A decrypted workbook gets no save
path, so Save never replaces the encrypted original.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Clean-room from [MS-OFFCRYPTO]: EncryptionInfo parsing, SHA-1/SHA-2 key
derivation with a capped spin count, AES-ECB/CBC. RC4, Extensible and
certificate-only encryption are reported as unsupported.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Restores "Counts whole years, months or days between two dates." and
appends the units, in the multi-line form rustfmt gives a long entry.
Drops the 256-argument test case: the parser already refuses more than
255 arguments, so it never reached the entry check. (993c108's message
says entry "also refuses" them; it already did.)
Claude-Session: https://claude.ai/code/session_01BGBBGBC2gRpQ7GDuwQ6WPt
- Side-by-side and synchronous-scrolling keytips removed (do not exist in
James's Excel); Copy H,C / Spelling R,S / Fill H,H / Sparklines N,Z,K
confirmed already correct
- QAT digits 0-9 and Backstage account/home/options + legacy Share Workbook
sequences dropped (no meaningful GridCraft target; not left as trash)
- Colour palette (H,H fill and F,C font colour): arrow keys move a highlight
through the swatches, Enter applies; key events are stripped so the grid
behind the popup does not react
- Arrows/Enter while a keytip combo is open now navigate the list instead
of moving the filter field's text cursor (events stripped from TextEdit)
- Reopening a combo resets the filter: the reset frame requests a repaint
so the stale filtered list never lingers on screen
- Page Layout Sheet Options: Gridlines View/Print and Headings View/Print
checkboxes painted with VG/PG/VH/PH badges and keytip toggles
- Background rebound from PG to PGB (Excel's Page Setup GB badge); PG is
no longer terminal
- editable_combo: every dropdown keytip opens with a filter field focused;
typing narrows the list, Up/Down move the highlight (wrapping), Enter or
click applies, custom text applies where valid (font size). Fixes arrows
and typing in ALT+H FF/FS/N.
- Audited all 54 painted ribbon ids against the table: real mismatches fixed
(Data Sort/Text-to-Columns/Remove-Duplicates/Subtotal, Review Spelling/
Accessibility/New Comment/Notes, View Zoom/Freeze, Formulas Insert Function/
Name Manager/Define Name/Use-in-Formula/Error Checking/Evaluate, Insert Link/
Comment/Header-Footer/Sparklines, Home Protect Sheet).
- keytips.json: dialog kind for real dialog openers; control kind for the 6
chart-type buttons, 7 formula-category buttons, and Orientation (HFQ added,
was missing); M-family restructured to Excel semantics (ML/MT/ME/MO/MG/MQ
fire directly, MI1 opens Financial) with 14 unreachable children dropped;
383 entries total.
- New Action::Control routes a keytip to its ribbon control (popup/dropdown
open, checkbox toggle, button handler) instead of an engine command with
empty params. Fixes ALT+H FF/FS/N/H/H error boxes.
- Ribbon consumes a one-shot ui.keytip_invoke: font/size/number combos
converted to the popup pattern (ComboBox has no open_memory), fill/font
color menus force-open via SetOpenCommand, 100% zoom and Formula Bar run
their handlers.
- keytips.json: FF/FS/N/H/H -> control kind; View/Formulas/Data dialog
openers (WQ zoom, HFM format cells, HO*, MV, AWG, sparkline types) and
control WVF; MSP/HVP re-targeted; dropped 15 unreachable Home sub-items
and non-Excel HWS shrink-to-fit.
- View tab: badges on workbook views, gridlines/headings, formula bar.
- Generated suite: 399 tests incl control-kind arm; direct tests 18.
cargo xtask keytips now emits tests/keytips_generated.rs alongside the
table: one end-to-end test per sequence, asserting exactly what its
action does today. The generator probes the live engine catalog at
generation time (blank workbook, empty params), so each live command
asserts journaled / ran clean / surfaced its missing-params error;
pending asserts silence; dialogs assert the dialog opens; tabs assert
the ribbon switch; group levels assert the prefix stays armed.
- pending-but-landed targets get live assertions and a generation
warning (HWS home.shrinkToFit and MAA formulas.removeArrows had
landed since population - flipped to live)
- unreachable-sequence validation: any seq with a terminal prefix
entry is rejected (HCP dropped - HC Copy fires first)
- ENV_SENSITIVE list keeps the checked-in file byte-stable across
machines (review.spelling uses the system dictionary)
- sample_sequences_work_with_text_before_key covers IME text-first
event order for one representative of each action kind
- generated_test_count_matches_the_table pins the table size
518 ui-egui tests green; all 8 CI gates pass.
- Action::Pending now consults the engine catalog at fire time: silent
no-op while the command is missing, runs it once it exists - no table
edit needed when a future feature lands.
- Stripped stray backticks from 7 pending target ids so catalog lookup
can ever match them.
- gridcraft-engine: doc(hidden) register_test_command hook so UI tests
can prove the go-live path without touching production code.
- Tests: pending_sequences_are_silent_no_ops (no dialog/toast/journal),
pending_sequences_go_live_when_the_command_lands (fake command fires
via its reserved sequence), every_sequence_terminates_without_panicking
(all 413 sequences pressed end-to-end).
- HP -> home.percent (was wrongly numberFormat); HN stays the Number dropdown.
- H3 -> home.underline fires directly; H3U/H3D dropped as unreachable.
- HAT/HAM/HAB -> Top/Middle/Bottom Align (were unbound).
- NCM/NZT/NZS -> modern Comment/Text Box/Symbol (NC2/NZTX/NU kept as
legacy aliases); MI1 -> Financial first item.
- Badges on the three dropdowns (font FF, font size FS, number format N)
and the vertical alignment buttons; Print Titles paints PI.
Model: Series.trendlines (Vec<Trendline>, serde default) with kind
(linear, exponential, logarithmic, polynomial 2..6, power, moving
average 2..255), name, forward/backward forecast, set intercept,
equation / R² display and line colour, width and dash.
XLSX: read and write <c:trendline> in CT_Trendline child order, placed
after dLbls and before the data references in line, bar, area, scatter,
bubble and stock series; unknown types are skipped.
Chart: least-squares fits (transformed for exp/log/power, skipping
non-positive values; polynomials via normal equations on centred,
scaled x with partial pivoting), moving averages, forecasts that widen
the category or x axis, clipping to the plot, equation and R² labels and
legend entries ("Linear (Sales)"). Degenerate data draws nothing.
Engine: chart.addElement element="trendline" adds (type, series, order,
period, forward, backward, displayEquation, displayRSquared) or removes
trendlines; document.inspect lists each chart's trendlines.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>