Commit Graph
185 Commits
Author SHA1 Message Date
Brandon Thomas beda2a44dc Merge PR #2394 2026-10-24 02:10:42 -04:00
Brandon Thomas d743f21992 Merge PR #2399
# Conflicts:
#	ROADMAP.md
#	docs/function-parity.md
2026-10-24 02:10:42 -04:00
Brandon Thomas f9af0d88a5 Merge PR #2397
# Conflicts:
#	ROADMAP.md
#	docs/function-parity.md
2026-10-24 02:10:42 -04:00
Brandon Thomas 14d6dabcaf Merge PR #2396 2026-10-24 02:10:36 -04:00
Harrison Booth 35067fa9ca Read accounting negatives like $(1,234) in number text
Typed entry, VALUE and arithmetic now read $(1,234), $ (5) and (5)% as
negative numbers, as Excel 365 does. Parentheses no longer nest: (-5),
((5)), $5% and dates in parentheses stay text. This changes main's
((100)) from 100 to text; the no-recursion guard from #2180 is kept and
its test now asserts the new result.
2026-10-23 16:57:24 -05:00
Harrison Booth 86f4114514 Merge remote-tracking branch 'origin/main' into gc-lookup-exact-number-compare
# Conflicts:
#	ROADMAP.md
#	docs/function-parity.md
2026-10-23 16:55:41 -05:00
Harrison Booth e883c84e7b Merge origin/main into the Analysis ToolPak value-argument branch
Resolves conflicts in ROADMAP.md, docs/function-parity.md and
crates/calc/src/tests.rs: both sides' progress-log rows and tests are kept.
2026-10-23 16:55:37 -05:00
Harrison Booth 9fd7693d4e Merge fork's border keytips fix into main 2026-10-23 16:39:13 -05:00
Harrison Booth 74b2bda75c Merge origin/main into gc-index-2d-ref-one-index 2026-10-23 16:02:22 -05:00
Tyrel HavemanandClaude Opus 5.5 e177bf1c44 calc: hardening: overlong digits, NaN indexes, REGEXREPLACE output (#2163, #2162)
- Text coercion: digits too many for a finite number are not a number,
  and a fraction must come out finite, so "1 <400 digits>/<400 digits>"
  (inf/inf) no longer coerces to NaN (test overlong_digits_stay_text).
- VLOOKUP/HLOOKUP and the D-functions' field index refuse NaN, which
  passed their "< 1" checks and became index 0, then underflowed
  (test nan_index_is_a_value_error; hostile_inputs_never_panic now also
  passes NaN and infinity to every function).
- REGEXREPLACE replaces match by match and gives up once the result can
  only be too long, instead of building every replacement first: the
  32,767 x 32,767 worst case went from 1.05 GB peak to 7 MB
  (test regexreplace_bounds_its_result).

#2165 (MAP's size check) is already fixed on main by the broadcast cap
(836b2698, #2182), whose test covers MAP.

Also adds my contributors/people.toml entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Nnsfu3QGqjD1aFZbBgUWP
2026-10-21 23:41:28 -07:00
aiongg 561382cc6d Integration: track t14
# Conflicts:
#	ROADMAP.md
#	contributors/people.toml
#	crates/formula/src/tests.rs
#	docs/file-format-parity.md
#	docs/localization-parity.md
#	docs/ui-parity.md
2026-10-22 03:05:30 +00:00
aiongg ca1cdd4229 Integration: track t13
# Conflicts:
#	ROADMAP.md
#	contributors/people.toml
#	crates/engine/src/cmd/data.rs
#	crates/xlsx/src/tests/mod.rs
#	docs/chart-parity.md
#	docs/file-format-parity.md
#	docs/function-parity.md
#	docs/gaps.md
#	docs/localization-parity.md
#	docs/target-app-parity.md
2026-10-22 03:05:18 +00:00
aiongg c7fd66d807 Integration: track t12
# Conflicts:
#	ROADMAP.md
#	crates/calc/src/tests.rs
#	crates/chart/src/tests.rs
#	crates/engine/src/tests.rs
#	crates/xlsx/src/tests/mod.rs
#	docs/chart-parity.md
2026-10-22 03:05:03 +00:00
aiongg 9350ab1def Integration: track t11
# Conflicts:
#	ROADMAP.md
#	apps/gridcraft-web/Cargo.toml
#	crates/ui-egui/src/i18n.rs
#	docs/control-protocol.md
#	docs/gaps.md
#	docs/target-app-parity.md
#	docs/ui-parity.md
2026-10-22 03:04:52 +00:00
aiongg 4c5c345c31 Integration: track t10
# Conflicts:
#	ROADMAP.md
#	crates/ui-egui/tests/sheet_tabs.rs
#	crates/xlsx/src/tests/roundtrip.rs
#	docs/gaps.md
#	docs/ui-parity.md
2026-10-22 03:04:30 +00:00
aiongg d3201e7cea Integration: track t08
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/tests.rs
#	docs/file-format-parity.md
#	docs/localization-parity.md
2026-10-22 03:03:55 +00:00
aiongg cfda01c831 Integration: track t06
# Conflicts:
#	ROADMAP.md
#	contributors/people.toml
#	crates/ui-egui/src/i18n.rs
#	crates/ui-egui/tests/interaction.rs
#	docs/gaps.md
#	docs/localization-parity.md
2026-10-22 03:03:17 +00:00
aiongg 4c81d658ec Integration: track t05
# Conflicts:
#	crates/ui-egui/tests/keyboard_shortcuts.rs
#	docs/ui-parity.md
2026-10-22 03:01:39 +00:00
aiongg 512b2aa9fd Integration: track t04
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/cmd/edit.rs
#	crates/engine/src/cmd/formulas.rs
#	crates/engine/src/tests.rs
#	crates/formula/src/lib.rs
#	crates/formula/src/parser.rs
#	crates/formula/src/tests.rs
#	crates/ui-egui/src/control.rs
#	crates/ui-egui/src/formula_bar.rs
#	crates/ui-egui/src/grid.rs
#	crates/ui-egui/src/i18n.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/ribbon.rs
#	crates/ui-egui/tests/selection.rs
#	docs/function-parity.md
#	docs/ui-parity.md
2026-10-22 03:01:31 +00:00
aiongg b0b6409112 Integration: track t03
# Conflicts:
#	ROADMAP.md
#	crates/ui-egui/tests/keyboard_shortcuts.rs
#	docs/file-format-parity.md
#	docs/localization-parity.md
#	docs/ui-parity.md
2026-10-22 03:00:13 +00:00
aiongg 54d0f7cfc0 Integration: track t02
# Conflicts:
#	ROADMAP.md
#	crates/core/src/lib.rs
#	crates/ui-egui/src/editor.rs
#	crates/ui-egui/src/grid.rs
#	crates/ui-egui/src/tabs.rs
#	docs/chart-parity.md
#	docs/localization-parity.md
#	docs/ui-parity.md
2026-10-22 02:59:55 +00:00
aiongg e72d5f290a Merge PR #2061: i18n: Dutch (nl) interface language
Conflicts:
- crates/ui-egui/src/i18n.rs: language registration lines kept from both sides (Language::ALL has 17 entries).
- ROADMAP.md: one Last updated line naming both changes; both progress-log rows kept.
- docs/localization-parity.md: one Last updated line naming both changes; both revision rows kept.
2026-10-22 02:38:32 +00:00
aiongg 1316d39865 Merge PR #1151: Charts: a huge trendline forecast no longer collapses the chart (#1148)
ROADMAP.md: all rows kept.
crates/chart/src/tests.rs: both tests kept.
2026-10-22 02:37:37 +00:00
aiongg e738049157 Merge PR #1088: Charts: multi-level category axes (year beside month) read, drawn and written back
ROADMAP.md: all rows kept.
2026-10-22 02:36:49 +00:00
aiongg cd3fcfd2a0 Merge PR #1083: Colour menus: More Colors… and Recent Colors (#928)
ROADMAP.md: all progress-log rows kept.
docs/ui-parity.md: one Last updated line, change notes combined; both history rows kept; ribbon row wording tidied.
2026-10-22 02:36:40 +00:00
aiongg fccca928b3 Merge PR #1631: Memory: floating pictures' textures are bounded, sized to what is drawn, and dropped with their workbook
Conflicts:
- ROADMAP.md: header change line names both memory changes; both progress-log and revision rows kept
2026-10-22 02:36:33 +00:00
aiongg 8e2974cc65 Merge PR #1629: Memory: undo steps share picture and macro bytes instead of copying them
Conflicts:
- ROADMAP.md: both progress-log and revision rows kept
- crates/xlsx/src/sheet_write.rs: keeps #995's image_part call; drops #1629's to_vec line (image_part copies from &[u8])
2026-10-22 02:36:22 +00:00
aiongg 826a22dc2b Integration: #2131 remove a leftover conflict marker line in ROADMAP.md 2026-10-22 02:36:21 +00:00
aiongg cba89cfda8 Merge PR #1066: Engine: formulas.evaluate refuses what cell entry refuses, saying why
ROADMAP.md: both progress-log rows kept.
2026-10-22 02:36:20 +00:00
aiongg 635056bd23 Merge PR #2131: Print: JIS B4/B5 and Japanese paper sizes (はがき・封筒・B6)
ROADMAP.md: one status line naming both changes; both feature-table and progress-log rows, newest first.
2026-10-22 02:36:10 +00:00
aiongg c03d4a881b Merge PR #1570: XLSX: keep dynamic-array cell metadata (cm) on save
ROADMAP.md: kept both progress-log rows
2026-10-22 02:36:04 +00:00
aiongg b17f47b2ca Merge PR #2033: Row auto-fit: count line breaks only in cells that wrap
ROADMAP.md: header line keeps the newer 2026-10-19 date and lists this change; this PR's progress-log row added once below the newer rows.
2026-10-22 02:35:31 +00:00
aiongg 39add6b7c3 Merge PR #2026: Linux: time out the desktop theme's portal read
ROADMAP.md: header line takes the newer date and mentions both changes; both progress-log rows and revision-history rows kept once, newest first.
2026-10-22 02:35:16 +00:00
aiongg 5186b9c964 Merge PR #1523: UI: function help follows the interface language
ROADMAP.md: kept both progress-log rows, newest first
2026-10-22 02:35:16 +00:00
aiongg 00fd1e7a6f Merge PR #1428: Recalc: formulas reading an array that loses a spill conflict see #SPILL!
ROADMAP.md: union of both sides (header change text combined; table and progress-log rows kept once each).
2026-10-22 02:34:45 +00:00
midasdf b092633561 Print: Japanese Envelope #4 is 90×205 mm and add B6 (ISO) to the Size menu
長形4号 is a 90×205 mm envelope (90×225 mm is 長形40号, a different one), so
the paper table gave it a height 20 mm too tall — and XLSX paper id 74, the PDF
MediaBox and the print preview all followed it. Use 205 mm (581.10 pt) and pin
the corrected size with a dedicated assertion; the ROADMAP progress row is
corrected too. 長形40号 is not added: it is a different envelope.

The Page Layout ▸ Size menu stopped at `B5 (ISO)` and never offered
`B6 (ISO)`, which the engine and the command docs support; add it.
2026-10-22 00:24:30 +09:00
midasdf f91f7c05d4 Print: JIS B4/B5/B6 and Japanese paper sizes
Japanese Excel's B4/B5/B6 are the JIS sizes (257×364, 182×257 and 128×182 mm),
but Page Setup's `b4`/`b5` were the ISO ones (250×353, 176×250): a Japanese B5
worksheet printed 8 mm narrow. `known_paper` now reads `B4`/`B5`/`B6` as JIS and
keeps the ISO sizes reachable as `B4 (ISO)`/`B5 (ISO)`/`B6 (ISO)`. This also
fixes the XLSX round-trip, whose `paperSize` ids 12/13 are the JIS sizes.

Adds the Japanese papers Page Setup lacked: Japanese Postcard (はがき,
100×148 mm), Japanese Double Postcard (往復はがき, 148×200 mm), Japanese
Envelope #3/#4 (長形3号/4号, 120×235 and 90×225 mm), Japanese Envelope Kaku
#2/#3 (角形2号/3号, 240×332 and 216×277 mm), A6, and aliases such as
`postcard`, `chou #3`, `kaku #2`; the xlsx paper table gains ids 42 (ISO B4) and
43/69–74/88 so these names survive save and reopen (the ISO B5/B6 names have no
ECMA-376 paper id and stay engine-side).

The pageSetup/pageLayout.size parameter docs list the names, the Page Layout
Size menu lists them, and tests pin the point sizes, the PDF MediaBox for A4
(unchanged), B5, postcard, double postcard and kaku #2, landscape and
fit-to-page, the unknown-name Letter fallback, and the XLSX round-trip.

Docs: docs/target-app-parity.md print row + revision history, and ROADMAP.md
progress log, dated 2026-10-21.
2026-10-21 23:38:26 +09:00
midasdf 97aa04dc80 i18n(ja): add the §11 revision row and align the docs header dates
The Japanese catalog's ribbon labels the review flagged are already in the head
("Save (⌘S)" is 上書き保存 (⌘S), "Insert\nSlicer" is スライサーの\n挿入, and the
catalog test asserts the new value), so only the docs needed work: docs/gaps.md
had no revision row for the §11 Japanese-catalog update. Add one dated
2026-10-20, and set the "Last updated" header of ROADMAP.md, docs/gaps.md and
docs/localization-parity.md to the same date as their new rows. Every existing
revision row keeps its original date.
2026-10-21 22:51:09 +09:00
Stefan FransenandClaude Fable 5.1 60e113bcd7 i18n: Dutch (nl) interface language
Adds a Dutch catalog (`i18n/nl.rs`, 518 labels) covering every key the
other catalogs translate: ribbon, context menus, File view, dialog
titles and the Options page. `nl-NL` and `nl-BE` locale tags resolve
to Dutch. Updates localization parity and the roadmap.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-20 18:10:09 +02:00
RedBearAKandClaude Opus 5.5 4faa3ff098 Row auto-fit: count line breaks only in cells that wrap
auto_row_height grew a row for every line break in a cell's text whether
or not the cell wrapped. Excel counts breaks only when Wrap Text is on:
with it off a multi-line value displays on one line and AutoFit gives a
one-line row. A file whose unwrapped cells hold pasted multi-line text
(the shape generating libraries write) opened with tall rows and nothing
visibly tall in them.

The fast path no longer treats a line break as a reason to measure, and
the measuring path lays text out over lines only for a wrapping cell.
Typing a break still turns wrap on (the Alt+Enter rule in cell entry) and
grows the row, as before.

Test: an unwrapped multi-line cell from a file keeps the default height
on open; wrap on grows the row; wrap off returns it; a typed break wraps
and grows. The open-time fit tests from #833 are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 22:45:22 -08:00
bmh129andClaude Opus 5.5 132e887efa Linux: time out the desktop theme's portal read
The theme watcher (DesktopTheme) reads the desktop's light/dark choice
from the XDG Desktop Portal over a blocking D-Bus call with no timeout.
zbus waits forever by default, so a portal that accepts the call and
never answers stalled the watcher's thread on its first read, and "Use
system setting" stopped following the desktop for the rest of the
session, even after the portal recovered.

The session connection is now built with a 2 s method timeout (REPLY,
shorter than the 4 s POLL). A timed-out call returns InputOutput, which
read() already handles by dropping the connection, so the next poll
asks again on a fresh one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0115HyvML9WnuFRdmtMcLP5t
2026-10-19 23:45:59 -05:00
midasdf ad32e6a847 i18n(ja): translate every dialog, message and menu string the pt-BR catalog covers
The Japanese catalog still lived inline in i18n.rs with its ribbon and widget
labels, so with the interface set to 日本語 the dialog titles and labels, message
boxes, Backstage/File-view items, template names and native menus showed in
English. This moves it to i18n/ja.rs and adds the 545 keys the Brazilian
Portuguese catalog translates beyond it: 943 keys, the coverage pt-BR has
(~43% of ~2,200 strings), in Excel for Mac 日本語版 wording.

CORE keeps the shared reference set every catalog covers, verbatim and in the
same order (the cross-catalog coverage test still points at it); DIALOGS holds
the new strings, and the lookup checks it first. One test parses pt.rs's source
so the two catalogs cannot drift apart again, one checks that every key is
unique across the two lists and every value is translated, and one spot-checks
the high-value strings.

Docs: the Japanese row and the "Where we are" bullet in
docs/localization-parity.md (943, ~43%), a revision row, the ROADMAP Languages
paragraph and progress log, and gaps.md §11.
2026-10-20 13:45:17 +09:00
Harrison BoothandClaude Sonnet 5.5 199e5f8e05 Formulas: test the order walk and map visit nodes; date ROADMAP like the parity doc
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 20:56:26 -05:00
Harrison BoothandClaude Opus 5.5 2aeb21d4d3 Formulas: flat operator chains as long as Excel allows (#916)
along: =1+1+... with 4,096 operands (8,192 characters, exactly Excel's
limit, which Excel accepts and calculates) overflowed the stack when
entered, because the derived Clone of Expr recursed once per operand
down the chain's left spine. Saving hit the same in the XLSX writer.

- Expr: Clone, PartialEq, walk and map follow the left spine in a loop
  and recurse only into right operands and real nesting.
- XLSX: _xlpm. prefixing and the implicit-intersection scan follow the
  spine too. The scan's depth limit of 64 wrote any chain of more than
  about 64 operands as a dynamic-array formula; such sums are plain
  formulas again (ranges in the chain still get array evaluation).
- Evaluate Formula borrows sub-expressions instead of cloning each
  operator's subtree (quadratic memory on a long chain).
- Spanish formula entry and display no longer refuse chains of more
  than 256 operands; the left spine does not count as nesting.

Tests run on a 1 MiB stack (the Windows main thread) with Excel's
observed results: formula (clone/eq/walk/map/adjust at 4,096), calc
(401 and 4,096 operands, -, *, /, ^, &, %, comparisons, 1,500 refs),
xlsx (long chains written as scalar formulas), engine (cell.set, fill,
copy/paste, insert rows/columns, undo/redo, Evaluate Formula, XLSX save
and reopen), Spanish entry. Each fails without the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:54:30 -05:00
Bryan MarkandClaude Opus 5.5 3684349d9c Memory: floating pictures' textures are bounded, sized to what is drawn, and dropped with their workbook
Floating pictures were decoded at full size, with no limits, into one
process-wide map of textures that never let go, not even when their
workbook closed. Its key was the picture's id and byte length, and ids
are per workbook, so a second open workbook could show the first one's
picture.

The new floating_pictures module, built like cell_pictures, keeps a
cache per egui context keyed by workbook, picture id and size:
- bounded at 128 MB, least recently drawn first, never evicting a
  picture drawn in the last frame, so none turns into a placeholder;
- a workbook's textures go when it closes (checked every frame);
- a picture's header is read first (16,384 px a side, 64 MP at most),
  it is decoded with limits, and to the next size step of what is
  drawn (a power of two or three quarters of one, up to 4,096 px or the
  GPU's limit); it is decoded again only when drawn larger;
- a picture that can't be decoded is remembered, not retried each frame.

Measured on macOS 27 (Apple M3 Max): 12 pictures of 2600 x 2600 opened
from an .xlsx and scrolled through, textures held by egui 258 -> 40 MB,
settled footprint 738 -> 509 MB; after closing the workbook, textures
258 -> 0 MB, footprint 504 -> 236 MB. 24 pictures: textures 490 -> 76 MB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:26:53 +09:00
Bryan MarkandClaude Opus 5.5 a09d3f6934 Memory: undo steps share picture and macro bytes instead of copying them
Every edit copies the workbook for its undo step (copy-on-write: sheets
and 64-row bands of cells are shared). A floating picture's bytes
(Image.data) and the VBA project (Workbook.vba_project) were plain
Vec<u8>, so each edit on a sheet with a picture, and every edit in a
workbook with macros, kept another full copy of them, up to the 100
steps of the history. They are Arc<Vec<u8>> now, as cell pictures
already are, with base64 helpers for serde (b64::shared, b64::opt). JSON
and XLSX are unchanged.

Measured on macOS 27 (Apple M3 Max), gridcraft-cli, kernel peak
footprint: a 19 MB picture and 50 cell edits on its sheet, 992 -> 22 MB;
10 edits, 215 -> 21 MB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:26:53 +09:00
Bryan MarkandClaude Opus 5.5 c5baa829e3 Memory: interface fonts are read once and shared with egui, not copied into it
egui copies an owned font's bytes into its text engine (epaint's
blob_from_font_data clones the Cow) and keeps the original FontData too,
so every interface and script fallback font was in memory twice: about
100 MB on a Mac, where the fallbacks alone (Hiragino Sans GB, Hiragino
Sans, Apple SD Gothic Neo, Thonburi...) are 89 MB of files. try_load now
keeps each file it reads for the rest of the run and hands egui borrowed
'static bytes, which it shares. These faces are loaded by every font
rebuild anyway, so keeping them costs nothing, and rebuilds no longer
read them from disk again. A missing or broken file is looked for again
next time. Which faces load, and their order, are unchanged; workbook
fonts (bind_faces) load as before.

Measured on macOS 27 (Apple M3 Max), offscreen snapshot held after its
picture, settled footprint: empty workbook 258 -> 158 MB, the sample
workbook 261 -> 160 MB, a cell in five scripts 258 -> 158 MB; the
rendered pictures are byte-for-byte the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:26:53 +09:00
Marco Arnulfo 79e8973c30 Web: keep preferences such as dark mode between visits (fixes #1562) 2026-10-16 01:35:02 +02:00
NetterSilver 9f6bd5848c Docs: update the progress docs for this change 2026-10-15 20:17:42 +00:00
quantmind-br 47268a42af UI: function help follows the interface language
The argument hint, autocomplete, Insert Function and the Formulas-tab menus
read per-language tables of function descriptions and argument names
(i18n/<lang>_functions.rs), keyed by the catalog's English text and
binary-searched. The hint is assembled from the formula syntax's function
name and separator plus the language's argument names, all of them or none,
so it never mixes two languages. Insert Function searches the translated
descriptions and shows readable category names. SPANISH_HELP moves to
es_functions.rs with its 10 functions.
2026-10-15 10:49:13 -03:00