Commit Graph
238 Commits
Author SHA1 Message Date
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 6dda6be2c6 Integration: track t09
# Conflicts:
#	crates/engine/src/tests.rs
#	crates/ui-egui/src/i18n.rs
#	crates/ui-egui/src/i18n/pt.rs
#	docs/file-format-parity.md
#	docs/target-app-parity.md
#	docs/ui-parity.md
2026-10-22 03:04:21 +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 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 ec61d59b41 Integration: cargo fmt 2026-10-22 02:50:46 +00:00
aiongg 470a2ae2c1 Merge PR #1765: Sheet protection: obey the Sort and Use AutoFilter boxes
Conflicts:
- crates/engine/src/cmd/data.rs: do_sort keeps #1284's sheet parameter and checks Sorting on it; toggle_filter checks Filtering after #1285's data_target
- crates/engine/src/tests.rs: adjacent tests, both kept
2026-10-22 02:37:16 +00:00
aiongg 8ec29a8b3b Merge PR #1652: Fill handle: right-drag opens the fill menu (Copy Cells, Fill Series, Fill Formatting Only, Fill Without Formatting, Series…)
crates/ui-egui/src/grid.rs: kept both GridState fields (context_menu_frame, fill_menu); previous_popups tuple has four elements inside the touch_pan branch; release match has Drag::Rows|Cols, then the two Drag::Fill arms
docs/ui-parity.md: kept HEAD header line, both change rows
2026-10-22 02:36:24 +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 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 8590dca0db Merge PR #2207: clipboard: bound HTML colspan/rowspan expansion (#2171) 2026-10-22 02:36:12 +00:00
aiongg 7e74b35a1b Merge PR #2095: Number Stored as Text: green indicator, warning button and Convert to Number (#1994)
crates/ui-egui/src/grid.rs: kept object_menu (2084) and error_check_tag (2095), both fns and both calls.
crates/ui-egui/src/i18n/de.rs, pt.rs: union of the entries.
docs/ui-parity.md: one status line naming both changes, both history rows.
2026-10-22 02:36:03 +00:00
aiongg 7768f56603 Merge PR #1580: Calc: CELL("filename") names the workbook's file 2026-10-22 02:35:56 +00:00
aiongg 013ead7389 Integration: #2033 drop the dated history from the auto-fit comments 2026-10-22 02:35:41 +00:00
aiongg aab44d2c23 Merge PR #1535: engine: sort and remove duplicates move the rows' notes and hyperlinks
# Conflicts:
#	crates/engine/src/tests.rs
2026-10-22 02:35:40 +00:00
aiongg 5c1b171892 Merge PR #1738: Keep chart source range in step with inserted and deleted lines 2026-10-22 02:35:39 +00:00
aiongg d83dc11ff2 Merge PR #1695: Charts: box & whisker charts honor their quartile method
crates/engine/src/tests.rs: kept both new tests (csv_as_text_keeps_identifier_columns_as_written and box_whisker_quartile_methods_survive_xlsx).
2026-10-22 02:35:39 +00:00
aiongg 26c6e4ca14 Merge PR #1621: Reject unsupported flip param in arrange.rotate
Conflicts:
- crates/engine/src/tests.rs: kept both appended tests
2026-10-22 02:35:33 +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 cede13d0a7 Merge PR #1527: engine: pageLayout.printTitles only touches the axes it is given 2026-10-22 02:35:30 +00:00
aiongg 5f4309e4ba Merge PR #1653: Charts: insert.chart builds a series from every area of a multi-area range 2026-10-22 02:35:30 +00:00
aiongg d691e95f6d Merge PR #1285: Remove Duplicates, Filter and Subtotal: a Sheet! prefix on the range works on that sheet 2026-10-22 02:35:24 +00:00
aiongg 87df1947f9 Merge PR #1284: Sort: a Sheet! prefix on the range sorts that sheet, not the active one 2026-10-22 02:35:21 +00:00
aiongg d26bbe3432 Merge PR #1085: Format: Row Height and Column Width say pixels, and take points like the reference app
Conflicts:
- crates/engine/src/cmd/format.rs: spec strings keep #885's sheet?/Sheet! forms with #1085's pixels/points wording; row_height and col_width keep #1085's unit logic with #885's (si, lines) = line_targets
2026-10-22 02:35:21 +00:00
aiongg 8709b41666 Merge PR #1525: Keep leading empty columns and rows when saving CSV/text
Conflicts:
- crates/xlsx/src/csv.rs: write_csv doc comment merged (this PR's A1 rectangle sentence, main's per-field cap wording)
- crates/engine/src/tests.rs: kept both appended tests
2026-10-22 02:35:17 +00:00
aiongg f8b7547344 Merge PR #1709: Rows: a big font isn't counted twice when the sheet's default height already fits it 2026-10-22 02:35:02 +00:00
aiongg 51401a382c Merge PR #1534: engine: a cut takes the source's notes, hyperlinks and merged areas with it 2026-10-22 02:35:01 +00:00
aiongg 32faa4f1c6 Merge PR #1661: Merged cell with Wrap Text: auto-fit skips it, so the text draws and the row keeps its default height 2026-10-22 02:34:59 +00:00
aiongg ee54646258 Merge PR #1372: Edit: text that would parse as a number or formula keeps its quote prefix in the editor (#1362) 2026-10-22 02:34:59 +00:00
aiongg 38fb979498 Merge PR #1329: Slicer: find a named table on any sheet
Conflicts: crates/engine/src/tests.rs (both appended a test at the same spot; kept both)
2026-10-22 02:34:53 +00:00
aiongg 49328f80c0 Merge PR #1381: engine: rebuild cell-store bands and counts when importing a JSON workbook 2026-10-22 02:34:49 +00:00
aiongg 4f7111941e Merge PR #951: fix(fill): respect the workbook date system in monthly AutoFill
docs/ui-parity.md: kept the newer header line, kept both history rows.
2026-10-22 02:34:45 +00:00
aiongg ccc0e8cfe4 Merge PR #885: Row, column and freeze commands act on the sheet they are given 2026-10-22 02:34:36 +00:00
aiongg 947930e889 Merge PR #584: Refuse inserting cells that would push values off the worksheet (#580) 2026-10-22 02:34:36 +00:00
aiongg 136a8fa07e Merge PR #1337: Selection: whole columns and rows don't widen to merged cells 2026-10-22 02:34:33 +00:00
Higgs32584andClaude Opus 5.5 b817c04a9b clipboard: bound HTML colspan/rowspan expansion (#2171)
Clipboard HTML is read only as far as the pasted text's shape (clamped
to the sheet) and at most 1,000,000 cells; colspan/rowspan are clamped
to the sheet extent before expanding, and rowspan now keeps later rows
in their columns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 21:06:51 -04:00
dantebertuzziandClaude Opus 5.5 68f956a410 Number Stored as Text: green indicator, warning button and Convert to Number (#1994)
Numbers stored as text are skipped by SUM and friends, and GridCraft gave
no hint. Like Excel's background error checking, a constant whose text
would be a number if typed now gets a green triangle in its top-left
corner; with such a cell active, a warning button beside it opens a menu
naming the problem with Convert to Number, which converts every flagged
cell in the selection as one undo step.

- core: `parse::number_stored_as_text` (signs, thousands separators,
  currency, percent, exponent, one parenthesised negative). Dates, times
  and fractions kept as text are not flagged, as in Excel.
- engine: `cmd::formulas::number_stored_as_text(cell)` (constants only,
  not formula results) and `formulas.convertToNumber {range?}`, which
  keeps each cell's format.
- ui: the triangle in the grid and the warning button with its menu;
  pt-BR and German strings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 21:39:30 -03: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
kezmdorandClaude Opus 5.5 cfb0e186ed Formula entry: an incomplete formula's error describes what was typed (fixes #2030)
`=1+` reported "unexpected `)`", although no `)` was typed: entry closes
missing parentheses by appending up to eight `)`, and when every retry
failed it reported the last retry's error. It now reports the error of
the formula as typed ("unexpected end of formula").

`gridcraft_formula::parse_closing_parens` holds the convenience and takes
the parse function, so cell entry and the UI's Spanish formula path share
it instead of each having its own loop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 07:44:09 +02:00
vangel76 d9d4d64645 PR1372: merge main and preserve quote-prefix and CSV regression tests 2026-10-20 00:56:41 +02:00
Hamza e5aeea7a94 Sheet protection: obey the Sort and Use AutoFilter boxes
`SheetProtection` carries eleven permissions. `format_cells` is checked in
`apply_style`, and an edit to a locked cell is caught after the fact by
`check_protection`, but `sort` and `autofilter` had no reader anywhere outside
`sheet_read.rs`, `sheet_write.rs` and a round-trip test: they only ever
travelled through the file. So a protected sheet could still be sorted, and
Ctrl+Shift+L still put an AutoFilter on it.

`refuse_unless_allowed` sits beside `locked_cell_error`, with three call sites:
`do_sort` (which both Sort… and the A-to-Z buttons come through), `toggle_filter`
and `filter_by`.

Where the box decides is worth knowing. Sorting a range of locked cells was
already refused, by the locked-cell guard rather than the permission, because a
sort moves values between locked cells — which is Excel's rule too ("users
cannot sort ranges that contain locked cells on a protected worksheet,
regardless of this setting"). So the Sort box decides for a range that has been
unlocked, while an AutoFilter changes no cell's contents and the box is the only
thing that ever decided it. The test asserts both, and that an unprotected sheet
still sorts and filters.

Not fixed here: Delete Rows and Delete Columns are refused even when their boxes
are ticked, because deleting removes locked cells and trips the same post-hoc
guard, while Insert Rows and Insert Columns work. Letting the guard know which
operation ran is a change to code every command passes through and wants its own
PR.
2026-10-19 22:30:36 +05:00
Hamza aff9153dac Calc: CELL("filename") names the workbook's file (#1489)
It returned an empty string for every workbook, saved or not, so the classic
sheet-name formula `MID(CELL("filename",A1),FIND("]",…)+1,31)` gave #VALUE!:
with no `]` in the string there is nothing for FIND to find. Excel returns
`<folder>\[<file>]<sheet>`, and empty only before the first save.

The model had no file to report. `source_dir` could not serve: it names the
folder relative links to other workbooks are relative to, and must keep naming
it after a Save As into another folder, because the links held in memory are
still written for the old one — only the saved copy is rebased. `source_path`
is therefore its own field, with that distinction written down.

It is set when a workbook is opened, from the path made absolute so the folder
is the one the user sees, and when a full-fidelity save makes a file the
document's own — before the `saved` snapshot, or the workbook would read as
dirty the moment it was saved, and only when it changes, so an ordinary Save
does not clone the workbook for nothing. A workbook that arrived as bytes knows
its name but never a folder and reports `[name]Sheet`, which still splits on the
`]`; an import reports the file it came from, as Excel does. The sheet is the one
the reference is on, not the active one.

CELL is volatile and already in the volatile sets, so a cell holding it answers
from the next recalculation; after a Save As that means F9 rather than the save
itself, which the engine test asserts rather than papers over. Making a save
recalculate is a larger decision than this issue.

`check` still skips CELL("filename") as volatile, as docs/cli.md says: the
cached value in a file is the folder of the machine that saved it.
2026-10-19 22:29:37 +05:00
Brandon Thomas ab6fd48856 Merge pull request #1867 from HyakoV3:fix/1808-csv-as-text
# Conflicts:
#	docs/file-format-parity.md
2026-10-19 12:22:05 -04:00
Brandon Thomas 12ee27a177 Merge pull request #1943 from Mouhand-Kaddo:fix/table-name-length
# Conflicts:
#	docs/localization-parity.md
2026-10-19 12:22:01 -04:00
Mouhand-Kaddo eee872e429 M12.AR16: limit table names to 255 characters 2026-10-19 17:04:06 +04:00
justinjohn0306andClaude Opus 5.5 dcd4d1d13f #1855: redo selects the redone cell
Undo stored the selection at the moment of undoing (wherever the user had
clicked) in the redo entry, so redo jumped back there instead of to the
cells it changed. The redo entry now keeps the undone step's selection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 10:16:13 +05:30