Commit Graph
238 Commits
Author SHA1 Message Date
vangel76andClaude Opus 5.5 400ab591cb PivotTables: calculated fields (pivot.calculatedField) (#304)
A value field can be a calculated field whose formula is evaluated on
the sums of the fields it names for each report cell (Excel's documented
semantics). Command to add/change/delete, dialog from the field pane,
XLSX cacheField formula round trip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:24:50 +02:00
vangel76andClaude Opus 5.5 ce411edc91 Checkboxes: ribbon button, Excel's value and Delete rules, XLSX cell controls (#196)
insert.checkbox existed but had no ribbon button, replaced existing values
with FALSE and was written to XLSX as an invalid number format. Now:
Insert > Checkbox (Cell Controls); empty cells start FALSE, other values
stay and display as General; toggling an emptied box checks it and only
checkbox cells toggle; Delete unchecks first, then removes the boxes; XLSX
reads and writes the checkbox as Excel's feature-property-bag cell control
([MS-XLSX] 2.1.22, 2.3.9, 2.4.99).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:24:25 +02:00
vangel76andClaude Opus 5.5 9262fba5ce Charts: Select Data edits the category axis labels; blank corner makes column 1 the categories (#287)
A line chart from numeric X values (years) plotted them as a series and
there was no way to set the axis labels. Now:
- a blank top-left cell over a header row makes the first column the
  category labels even when it holds numbers (the usual convention);
- chart.selectData takes categories (Horizontal (Category) Axis Labels,
  "" clears) and removeSeries, and range is optional;
- Chart Design gets a Select Data button opening a Select Data Source
  dialog: chart data range, legend entries with Remove, axis labels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:20:29 +02:00
vangel76andClaude Opus 5.5 8e5b1ac8e3 XLSX: write threaded comments and persons parts, read note visibility (#300)
- Writer: one xl/threadedComments/threadedCommentN.xml per sheet with
  comments (thread, replies via parentId, done for resolved, dT when known)
  and xl/persons/person.xml (one person per author), with the [MS-XLSX]
  relationship and content types. Each thread keeps its legacy note, linked
  by the tc={id} author and xr:uid; its body is the text plus replies.
  Ids are GUID-shaped and deterministic.
- Reader: keeps dT timestamps (Comment.dates, JSON-compatible), drops
  replies whose thread is missing, and reads note visibility from the VML
  <x:Visible/> (best effort, broken VML skipped silently).
- Invalid dates are never written. Round-trip and hostile-input tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:15:45 +02:00
vangel76andClaude Opus 5.5 f58b1234fb Charts: Recommended Charts opens a dialog of chart types with previews (#215)
The ribbon button inserted a column chart straight away. It now opens an
Insert Chart dialog: a Recommended tab (insert.chartRecommendations, a
heuristic over the data's shape: series, points, labels, negatives) and an
All Charts tab, each with a live preview of the chart for the selection.
OK inserts the chosen type and selects the chart.

insert.recommendedCharts stays dialog-free for programmatic calls: without
a type it inserts the first recommendation; type/subtype pick one.
insert_chart is split into build_chart (also used for previews).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:15:12 +02:00
vangel76andClaude Opus 5.5 52921512c7 Functions: TRIMRANGE (#296)
Evaluator special form returning the range (or array) without its blank
outer rows and columns; trim codes 0-3 as documented; written as
_xlfn.TRIMRANGE. The trim-reference operators are not parsed yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:11:25 +02:00
vangel76andClaude Opus 5.5 be028cc6cc View: Formula Bar and Zoom 100% as engine commands (#289)
- view.zoom100 sets the active sheet's zoom to 100% (the ribbon's 100%
  button runs it).
- view.formulaBar {on?} toggles a formulaBar preference (Prefs, saved in
  prefs.json on desktop; an application option, not in the file). The UI
  shows the formula bar from it; the ribbon checkbox, native menu and
  ui.set {formulaBar} go through the command.
- The UI-only interceptions and their entries in engine.commands are gone,
  so the CLI and MCP can run both. Parity checklist regenerated (260 / 290).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:09:30 +02:00
vangel76andClaude Opus 5.5 a11446f2f0 Name Manager: New… and Edit… open the name dialog and return to the manager (#238)
dialogs::show put the Name Manager back into app.dialog after its body
had opened the New Name dialog, so New… did nothing. A dialog opened from
another one now takes over and the opener waits behind it (back), coming
back when the child closes; Go To still hands over to Go To Special.

The Name Manager gets Excel's New…/Edit…/Delete buttons over a selectable
list. formulas.defineName takes oldName/oldScope to edit a name in place;
a renamed name is renamed in cell formulas and other names' definitions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:09:19 +02:00
vangel76andClaude Opus 5.5 33afc7d3a5 Clipboard: Insert Copied Cells and Insert Cut Cells (#21)
New command home.insertCopiedCells: makes room at the active cell and
pastes the clipboard there, as one undo step. Whole copied rows or columns
insert whole rows or columns; a copied block shifts the cells down or right
(Insert Paste dialog from the menu). A cut of whole rows or columns moves
them and closes the gap (Insert Cut Cells). The cell and header context
menus show the entry while the clipboard holds a copy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:04:52 +02:00
vangel76andClaude Opus 5.5 6f47a8b463 Review: Previous/Next Comment, Show Comments, Show All Notes, Convert to Comments (#281)
- review.previousComment / review.nextComment select the previous/next
  threaded comment in reading order (row by row), across visible sheets in
  tab order, wrapping around; disabled when the workbook has no comments.
- review.showComments {on?} toggles the Comments pane as session state, so
  the CLI, MCP and control channel can drive it; the UI pane follows it.
- review.showAllNotes {on?} displays every note (session display setting,
  not saved in the file).
- review.convertToComments turns every note in the workbook into a threaded
  comment with the same author and text, as one undoable edit.
- Ribbon: Previous/Next and a Show Comments toggle in the Comments group;
  Show All Notes and Convert to Comments in the Notes menu. Strings in all
  catalogs. Parity checklist regenerated (263 / 290).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:04:03 +02:00
vangel76andClaude Opus 5.5 b6618aee8e Clipboard: pasted currency cells keep the number from the clipboard HTML (#257)
Spreadsheets put an HTML table next to the tab-separated text; Excel
(x:num) and LibreOffice Calc (sdval) record each cell's number there.
Paste now reads the HTML flavour (new paste_html host service, arboard on
desktop) and edit.paste takes an optional html param: a field that would
paste as text becomes the recorded number when the HTML cell shows the
same text, with an inferred format ("Rp"#,##0.00) that renders it back
identically.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:03:46 +02:00
vangel76andClaude Opus 5.5 1b9751ed82 Fill handle: Ctrl+drag swaps copying and extending a series (#264)
A plain drag copies a lone number and extends every other series; Ctrl+drag
(Cmd on macOS) now does the opposite, as in Excel: a lone number counts up
by 1, and numbers, dates, lists and `Item 1`-style text are copied.
edit.autoFill gains mode "alternate" for this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:55:45 +02:00
Alexander Alber 4e6e0d6c31 AutoFilter: a selected header row filters the data below it; search box in the filter menu (#201)
Turning the filter on with a multi-cell selection used the selection as the
filter range. With only the header row selected, the filter had no data rows:
the dropdown list was empty and filtering hid nothing. A one-row selection
now extends down over the current region below it. An explicit `range`
parameter is still taken as given.

The filter menu gets a search box, as asked for in the issue. It narrows
the value list; Select All then reads "(Select All Search Results)" and
covers only the matches, and Apply keeps only the checked matches. The box
takes focus when the menu opens, so typing no longer lands in the active
cell.

generated with Claude Code
2026-10-11 09:49:46 +02:00
Alexander Alber 32d0a866f9 XLSX: write one cfvo per icon in icon-set rules (#235)
An icon-set rule without stored thresholds (every rule made by
home.conditionalFormat, and the sales sample) was written as an empty
<iconSet>, which CT_IconSet forbids (cfvo minOccurs 2); openpyxl drops it.
The writer now always emits one cfvo per icon: the stored thresholds when
there is one per icon, the lower bound prepended when it is missing, else
Excel's defaults (percent 0/33/67, 0/25/50/75, 0/20/40/60/80).

Evaluation read the thresholds as one fewer than the icons, but files
carry one per icon (the first is the lower bound), so thresholds read from
a file were ignored. Both now share icon_count and default_icon_thresholds
in gridcraft-model; icon_count is clamped to 3..=5 so a set name like
"0Foo" can't underflow k - 1.

generated with Claude Code
2026-10-11 09:26:00 +02:00
AlissonFA 9518b041d5 M2: fix cell vertical alignment positioning and add keytips
Closes #241
2026-10-11 04:18:16 -03:00
nihilist-narwhal ce83871f2b Remove Duplicates: compare the text cells show
Excel decides duplicates by what a cell displays, not the value stored:
the same date shown as 3/8/2006 and as Mar 8, 2006 is two values, while
1.01 and 1.02 both shown as 1.0 are duplicates. Remove Duplicates
compared stored values, so it did the opposite in both cases.
2026-10-10 22:52:59 -05:00
nihilist-narwhal 5e22f9b373 Sort: case-sensitive order puts lowercase before uppercase
With Case sensitive checked, Sort compared text by code point, so every
uppercase word came before every lowercase one (A, B, a, b). Excel
compares ignoring case first and only then puts lowercase before
uppercase: a, A, b, B.
2026-10-10 22:52:59 -05:00
nihilist-narwhal a8a4c5dab3 Conditional formatting: accept Excel's operator names, refuse unknown ones
home.conditionalFormat took any operator it didn't know as "greater",
so a Cell Value rule given Excel's own names (lessThan, greaterThan,
lessThanOrEqual, greaterThanOrEqual, as in the file format and VBA)
silently became "greater than". Those names are now accepted, as data
validation already does, and anything else is an error.
2026-10-10 22:52:58 -05:00
nihilist-narwhal 4e7379bd68 Conditional formatting: cell value rules on blank and error cells
Excel compares a blank cell as 0 (or empty text) in Cell Value rules,
so "less than 5" or "equal to 0" also formats blank cells, and a
cell holding an error never matches (the comparison is an error).
GridCraft skipped blank cells and matched errors as if they sorted
above every number ("greater than 5" formatted #N/A).

The No Blanks rule also counted a cell holding only spaces as not
blank, while the Blanks rule (like Excel's LEN(TRIM())) counted it as
blank, so such a cell matched both.
2026-10-10 22:52:58 -05:00
nihilist-narwhal 2b1f851d0a Conditional formatting: apply every matching rule's format
Only the first matching rule's format was used, so with a light red
fill for >300 and a red border for >500, 510 showed only the border.
Excel applies every matching rule; where two rules set the same part
(fill, font colour, a border edge…), the rule with the higher priority
wins, and Stop If True still ends the list.
2026-10-10 22:52:58 -05:00
webdevtodayjason fae90c8e4a selection.move: clamp extreme dr/dc to the sheet edge instead of overflowing 2026-10-10 21:05:58 -05:00
Zarvinx 7a7e23cab7 Grid: reorder selected columns by header drag 2026-10-11 00:30:24 +03:00
Mikkel Georgsen c9525ab5fb Cell references: an invalid reference is an error instead of the active cell
cell_param returned None for any cell argument it could not parse, so every
command that falls back to the selection (cell.set, view.freezePanes,
formulas.trace*, insert.* and others) silently used the active cell instead:
set_cell with cell "ZZZZ0" wrote A1 and reported success. It also dropped a
sheet prefix, so "Other!B2" was applied to the active sheet.

cell_param now returns Result<Option<CellRef>>. An absent or null value is still
None, so the selection fallback is unchanged; an unparsable or non-string value
is an error; a sheet prefix naming a sheet other than the one the command works
on is an error.

cell_param_on is for the commands that resolve their own sheet (cell.get, links,
comments, notes, checkboxes, chart placement, paste): they accept a prefix naming
that sheet. cell.set resolves its own target sheet and still writes to another
existing sheet.
2026-10-10 22:41:40 +02:00
Mikkel Georgsen f69861f7e3 Cell: cell.set without an input is an error
cell.set treated a missing input as an empty string, so a call that forgot the
input (or sent it under the wrong key) cleared the cell and reported success.
It now returns an error when neither `input` nor `value` is given. An explicit
empty string still clears the cell.
2026-10-10 22:41:40 +02:00
Brandon Thomas 88d0c772fb Merge pull request #161 from nihilist-narwhal/fix-chart-kinds-roundtrip
Charts: histogram, box & whisker, waterfall, funnel, treemap and sunburst keep their kind through XLSX
2026-10-10 15:50:48 -04:00
Brandon Thomas f23281db8c Merge pull request #144 from harrisonoconnorhover/codex/cross-sheet-cut
Preserve formula references when cutting cells across sheets

# Conflicts:
#	ROADMAP.md
#	crates/formula/src/adjust.rs
#	crates/formula/src/tests.rs
2026-10-10 15:48:08 -04:00
Brandon Thomas 49fbae245a Merge pull request #156 from nihilist-narwhal/fix-legacy-array-formulas
Legacy array formulas: fill the range they were entered in

# Conflicts:
#	crates/engine/src/cmd/edit.rs
#	crates/ui-egui/src/formula_bar.rs
2026-10-10 15:47:56 -04:00
Brandon Thomas de0c715662 Merge pull request #186 from MarekSpodBiedry/issue-126
Write comment and hyperlink maps with A1 keys so JSON save works (#126)

# Conflicts:
#	crates/engine/src/tests.rs
2026-10-10 15:47:35 -04:00
Brandon Thomas b07249de75 Merge pull request #160 from itrycodinganditsbad/fix-month-fill-clamp
fill: clamp month and year date series to the month's last day

# Conflicts:
#	crates/engine/src/tests.rs
2026-10-10 15:47:32 -04:00
Brandon ThomasandClaude Opus 5.5 c15a51c959 Fix-up: move the #179 table-style test module to the end of tables.rs after merging #149
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 15:47:19 -04:00
Brandon Thomas 9fea6235f7 Merge pull request #148 from nihilist-narwhal/fix-stale-recalc-values
Recalc: stale spills and values after edits (fixes #133, #139)
2026-10-10 15:47:12 -04:00
Brandon Thomas 84a414a705 Merge pull request #158 from nihilist-narwhal/fix-chart-kinds-combo-stock
Charts: combo and stock charts keep their kind in XLSX
2026-10-10 15:47:11 -04:00
Brandon Thomas 1e5edbd43c Merge pull request #154 from nihilist-narwhal/fix-repeated-headers
Repeated headers: number pivot fields and table columns in linear time
2026-10-10 15:47:11 -04:00
Brandon Thomas 5c456df4b7 Merge pull request #152 from nihilist-narwhal/fix-whole-sheet-selection
Whole-sheet selection: Fill and Remove Duplicates no longer run out of memory or time
2026-10-10 15:47:10 -04:00
Brandon Thomas 92fb7cd1b3 Merge pull request #149 from nihilist-narwhal/fix-table-header-edits
Tables: typing in the header row renames the column; Go To a table selects its data

# Conflicts:
#	crates/engine/src/tables.rs
2026-10-10 15:47:10 -04:00
Brandon Thomas 645782f5e3 Merge pull request #185 from MarekSpodBiedry/issue-135
Report an error when file commands get no file in MCP and CLI (#135)
2026-10-10 15:46:32 -04:00
Brandon Thomas d031c8f37e Merge pull request #183 from MarekSpodBiedry/issue-140
Shrink 3-D sheet spans when an end sheet is deleted (#140)
2026-10-10 15:46:31 -04:00
Brandon Thomas 75ede09917 Merge pull request #180 from MarekSpodBiedry/issue-129
Keep the untouched part of a data validation range when clearing or replacing part of it (#129)
2026-10-10 15:35:45 -04:00
Brandon Thomas 14402fc5a3 Merge pull request #179 from MarekSpodBiedry/issue-130
Clamp table style number to 1 so zero-numbered styles don't underflow (#130)
2026-10-10 15:35:44 -04:00
Brandon Thomas 00df1908a7 Merge pull request #153 from nihilist-narwhal/fix-jump-without-direction
selection.move: Ctrl+arrow without a direction no longer loops forever
2026-10-10 15:35:42 -04:00
Brandon Thomas c4e4aeb293 Merge pull request #151 from nihilist-narwhal/fix-current-region
Current region: grow past 10,000 rows, in linear time
2026-10-10 15:35:42 -04:00
Brandon Thomas 20aa531d8c Merge pull request #150 from nihilist-narwhal/fix-paste-special-operations
Paste Special operations: keep text, errors and formulas
2026-10-10 15:35:41 -04:00
Brandon ThomasandClaude Opus 5.5 dfd3675324 Maintainer fix-up: drop wall-clock assertions from the repeated-headers test (flaky under load; Instant::now is a disallowed method)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 15:35:10 -04:00
Brandon ThomasandClaude Opus 5.5 f75ded37e7 Merge pull request #105 from harrisonoconnorhover/codex/cell-pictures
Add static pictures inside cells with XLSX roundtrip

Rebased onto main (conflicts with #83/#98 and main resolved by maintainer); the contributor's branch does not allow maintainer edits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 15:02:44 -04:00
Zaid ShurbajiandClaude Opus 4.8 fd2243df95 Add table slicers (insert.slicer / table.insertSlicer)
Implements the two slicer commands from the parity catalog as first-class
floating objects that filter a table column.

- model: Slicer struct on Sheet (#[serde(default)]), included in
  Workbook::next_object_id; slicer anchors use AnchorMode::MoveOnly.
- engine: cmd/slicer.rs with insert.slicer, table.insertSlicer, slicer.toggle
  (single + multi), slicer.selectAll, slicer.clear, slicer.delete. Selection is
  written as a FilterCriterion::Values into the sheet AutoFilter and applied via
  the existing apply_filter. object.move / object.delete handle "slicer".
- ui-egui: slicers rendered, hit-tested, selected and dragged like charts; value
  tiles toggle on click (Ctrl/Cmd = multi), funnel button clears. Ribbon buttons
  under Insert > Filters and Table Design > Tools.
- tests: slicer_filters_table; the every_command_survives_empty_params fuzz
  covers the new commands.

Native-only for now; .xlsx slicer-cache round-trip is a follow-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-10 21:27:13 +03:00
Brandon ThomasandClaude Opus 5.5 60aa2dfe07 Progress docs: target-app parity, gaps, alpha gate, readiness by audience (#189)
Progress docs per craftrules standards/progress-docs.md: target-app parity, gaps, roadmap with alpha gate, readiness by audience (full / mainstream / essentials) with Opus 5.5 hours, and feature, format, hardware, UI and localization parity docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:09:06 -04:00
Brandon Thomas f2ed982fdd Merge pull request #12 from justinjohn0306/fix/anchor-mode-sort
Objects: anchor modes — images/charts/shapes follow cells on sort (#5)

# Conflicts:
#	crates/engine/src/tests.rs
2026-10-10 13:17:30 -04:00
Brandon Thomas eb4174723d Merge pull request #17 from justinjohn0306/fix/encrypted-file-message
File open: report password-protected (encrypted) files clearly (#11)

# Conflicts:
#	crates/engine/src/io.rs
2026-10-10 13:17:21 -04:00
Brandon Thomas bd1be73f2d Merge pull request #62 from justinjohn0306/fix/smooth-line-charts
Line charts: smooth (spline) curves (issue #52)

# Conflicts:
#	crates/xlsx/src/tests/mod.rs
2026-10-10 13:17:07 -04:00
Brandon Thomas 13f8f19248 Merge pull request #116 from nihilist-narwhal/fix-chart-switch-and-scatter
Charts: Switch Row/Column on charts read from a file; scatter with text X values
2026-10-10 13:16:59 -04:00