Commit Graph
655 Commits
Author SHA1 Message Date
aiongg e8091a1952 refactor(engine): move io tests to src/io/tests.rs 2026-10-26 18:15:42 +00:00
aiongg 8c338b7cbe refactor(engine): move cmd/whatif tests to src/cmd/whatif/tests.rs 2026-10-26 18:15:42 +00:00
aiongg 6fee0e9134 refactor(engine): move cmd/solver tests to src/cmd/solver/tests.rs 2026-10-26 18:15:42 +00:00
aiongg 1f5c4747df refactor(engine): move cmd/print tests to src/cmd/print/tests.rs 2026-10-26 18:15:41 +00:00
aiongg 2396bb4f64 refactor(engine): move cmd/pivot tests to src/cmd/pivot/tests.rs 2026-10-26 18:15:41 +00:00
aiongg 2b808def4f refactor(engine): move cmd/edit tests to src/cmd/edit/tests.rs 2026-10-26 18:15:40 +00:00
aiongg 97c2a984e0 refactor(engine): move cmd/data tests to src/cmd/data/tests.rs 2026-10-26 18:15:39 +00:00
aiongg e95c29b1fe refactor(engine): move crates/engine/src/cmd/mod.rs to crates/engine/src/cmd.rs 2026-10-26 18:15:25 +00:00
aiongg f102fe29a1 Merge g3 into g4
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/cmd/edit.rs
#	crates/engine/src/cmd/formulas.rs
#	crates/engine/src/cmd/inspect.rs
#	crates/engine/src/cmd/pivot.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/tabs.rs
#	docs/gaps.md
#	docs/ui-parity.md
2026-10-26 02:45:41 +00:00
aiongg 015b9abe5b Merge g2 into g3
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	ROADMAP.md
#	apps/gridcraft/src/main.rs
#	crates/ui-egui/src/lib.rs
#	docs/ui-parity.md
2026-10-26 02:37:36 +00:00
aiongg 929495e274 Merge g1 into g2
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/cmd/extra.rs
#	crates/engine/src/lib.rs
#	crates/engine/src/tests.rs
#	docs/control-protocol.md
#	docs/ui-parity.md
2026-10-26 02:37:33 +00:00
aiongg 22aec7e667 G1: build on current main
Scripts can't run the View tab's window commands (Switch Windows, New Window, Hide, Unhide):
they change the active workbook, as window.* steps do. The Switch Windows button names its
accessibility role with egui::Role (egui 0.37).
2026-10-26 02:37:27 +00:00
aiongg 903bece86f Merge upstream main into g1
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/tests.rs
#	crates/ui-egui/src/lib.rs
#	docs/ui-parity.md
2026-10-26 02:23:11 +00:00
Dylan M. Taylor 42bbf6baa2 refactor: split complex functions for Sonar S3776 (#2612)
Extract group_bracket from outline layout and move_marks from data
outline_settings. No behaviour change.
2026-10-25 21:39:17 -04:00
Dylan M. Taylor 52cf825395 refactor: split complex functions for Sonar S3776 (#2609)
Extract helpers from auto_sum (selection and single-cell guess), update_cursor
(drag, hover, freeze, and header-edge cursors) and read_styles (dxf reader).
No behaviour change.
2026-10-25 21:37:09 -04:00
3b65b9af58 Sonar maintainability: explicit imports, method paths, smaller functions (#2412)
* Sonar: explicit imports, fn paths for closures, extract helpers for cognitive complexity

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

* Fix imports

* Fix serde imports

* Fix engine imports

* Fix clippy gate and a type error from the explicit-import change

Remove the unused imports the review flagged (cf.rs, pivot.rs, tables.rs, cmd/sheet.rs) so clippy -D warnings passes, and point the backstage parent-folder lookup at Path::to_str, which the fn-path rewrite had broken.

Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* Apply rustfmt to the explicit-import cleanup so the fmt gate passes

* Share the per-directory font path expansion in theme.rs

The candidate font lists repeated the same loop over the Linux font
directories in every role. A single helper expands them in the same order,
so the lookup order is unchanged and the duplicated blocks go away.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* Read the Windows fonts folder in one place in theme.rs

Every script-font list repeated the same WINDIR lookup. A single helper
returns the same path, so the duplicated lines go away without changing
which font files are tried.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* Build the light and dark UI palettes from one table in theme.rs

Tokens::light() and Tokens::dark() listed the same 40 colour fields in the
same order, so every change had to be made twice. A single palette
constructor takes the mode and picks each colour's value, so each field is
written once and both modes keep their exact colours.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* Share the Noto CJK font list between the CJK script lists in theme.rs

The Japanese, Simplified and Korean lists each repeated the same loop over
the Linux CJK directories with a different locale file name. One helper
builds that loop, and each list keeps its own face index, so the lookup
order is unchanged.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* Share Linux Noto directory list across Thai and Hebrew font lookups

Removes the duplicated directory arrays flagged by SonarCloud new-code duplication.

* Reuse in_dirs for Thai and Hebrew Noto font candidates

Removes the remaining duplicated per-directory loops flagged by SonarCloud.

* Share one font-list builder for the Thai and Hebrew faces

The two per-script functions repeated the same Windows, macOS, Linux and
variable-font setup. A single script_fonts helper now builds both lists,
keeping the candidate order unchanged, which clears the Sonar duplication gate.

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Codebuff <noreply@codebuff.com>
2026-10-25 12:32:02 -04:00
Brandon Thomas 4a44dec500 Merge pull request #2515 from Fubeo:fub/edit-note-keeps-thread 2026-10-25 09:36:36 -04:00
Brandon Thomas 97ec7653aa Merge pull request #2512 from Fubeo:fub/open-saved-without-recalc 2026-10-25 09:36:34 -04:00
Brandon Thomas 27e96a9a58 Merge pull request #2561 from arcanii:autosum-across-a-row 2026-10-25 09:36:34 -04:00
Brandon Thomas 2c81adf94f Merge pull request #2557 from Silvertree2010:fix/2517-a-new-font-derived-from-the-them 2026-10-25 09:36:33 -04:00
Bryan MarkandClaude Opus 5.5 802c782360 AutoSum: a selected row gets its total to the right, as in Excel
AutoSum over any selection of more than one cell wrote a total under each column, so a row
selected (B2:E2) got four one-cell totals in row 3 instead of =SUM(B2:E2) in F2.

As Excel does, totals now go in the selection's empty last row or column, and otherwise past
it:
- a single row: its total in its last cell when that is empty, else just to its right;
- a block whose last column is empty: each row's total there; whose last row is empty: each
  column's; both: both, and the block's total in the corner;
- otherwise totals under each column, as before.

A whole-row selection still stops at the data's last column, and all totals are one undo step.
Tests: autosum_over_a_row_totals_it_to_the_right,
autosum_over_a_whole_row_totals_it_after_the_data and
autosum_fills_a_selections_empty_last_column_and_row; each fails without the change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 20:34:30 +08:00
NetterSilverandClaude Opus 5.5 85b6f564f9 Keep <scheme val="minor"/> on every body-font font on save
Fixes #2517

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 13:20:17 +01:00
NetterSilverandClaude Haiku 5.5 80e2041159 Remove sparklines when their row or column is deleted
Found while testing crates/engine/src/cmd/sheet.rs:~199 (shift_sheet_features, sparklines loop)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 09:39:12 +00:00
aiongg 17b9f6ff01 Paste Name and Go To: follow-ups from the batch review (#2540)
* Go To: names match in any case and script, as formulas match them

* Paste Name: only the names in view are laid out

* Docs: LAMBDA recursion limit and called error names; one Page Layout view row with the side margin marked unverified

* Go To and Paste Name: cargo fmt
2026-10-25 01:24:24 -04:00
aiongg 24e49d18ad Batch: Subtotal puts summary rows below their detail in the same undo step (#2482) 2026-10-25 04:27:21 +00:00
aiongg f17179ceeb Batch: Show Details turned off says so in plain words; the option is in the command's docs (#2461) 2026-10-25 04:22:02 +00:00
aiongg 87a649c763 Batch: Paste Name lists the names once, finds local names by hash and refuses a name it doesn't list (#2410) 2026-10-25 03:56:45 +00:00
aiongg 50c7ee3971 Batch: undo, redo and rollbacks list the circular references of the restored cells (#2501) 2026-10-25 03:50:42 +00:00
aiongg 6194f8241d Merge storytold/gridcraft#2522: Charts: 100% Stacked Area draws each value as a share of its category's total
# Conflicts:
#	ROADMAP.md
2026-10-25 02:54:23 +00:00
aiongg 1e50c72698 Merge storytold/gridcraft#2488: Headers and footers: printing follows the Scale with Document and Align with Page Margins check boxes
# Conflicts:
#	docs/ui-parity.md
2026-10-25 02:54:23 +00:00
aiongg b58846a549 Merge storytold/gridcraft#2482: Outline: Settings puts summary rows above and summary columns left of their detail
# Conflicts:
#	docs/ui-parity.md
2026-10-25 02:54:23 +00:00
aiongg cb1fb89549 Merge storytold/gridcraft#2467: PivotTables: right-clicking a value cell offers Show Details in the cell menu
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/cmd/pivot.rs
#	docs/ui-parity.md
2026-10-25 02:46:38 +00:00
aiongg 75f7df9da6 Merge storytold/gridcraft#2461: PivotTables: Enable show details turns Show Details off for a PivotTable
# Conflicts:
#	ROADMAP.md
2026-10-25 02:46:16 +00:00
aiongg 8356b33c78 Merge storytold/gridcraft#2456: Fill handle: Fill Days, Fill Weekdays, Fill Months and Fill Years for a date
# Conflicts:
#	ROADMAP.md
#	docs/ui-parity.md
2026-10-25 02:46:16 +00:00
aiongg 924d36e247 Merge storytold/gridcraft#2421: Status bar: a right-click opens a statistics menu, with Numerical Count, Minimum and Maximum added
# Conflicts:
#	ROADMAP.md
#	crates/ui-egui/src/tabs.rs
#	docs/ui-parity.md
2026-10-25 02:25:39 +00:00
aiongg ae88b40f58 Merge storytold/gridcraft#2414: Go To: lists the named ranges of every sheet and the references entered, and goes to several at once
# Conflicts:
#	docs/ui-parity.md
2026-10-25 02:25:15 +00:00
aiongg 0217dbdfd8 Merge storytold/gridcraft#2410: Formulas: F3 opens Paste Name, which inserts a defined name or pastes the list of names 2026-10-25 02:24:49 +00:00
aiongg 58aa0f1df2 Merge storytold/gridcraft#2504: Circular references: Error Checking and the status bar quote sheet names that need quotes 2026-10-25 02:24:49 +00:00
dotCooCoo 0eb2f1f6f0 Charts: 100% Stacked Area draws each value as a share of its category's total
Insert > Line or Area and the All Charts list offer 100% Stacked Area,
and insert.chart and chart.set take it as type area with subtype
stacked100. Each series' area stacks on the ones before it as its
share of the category's total. When every series on the value axis is
100% stacked and no value is negative, the axis runs from 0% to 100%.
A blank cell counts as zero, and a category whose total is zero stays
on the baseline.

An XLSX area chart with percentStacked grouping now opens as 100%
stacked and is saved back as percentStacked. It used to open as a
stacked area and was saved as stacked.
2026-10-24 16:42:59 -07:00
Fubeo 4548bab2e3 feat(engine): open a saved workbook without recalculating it
DocState::new recalculates the whole workbook, so values saved in the file
change where nothing was edited (volatile functions, functions GridCraft
lacks, cycles). DocState::from_saved builds the dependency graph without
evaluating, so every value stays the file's until an edit reaches it.
2026-10-25 01:37:44 +02:00
Fubeo 3e6eac4222 fix(engine): editing a note or comment keeps its thread
Writing a note or comment on a cell that already has one of the same kind
replaced the whole thread: Edit Comment lost the replies, the resolved state
and the dates, and Edit Note the box read from the file. Now only the text
(and the author, when the command names one) changes, as Excel's Edit Note
does; a note written over a comment still replaces it.
2026-10-25 01:31:19 +02:00
dotCooCoo 1dd07b7f75 Circular references: Error Checking and the status bar quote sheet names that need quotes
formulas.errorChecking listed each circular reference as Sheet!A1 with
the sheet name as it is, so a sheet named Bob's Q1 gave Bob's Q1!B2,
which a formula does not accept as a reference. The list now quotes the
name with quote_sheet, as references are written elsewhere in the
engine ('Bob''s Q1'!B2), and the status bar's Circular References
label uses the same form.
2026-10-24 14:51:06 -07:00
dotCooCoo b745c136b2 Headers and footers: printing follows the Scale with Document and Align with Page Margins check boxes
The Header & Footer tab now has the Scale with Document and Align with
Page Margins check boxes, and pageLayout.headerFooter takes
scaleWithDoc and alignWithMargins. XLSX already kept both settings,
but nothing else read them.

With Scale with Document on, header and footer text prints at the
sheet's print scale. With it off, the text keeps its point size. With
Align with Page Margins on, the left and right sections line up with
the page's side margins. With it off, they start 0.7 inch from the
paper's edges, or a quarter of the page width on paper narrower than
2.8 inches. The Page Layout view draws headers and footers and takes
clicks on them the same way. Both settings are on by default, so a
sheet printed at a scale other than 100% now prints its header and
footer text at that scale.
2026-10-24 13:01:00 -07:00
dotCooCoo 118cd15d93 Outline: Settings puts summary rows above and summary columns left of their detail
Data > Outline > Settings now has Summary rows below detail and Summary
columns to right of detail. With one cleared, each group's - / + button
sits on the line before the group, its bracket runs down to the last
detail line, and Hide Detail, Show Detail, the level buttons and
Ungroup mark or clear the collapsed flag on that line. Changing a
direction moves the flags of collapsed groups to their new summary
lines.

- model: Sheet::summary_below and summary_right (on by default, also
  for older JSON).
- xlsx: read and written as sheetPr/outlinePr summaryBelow and
  summaryRight; files that set them no longer lose them on save.
- engine: data.outlineSettings {sheet?, summaryBelow?, summaryRight?},
  undoable; outline::groups_with places the summary line.
- ui: a Settings button in the Data tab's Outline group opens the
  dialog; the outline band follows the setting.
2026-10-24 11:34:35 -07:00
dotCooCoo 010eddd25e PivotTables: the cell menu computes a report once for all its cells
The cell menu checked whether to offer Show Details by computing the
whole report again for each new active cell. pivot::detail_cells now
returns every value, subtotal and grand total cell of a report from one
computation, and the menu caches that set per document, revision, sheet
and PivotTable.
2026-10-24 11:27:58 -07:00
dotCooCoo 7c10db07d9 PivotTables: Show Details reports the turned-off option before an out-of-date report
With Enable show details off, Show Details on a value cell of a report whose
source has changed gave the out-of-date error. It now gives the turned-off
message, and a label still reports that it is not a value cell. The message
names pivot.options with enableShowDetails set to true, since there is no
PivotTable Options dialog.
2026-10-24 10:31:09 -07:00
dotCooCoo 30126a709a PivotTables: Enable show details turns Show Details off for a PivotTable
A PivotTable has an Enable show details option, set with the new
pivot.options command ({pivot?, enableShowDetails?: bool}). While it is
off, pivot.showDetails and double-clicking a value cell list no records:
the double-click shows a message and does not open the cell for editing.
Labels and headers still edit. Changing the option is one undo step and
does not refresh the report. pivot.fields reports the setting.

XLSX files keep it: an off option is written as enableDrill="0" on the
pivotTableDefinition, and enableDrill is read on open (on when absent).
2026-10-24 07:46:29 -07:00
dotCooCoo 00edfd0690 Fill handle: Fill Days, Fill Weekdays, Fill Months and Fill Years for a date
When a fill starts from a date, the right-drag fill menu and the Auto
Fill Options button now also offer Fill Days, Fill Weekdays, Fill Months
and Fill Years. edit.autoFill takes them as the modes days, weekdays,
months and years.

A lone date steps by one unit. Two or more dates step by the difference
between the first two in that unit, or by one unit when both fall in
the same one. Fill Weekdays skips Saturday and Sunday, and a start on a
weekend moves to the next weekday first. Fill Months and Fill Years keep
the day of the month, clamped to the month's last day. A source that is
not all dates fills as a plain drag does.

Fills by months or years now keep the time of day of a date with a
time. A plain drag of dates a month apart and Series by Month or Year
used to drop it.
2026-10-24 06:56:26 -07:00
dotCooCoo d0fe8b6423 Tests: the engine's file-system tests each use their own temporary folder
save_fails_upfront_when_the_temp_name_is_taken,
save_keeps_the_destination_access_restrictions and
open_refuses_directories_and_unknowable_lengths in crates/engine/src/io.rs
all worked in temp_dir()/gridcraft-fs-safety and removed it at the start
and the end. cargo test runs them on parallel threads, so one test could
delete the folder while another was writing to it, and the other test
failed. Each test now uses its own folder, named with a short label and
the process id, as the gridcraft-write and gridcraft-sandbox tests in the
same file do.
2026-10-24 04:54:53 -07:00
Dylan M. Taylor a005d8235f M2.9: close protection gaps a trusted script or other sheet would slip through (sec scan findings 17,20,24) (#2420)
- scripts: refuse `window.*` steps like file and link steps — activating
  another window repointed every later step at a different open document
  (finding 17).
- format: on a protected sheet, formatting may not change a cell's
  protection flags: the format-cells permission can't drop `locked` and
  then authorize content edits the password gates (finding 20).
- sheet.moveColumns: the insert/delete protection checks now carry the
  command's own `sheet` parameter, so the sheet modified is the sheet
  authorized, not whichever is active (finding 24).

Tests: unlock-via-format refused, cross-sheet move refused, window switch
refused, plus the positive controls. Engine: 462 tests pass; clippy clean.
2026-10-24 06:15:24 -04:00